1
1
#[ cfg( all( test, not( target_os = "emscripten" ) ) ) ]
2
2
mod tests;
3
3
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} ;
5
5
6
+ pub use self :: cstring_array:: CStringArray ;
7
+ use self :: cstring_array:: CStringIter ;
6
8
use crate :: collections:: BTreeMap ;
7
9
use crate :: ffi:: { CStr , CString , OsStr , OsString } ;
8
10
use crate :: os:: unix:: prelude:: * ;
@@ -14,7 +16,9 @@ use crate::sys::fs::OpenOptions;
14
16
use crate :: sys:: pipe:: { self , AnonPipe } ;
15
17
use crate :: sys:: process:: env:: { CommandEnv , CommandEnvs } ;
16
18
use crate :: sys_common:: { FromInner , IntoInner } ;
17
- use crate :: { fmt, io, ptr} ;
19
+ use crate :: { fmt, io} ;
20
+
21
+ mod cstring_array;
18
22
19
23
cfg_if:: cfg_if! {
20
24
if #[ cfg( target_os = "fuchsia" ) ] {
@@ -77,13 +81,7 @@ cfg_if::cfg_if! {
77
81
78
82
pub struct Command {
79
83
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 ,
87
85
env : CommandEnv ,
88
86
89
87
program_kind : ProgramKind ,
@@ -102,14 +100,6 @@ pub struct Command {
102
100
pgroup : Option < pid_t > ,
103
101
}
104
102
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
-
113
103
// passed back to std::process with the pipes connected to the child, if any
114
104
// were requested
115
105
pub struct StdioPipes {
@@ -171,42 +161,17 @@ impl ProgramKind {
171
161
}
172
162
173
163
impl Command {
174
- #[ cfg( not( target_os = "linux" ) ) ]
175
164
pub fn new ( program : & OsStr ) -> Command {
176
165
let mut saw_nul = false ;
177
166
let program_kind = ProgramKind :: new ( program. as_ref ( ) ) ;
178
167
let program = os2c ( program, & mut saw_nul) ;
168
+ let mut args = CStringArray :: with_capacity ( 1 ) ;
169
+ args. push ( program. clone ( ) ) ;
179
170
Command {
180
- argv : Argv ( vec ! [ program. as_ptr( ) , ptr:: null( ) ] ) ,
181
- args : vec ! [ program. clone( ) ] ,
182
171
program,
183
- program_kind ,
172
+ args ,
184
173
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,
208
174
program_kind,
209
- env : Default :: default ( ) ,
210
175
cwd : None ,
211
176
chroot : None ,
212
177
uid : None ,
@@ -217,6 +182,7 @@ impl Command {
217
182
stdin : None ,
218
183
stdout : None ,
219
184
stderr : None ,
185
+ #[ cfg( target_os = "linux" ) ]
220
186
create_pidfd : false ,
221
187
pgroup : None ,
222
188
}
@@ -225,20 +191,11 @@ impl Command {
225
191
pub fn set_arg_0 ( & mut self , arg : & OsStr ) {
226
192
// Set a new arg0
227
193
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) ;
231
195
}
232
196
233
197
pub fn arg ( & mut self , arg : & OsStr ) {
234
- // Overwrite the trailing null pointer in `argv` and then add a new null
235
- // pointer.
236
198
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.
242
199
self . args . push ( arg) ;
243
200
}
244
201
@@ -295,6 +252,8 @@ impl Command {
295
252
296
253
pub fn get_args ( & self ) -> CommandArgs < ' _ > {
297
254
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.
298
257
iter. next ( ) ;
299
258
CommandArgs { iter }
300
259
}
@@ -307,12 +266,12 @@ impl Command {
307
266
self . cwd . as_ref ( ) . map ( |cs| Path :: new ( OsStr :: from_bytes ( cs. as_bytes ( ) ) ) )
308
267
}
309
268
310
- pub fn get_argv ( & self ) -> & Vec < * const c_char > {
311
- & self . argv . 0
269
+ pub fn get_argv ( & self ) -> & CStringArray {
270
+ & self . args
312
271
}
313
272
314
273
pub fn get_program_cstr ( & self ) -> & CStr {
315
- & * self . program
274
+ & self . program
316
275
}
317
276
318
277
#[ allow( dead_code) ]
@@ -405,32 +364,6 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
405
364
} )
406
365
}
407
366
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
-
434
367
fn construct_envp ( env : BTreeMap < OsString , OsString > , saw_nul : & mut bool ) -> CStringArray {
435
368
let mut result = CStringArray :: with_capacity ( env. len ( ) ) ;
436
369
for ( mut k, v) in env {
@@ -619,14 +552,16 @@ impl fmt::Debug for Command {
619
552
write ! ( f, "{}={value:?} " , key. to_string_lossy( ) ) ?;
620
553
}
621
554
}
622
- if self . program != self . args [ 0 ] {
555
+
556
+ if * self . program != self . args [ 0 ] {
623
557
write ! ( f, "[{:?}] " , self . program) ?;
624
558
}
625
- write ! ( f, "{:?}" , self . args[ 0 ] ) ?;
559
+ write ! ( f, "{:?}" , & self . args[ 0 ] ) ?;
626
560
627
- for arg in & self . args [ 1 .. ] {
561
+ for arg in self . get_args ( ) {
628
562
write ! ( f, " {:?}" , arg) ?;
629
563
}
564
+
630
565
Ok ( ( ) )
631
566
}
632
567
}
@@ -658,14 +593,16 @@ impl From<u8> for ExitCode {
658
593
}
659
594
660
595
pub struct CommandArgs < ' a > {
661
- iter : crate :: slice :: Iter < ' a , CString > ,
596
+ iter : CStringIter < ' a > ,
662
597
}
663
598
664
599
impl < ' a > Iterator for CommandArgs < ' a > {
665
600
type Item = & ' a OsStr ;
601
+
666
602
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 ( ) ) )
668
604
}
605
+
669
606
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
670
607
self . iter . size_hint ( )
671
608
}
@@ -675,6 +612,7 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> {
675
612
fn len ( & self ) -> usize {
676
613
self . iter . len ( )
677
614
}
615
+
678
616
fn is_empty ( & self ) -> bool {
679
617
self . iter . is_empty ( )
680
618
}
0 commit comments