11#[ cfg( all( test, not( target_os = "emscripten" ) ) ) ]
22mod tests;
33
4- use libc:: { EXIT_FAILURE , EXIT_SUCCESS , c_char , c_int, gid_t, pid_t, uid_t} ;
4+ use libc:: { EXIT_FAILURE , EXIT_SUCCESS , c_int, gid_t, pid_t, uid_t} ;
55
6+ pub use self :: cstring_array:: CStringArray ;
7+ use self :: cstring_array:: CStringIter ;
68use crate :: collections:: BTreeMap ;
79use crate :: ffi:: { CStr , CString , OsStr , OsString } ;
810use crate :: os:: unix:: prelude:: * ;
@@ -14,7 +16,9 @@ use crate::sys::fs::OpenOptions;
1416use crate :: sys:: pipe:: { self , AnonPipe } ;
1517use crate :: sys_common:: process:: { CommandEnv , CommandEnvs } ;
1618use crate :: sys_common:: { FromInner , IntoInner } ;
17- use crate :: { fmt, io, ptr} ;
19+ use crate :: { fmt, io} ;
20+
21+ mod cstring_array;
1822
1923cfg_if:: cfg_if! {
2024 if #[ cfg( target_os = "fuchsia" ) ] {
@@ -77,13 +81,7 @@ cfg_if::cfg_if! {
7781
7882pub struct Command {
7983 program : CString ,
80- args : Vec < CString > ,
81- /// Exactly what will be passed to `execvp`.
82- ///
83- /// First element is a pointer to `program`, followed by pointers to
84- /// `args`, followed by a `null`. Be careful when modifying `program` or
85- /// `args` to properly update this as well.
86- argv : Argv ,
84+ args : CStringArray ,
8785 env : CommandEnv ,
8886
8987 program_kind : ProgramKind ,
@@ -101,14 +99,6 @@ pub struct Command {
10199 pgroup : Option < pid_t > ,
102100}
103101
104- // Create a new type for argv, so that we can make it `Send` and `Sync`
105- struct Argv ( Vec < * const c_char > ) ;
106-
107- // It is safe to make `Argv` `Send` and `Sync`, because it contains
108- // pointers to memory owned by `Command.args`
109- unsafe impl Send for Argv { }
110- unsafe impl Sync for Argv { }
111-
112102// passed back to std::process with the pipes connected to the child, if any
113103// were requested
114104pub struct StdioPipes {
@@ -170,41 +160,17 @@ impl ProgramKind {
170160}
171161
172162impl Command {
173- #[ cfg( not( target_os = "linux" ) ) ]
174163 pub fn new ( program : & OsStr ) -> Command {
175164 let mut saw_nul = false ;
176165 let program_kind = ProgramKind :: new ( program. as_ref ( ) ) ;
177166 let program = os2c ( program, & mut saw_nul) ;
167+ let mut args = CStringArray :: with_capacity ( 1 ) ;
168+ args. push ( program. clone ( ) ) ;
178169 Command {
179- argv : Argv ( vec ! [ program. as_ptr( ) , ptr:: null( ) ] ) ,
180- args : vec ! [ program. clone( ) ] ,
181170 program,
182- program_kind ,
171+ args ,
183172 env : Default :: default ( ) ,
184- cwd : None ,
185- uid : None ,
186- gid : None ,
187- saw_nul,
188- closures : Vec :: new ( ) ,
189- groups : None ,
190- stdin : None ,
191- stdout : None ,
192- stderr : None ,
193- pgroup : None ,
194- }
195- }
196-
197- #[ cfg( target_os = "linux" ) ]
198- pub fn new ( program : & OsStr ) -> Command {
199- let mut saw_nul = false ;
200- let program_kind = ProgramKind :: new ( program. as_ref ( ) ) ;
201- let program = os2c ( program, & mut saw_nul) ;
202- Command {
203- argv : Argv ( vec ! [ program. as_ptr( ) , ptr:: null( ) ] ) ,
204- args : vec ! [ program. clone( ) ] ,
205- program,
206173 program_kind,
207- env : Default :: default ( ) ,
208174 cwd : None ,
209175 uid : None ,
210176 gid : None ,
@@ -214,6 +180,7 @@ impl Command {
214180 stdin : None ,
215181 stdout : None ,
216182 stderr : None ,
183+ #[ cfg( target_os = "linux" ) ]
217184 create_pidfd : false ,
218185 pgroup : None ,
219186 }
@@ -222,20 +189,11 @@ impl Command {
222189 pub fn set_arg_0 ( & mut self , arg : & OsStr ) {
223190 // Set a new arg0
224191 let arg = os2c ( arg, & mut self . saw_nul ) ;
225- debug_assert ! ( self . argv. 0 . len( ) > 1 ) ;
226- self . argv . 0 [ 0 ] = arg. as_ptr ( ) ;
227- self . args [ 0 ] = arg;
192+ self . args . write ( 0 , arg) ;
228193 }
229194
230195 pub fn arg ( & mut self , arg : & OsStr ) {
231- // Overwrite the trailing null pointer in `argv` and then add a new null
232- // pointer.
233196 let arg = os2c ( arg, & mut self . saw_nul ) ;
234- self . argv . 0 [ self . args . len ( ) ] = arg. as_ptr ( ) ;
235- self . argv . 0 . push ( ptr:: null ( ) ) ;
236-
237- // Also make sure we keep track of the owned value to schedule a
238- // destructor for this memory.
239197 self . args . push ( arg) ;
240198 }
241199
@@ -286,6 +244,8 @@ impl Command {
286244
287245 pub fn get_args ( & self ) -> CommandArgs < ' _ > {
288246 let mut iter = self . args . iter ( ) ;
247+ // argv[0] contains the program name, but we are only interested in the
248+ // arguments so skip it.
289249 iter. next ( ) ;
290250 CommandArgs { iter }
291251 }
@@ -298,12 +258,12 @@ impl Command {
298258 self . cwd . as_ref ( ) . map ( |cs| Path :: new ( OsStr :: from_bytes ( cs. as_bytes ( ) ) ) )
299259 }
300260
301- pub fn get_argv ( & self ) -> & Vec < * const c_char > {
302- & self . argv . 0
261+ pub fn get_argv ( & self ) -> & CStringArray {
262+ & self . args
303263 }
304264
305265 pub fn get_program_cstr ( & self ) -> & CStr {
306- & * self . program
266+ & self . program
307267 }
308268
309269 #[ allow( dead_code) ]
@@ -392,32 +352,6 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
392352 } )
393353}
394354
395- // Helper type to manage ownership of the strings within a C-style array.
396- pub struct CStringArray {
397- items : Vec < CString > ,
398- ptrs : Vec < * const c_char > ,
399- }
400-
401- impl CStringArray {
402- pub fn with_capacity ( capacity : usize ) -> Self {
403- let mut result = CStringArray {
404- items : Vec :: with_capacity ( capacity) ,
405- ptrs : Vec :: with_capacity ( capacity + 1 ) ,
406- } ;
407- result. ptrs . push ( ptr:: null ( ) ) ;
408- result
409- }
410- pub fn push ( & mut self , item : CString ) {
411- let l = self . ptrs . len ( ) ;
412- self . ptrs [ l - 1 ] = item. as_ptr ( ) ;
413- self . ptrs . push ( ptr:: null ( ) ) ;
414- self . items . push ( item) ;
415- }
416- pub fn as_ptr ( & self ) -> * const * const c_char {
417- self . ptrs . as_ptr ( )
418- }
419- }
420-
421355fn construct_envp ( env : BTreeMap < OsString , OsString > , saw_nul : & mut bool ) -> CStringArray {
422356 let mut result = CStringArray :: with_capacity ( env. len ( ) ) ;
423357 for ( mut k, v) in env {
@@ -606,14 +540,16 @@ impl fmt::Debug for Command {
606540 write ! ( f, "{}={value:?} " , key. to_string_lossy( ) ) ?;
607541 }
608542 }
609- if self . program != self . args [ 0 ] {
543+
544+ if * self . program != self . args [ 0 ] {
610545 write ! ( f, "[{:?}] " , self . program) ?;
611546 }
612- write ! ( f, "{:?}" , self . args[ 0 ] ) ?;
547+ write ! ( f, "{:?}" , & self . args[ 0 ] ) ?;
613548
614- for arg in & self . args [ 1 .. ] {
549+ for arg in self . get_args ( ) {
615550 write ! ( f, " {:?}" , arg) ?;
616551 }
552+
617553 Ok ( ( ) )
618554 }
619555 }
@@ -645,14 +581,16 @@ impl From<u8> for ExitCode {
645581}
646582
647583pub struct CommandArgs < ' a > {
648- iter : crate :: slice :: Iter < ' a , CString > ,
584+ iter : CStringIter < ' a > ,
649585}
650586
651587impl < ' a > Iterator for CommandArgs < ' a > {
652588 type Item = & ' a OsStr ;
589+
653590 fn next ( & mut self ) -> Option < & ' a OsStr > {
654- self . iter . next ( ) . map ( |cs| OsStr :: from_bytes ( cs. as_bytes ( ) ) )
591+ self . iter . next ( ) . map ( |cs| OsStr :: from_bytes ( cs. to_bytes ( ) ) )
655592 }
593+
656594 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
657595 self . iter . size_hint ( )
658596 }
@@ -662,6 +600,7 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> {
662600 fn len ( & self ) -> usize {
663601 self . iter . len ( )
664602 }
603+
665604 fn is_empty ( & self ) -> bool {
666605 self . iter . is_empty ( )
667606 }
0 commit comments