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:: process:: env:: { 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 ,
@@ -102,14 +100,6 @@ pub struct Command {
102100 pgroup : Option < pid_t > ,
103101}
104102
105- // Create a new type for argv, so that we can make it `Send` and `Sync`
106- struct Argv ( Vec < * const c_char > ) ;
107-
108- // It is safe to make `Argv` `Send` and `Sync`, because it contains
109- // pointers to memory owned by `Command.args`
110- unsafe impl Send for Argv { }
111- unsafe impl Sync for Argv { }
112-
113103// passed back to std::process with the pipes connected to the child, if any
114104// were requested
115105pub struct StdioPipes {
@@ -171,42 +161,17 @@ impl ProgramKind {
171161}
172162
173163impl Command {
174- #[ cfg( not( target_os = "linux" ) ) ]
175164 pub fn new ( program : & OsStr ) -> Command {
176165 let mut saw_nul = false ;
177166 let program_kind = ProgramKind :: new ( program. as_ref ( ) ) ;
178167 let program = os2c ( program, & mut saw_nul) ;
168+ let mut args = CStringArray :: with_capacity ( 1 ) ;
169+ args. push ( program. clone ( ) ) ;
179170 Command {
180- argv : Argv ( vec ! [ program. as_ptr( ) , ptr:: null( ) ] ) ,
181- args : vec ! [ program. clone( ) ] ,
182171 program,
183- program_kind ,
172+ args ,
184173 env : Default :: default ( ) ,
185- cwd : None ,
186- chroot : None ,
187- uid : None ,
188- gid : None ,
189- saw_nul,
190- closures : Vec :: new ( ) ,
191- groups : None ,
192- stdin : None ,
193- stdout : None ,
194- stderr : None ,
195- pgroup : None ,
196- }
197- }
198-
199- #[ cfg( target_os = "linux" ) ]
200- pub fn new ( program : & OsStr ) -> Command {
201- let mut saw_nul = false ;
202- let program_kind = ProgramKind :: new ( program. as_ref ( ) ) ;
203- let program = os2c ( program, & mut saw_nul) ;
204- Command {
205- argv : Argv ( vec ! [ program. as_ptr( ) , ptr:: null( ) ] ) ,
206- args : vec ! [ program. clone( ) ] ,
207- program,
208174 program_kind,
209- env : Default :: default ( ) ,
210175 cwd : None ,
211176 chroot : None ,
212177 uid : None ,
@@ -217,6 +182,7 @@ impl Command {
217182 stdin : None ,
218183 stdout : None ,
219184 stderr : None ,
185+ #[ cfg( target_os = "linux" ) ]
220186 create_pidfd : false ,
221187 pgroup : None ,
222188 }
@@ -225,20 +191,11 @@ impl Command {
225191 pub fn set_arg_0 ( & mut self , arg : & OsStr ) {
226192 // Set a new arg0
227193 let arg = os2c ( arg, & mut self . saw_nul ) ;
228- debug_assert ! ( self . argv. 0 . len( ) > 1 ) ;
229- self . argv . 0 [ 0 ] = arg. as_ptr ( ) ;
230- self . args [ 0 ] = arg;
194+ self . args . write ( 0 , arg) ;
231195 }
232196
233197 pub fn arg ( & mut self , arg : & OsStr ) {
234- // Overwrite the trailing null pointer in `argv` and then add a new null
235- // pointer.
236198 let arg = os2c ( arg, & mut self . saw_nul ) ;
237- self . argv . 0 [ self . args . len ( ) ] = arg. as_ptr ( ) ;
238- self . argv . 0 . push ( ptr:: null ( ) ) ;
239-
240- // Also make sure we keep track of the owned value to schedule a
241- // destructor for this memory.
242199 self . args . push ( arg) ;
243200 }
244201
@@ -295,6 +252,8 @@ impl Command {
295252
296253 pub fn get_args ( & self ) -> CommandArgs < ' _ > {
297254 let mut iter = self . args . iter ( ) ;
255+ // argv[0] contains the program name, but we are only interested in the
256+ // arguments so skip it.
298257 iter. next ( ) ;
299258 CommandArgs { iter }
300259 }
@@ -307,12 +266,12 @@ impl Command {
307266 self . cwd . as_ref ( ) . map ( |cs| Path :: new ( OsStr :: from_bytes ( cs. as_bytes ( ) ) ) )
308267 }
309268
310- pub fn get_argv ( & self ) -> & Vec < * const c_char > {
311- & self . argv . 0
269+ pub fn get_argv ( & self ) -> & CStringArray {
270+ & self . args
312271 }
313272
314273 pub fn get_program_cstr ( & self ) -> & CStr {
315- & * self . program
274+ & self . program
316275 }
317276
318277 #[ allow( dead_code) ]
@@ -405,32 +364,6 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
405364 } )
406365}
407366
408- // Helper type to manage ownership of the strings within a C-style array.
409- pub struct CStringArray {
410- items : Vec < CString > ,
411- ptrs : Vec < * const c_char > ,
412- }
413-
414- impl CStringArray {
415- pub fn with_capacity ( capacity : usize ) -> Self {
416- let mut result = CStringArray {
417- items : Vec :: with_capacity ( capacity) ,
418- ptrs : Vec :: with_capacity ( capacity + 1 ) ,
419- } ;
420- result. ptrs . push ( ptr:: null ( ) ) ;
421- result
422- }
423- pub fn push ( & mut self , item : CString ) {
424- let l = self . ptrs . len ( ) ;
425- self . ptrs [ l - 1 ] = item. as_ptr ( ) ;
426- self . ptrs . push ( ptr:: null ( ) ) ;
427- self . items . push ( item) ;
428- }
429- pub fn as_ptr ( & self ) -> * const * const c_char {
430- self . ptrs . as_ptr ( )
431- }
432- }
433-
434367fn construct_envp ( env : BTreeMap < OsString , OsString > , saw_nul : & mut bool ) -> CStringArray {
435368 let mut result = CStringArray :: with_capacity ( env. len ( ) ) ;
436369 for ( mut k, v) in env {
@@ -619,14 +552,16 @@ impl fmt::Debug for Command {
619552 write ! ( f, "{}={value:?} " , key. to_string_lossy( ) ) ?;
620553 }
621554 }
622- if self . program != self . args [ 0 ] {
555+
556+ if * self . program != self . args [ 0 ] {
623557 write ! ( f, "[{:?}] " , self . program) ?;
624558 }
625- write ! ( f, "{:?}" , self . args[ 0 ] ) ?;
559+ write ! ( f, "{:?}" , & self . args[ 0 ] ) ?;
626560
627- for arg in & self . args [ 1 .. ] {
561+ for arg in self . get_args ( ) {
628562 write ! ( f, " {:?}" , arg) ?;
629563 }
564+
630565 Ok ( ( ) )
631566 }
632567 }
@@ -658,14 +593,16 @@ impl From<u8> for ExitCode {
658593}
659594
660595pub struct CommandArgs < ' a > {
661- iter : crate :: slice :: Iter < ' a , CString > ,
596+ iter : CStringIter < ' a > ,
662597}
663598
664599impl < ' a > Iterator for CommandArgs < ' a > {
665600 type Item = & ' a OsStr ;
601+
666602 fn next ( & mut self ) -> Option < & ' a OsStr > {
667- self . iter . next ( ) . map ( |cs| OsStr :: from_bytes ( cs. as_bytes ( ) ) )
603+ self . iter . next ( ) . map ( |cs| OsStr :: from_bytes ( cs. to_bytes ( ) ) )
668604 }
605+
669606 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
670607 self . iter . size_hint ( )
671608 }
@@ -675,6 +612,7 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> {
675612 fn len ( & self ) -> usize {
676613 self . iter . len ( )
677614 }
615+
678616 fn is_empty ( & self ) -> bool {
679617 self . iter . is_empty ( )
680618 }
0 commit comments