11use super :: FORK_MTX ;
2+ use nix:: errno:: Errno ;
23use nix:: spawn:: { self , PosixSpawnAttr , PosixSpawnFileActions } ;
34use nix:: sys:: signal;
45use nix:: sys:: wait:: { waitpid, WaitPidFlag , WaitStatus } ;
5- use std:: ffi:: CString ;
6+ use std:: ffi:: { CStr , CString } ;
7+
8+ /// Helper function to find a binary in the $PATH
9+ fn which ( exe_name : & str ) -> Option < std:: path:: PathBuf > {
10+ std:: env:: var_os ( "PATH" ) . and_then ( |paths| {
11+ std:: env:: split_paths ( & paths)
12+ . filter_map ( |dir| {
13+ let full_path = dir. join ( exe_name) ;
14+ if full_path. is_file ( ) {
15+ Some ( full_path)
16+ } else {
17+ None
18+ }
19+ } )
20+ . next ( )
21+ } )
22+ }
623
724#[ test]
825fn spawn_true ( ) {
926 let _guard = FORK_MTX . lock ( ) ;
1027
28+ let bin = which ( "true" ) . unwrap ( ) ;
29+ let args = & [
30+ CString :: new ( "true" ) . unwrap ( ) ,
31+ CString :: new ( "story" ) . unwrap ( ) ,
32+ ] ;
33+ let vars: & [ CString ] = & [ ] ;
34+ let actions = PosixSpawnFileActions :: init ( ) . unwrap ( ) ;
35+ let attr = PosixSpawnAttr :: init ( ) . unwrap ( ) ;
36+
37+ let pid =
38+ spawn:: posix_spawn ( bin. as_path ( ) , & actions, & attr, args, vars) . unwrap ( ) ;
39+
40+ let status = waitpid ( pid, Some ( WaitPidFlag :: empty ( ) ) ) . unwrap ( ) ;
41+
42+ match status {
43+ WaitStatus :: Exited ( wpid, ret) => {
44+ assert_eq ! ( pid, wpid) ;
45+ assert_eq ! ( ret, 0 ) ;
46+ }
47+ _ => {
48+ panic ! ( "Invalid WaitStatus" ) ;
49+ }
50+ } ;
51+ }
52+
53+ #[ test]
54+ fn spawn_sleep ( ) {
55+ let _guard = FORK_MTX . lock ( ) ;
56+
57+ let bin = which ( "sleep" ) . unwrap ( ) ;
58+ let args = & [ CString :: new ( "sleep" ) . unwrap ( ) , CString :: new ( "30" ) . unwrap ( ) ] ;
59+ let vars: & [ CString ] = & [ ] ;
60+ let actions = PosixSpawnFileActions :: init ( ) . unwrap ( ) ;
61+ let attr = PosixSpawnAttr :: init ( ) . unwrap ( ) ;
62+
63+ let pid =
64+ spawn:: posix_spawn ( bin. as_path ( ) , & actions, & attr, args, vars) . unwrap ( ) ;
65+
66+ let status =
67+ waitpid ( pid, WaitPidFlag :: from_bits ( WaitPidFlag :: WNOHANG . bits ( ) ) )
68+ . unwrap ( ) ;
69+ match status {
70+ WaitStatus :: StillAlive => { }
71+ _ => {
72+ panic ! ( "Invalid WaitStatus" ) ;
73+ }
74+ } ;
75+
76+ signal:: kill ( pid, signal:: SIGTERM ) . unwrap ( ) ;
77+
78+ let status = waitpid ( pid, Some ( WaitPidFlag :: empty ( ) ) ) . unwrap ( ) ;
79+ match status {
80+ WaitStatus :: Signaled ( wpid, wsignal, _) => {
81+ assert_eq ! ( pid, wpid) ;
82+ assert_eq ! ( wsignal, signal:: SIGTERM ) ;
83+ }
84+ _ => {
85+ panic ! ( "Invalid WaitStatus" ) ;
86+ }
87+ } ;
88+ }
89+
90+ #[ test]
91+ // `posix_spawn(path_not_exist)` succeeds under QEMU, so ignore the test. No need
92+ // to investigate the root cause, this test still works in native environments, which
93+ // is sufficient to test the binding.
94+ #[ cfg_attr( qemu, ignore) ]
95+ fn spawn_cmd_does_not_exist ( ) {
96+ let _guard = FORK_MTX . lock ( ) ;
97+
98+ let args = & [ CString :: new ( "buzz" ) . unwrap ( ) ] ;
99+ let envs: & [ CString ] = & [ ] ;
100+ let actions = PosixSpawnFileActions :: init ( ) . unwrap ( ) ;
101+ let attr = PosixSpawnAttr :: init ( ) . unwrap ( ) ;
102+
103+ let bin = "2b7433c4-523b-470c-abb5-d7ee9fd295d5-fdasf" ;
104+ let errno =
105+ spawn:: posix_spawn ( bin, & actions, & attr, args, envs) . unwrap_err ( ) ;
106+ assert_eq ! ( errno, Errno :: ENOENT ) ;
107+ }
108+
109+ #[ test]
110+ fn spawnp_true ( ) {
111+ let _guard = FORK_MTX . lock ( ) ;
112+
11113 let bin = & CString :: new ( "true" ) . unwrap ( ) ;
12114 let args = & [
13115 CString :: new ( "true" ) . unwrap ( ) ,
@@ -33,7 +135,7 @@ fn spawn_true() {
33135}
34136
35137#[ test]
36- fn spawn_sleep ( ) {
138+ fn spawnp_sleep ( ) {
37139 let _guard = FORK_MTX . lock ( ) ;
38140
39141 let bin = & CString :: new ( "sleep" ) . unwrap ( ) ;
@@ -67,3 +169,25 @@ fn spawn_sleep() {
67169 }
68170 } ;
69171}
172+
173+ #[ test]
174+ // `posix_spawnp(bin_not_exist)` succeeds under QEMU, so ignore the test. No need
175+ // to investigate the root cause, this test still works in native environments, which
176+ // is sufficient to test the binding.
177+ #[ cfg_attr( qemu, ignore) ]
178+ fn spawnp_cmd_does_not_exist ( ) {
179+ let _guard = FORK_MTX . lock ( ) ;
180+
181+ let args = & [ CString :: new ( "buzz" ) . unwrap ( ) ] ;
182+ let envs: & [ CString ] = & [ ] ;
183+ let actions = PosixSpawnFileActions :: init ( ) . unwrap ( ) ;
184+ let attr = PosixSpawnAttr :: init ( ) . unwrap ( ) ;
185+
186+ let bin = CStr :: from_bytes_with_nul (
187+ "2b7433c4-523b-470c-abb5-d7ee9fd295d5-fdasf\0 " . as_bytes ( ) ,
188+ )
189+ . unwrap ( ) ;
190+ let errno =
191+ spawn:: posix_spawnp ( bin, & actions, & attr, args, envs) . unwrap_err ( ) ;
192+ assert_eq ! ( errno, Errno :: ENOENT ) ;
193+ }
0 commit comments