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_common:: process:: { 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 ,
@@ -101,14 +99,6 @@ pub struct Command {
101
99
pgroup : Option < pid_t > ,
102
100
}
103
101
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
-
112
102
// passed back to std::process with the pipes connected to the child, if any
113
103
// were requested
114
104
pub struct StdioPipes {
@@ -170,41 +160,17 @@ impl ProgramKind {
170
160
}
171
161
172
162
impl Command {
173
- #[ cfg( not( target_os = "linux" ) ) ]
174
163
pub fn new ( program : & OsStr ) -> Command {
175
164
let mut saw_nul = false ;
176
165
let program_kind = ProgramKind :: new ( program. as_ref ( ) ) ;
177
166
let program = os2c ( program, & mut saw_nul) ;
167
+ let mut args = CStringArray :: with_capacity ( 1 ) ;
168
+ args. push ( program. clone ( ) ) ;
178
169
Command {
179
- argv : Argv ( vec ! [ program. as_ptr( ) , ptr:: null( ) ] ) ,
180
- args : vec ! [ program. clone( ) ] ,
181
170
program,
182
- program_kind ,
171
+ args ,
183
172
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,
206
173
program_kind,
207
- env : Default :: default ( ) ,
208
174
cwd : None ,
209
175
uid : None ,
210
176
gid : None ,
@@ -214,6 +180,7 @@ impl Command {
214
180
stdin : None ,
215
181
stdout : None ,
216
182
stderr : None ,
183
+ #[ cfg( target_os = "linux" ) ]
217
184
create_pidfd : false ,
218
185
pgroup : None ,
219
186
}
@@ -222,20 +189,11 @@ impl Command {
222
189
pub fn set_arg_0 ( & mut self , arg : & OsStr ) {
223
190
// Set a new arg0
224
191
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) ;
228
193
}
229
194
230
195
pub fn arg ( & mut self , arg : & OsStr ) {
231
- // Overwrite the trailing null pointer in `argv` and then add a new null
232
- // pointer.
233
196
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.
239
197
self . args . push ( arg) ;
240
198
}
241
199
@@ -286,6 +244,8 @@ impl Command {
286
244
287
245
pub fn get_args ( & self ) -> CommandArgs < ' _ > {
288
246
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.
289
249
iter. next ( ) ;
290
250
CommandArgs { iter }
291
251
}
@@ -298,12 +258,12 @@ impl Command {
298
258
self . cwd . as_ref ( ) . map ( |cs| Path :: new ( OsStr :: from_bytes ( cs. as_bytes ( ) ) ) )
299
259
}
300
260
301
- pub fn get_argv ( & self ) -> & Vec < * const c_char > {
302
- & self . argv . 0
261
+ pub fn get_argv ( & self ) -> & CStringArray {
262
+ & self . args
303
263
}
304
264
305
265
pub fn get_program_cstr ( & self ) -> & CStr {
306
- & * self . program
266
+ & self . program
307
267
}
308
268
309
269
#[ allow( dead_code) ]
@@ -392,32 +352,6 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
392
352
} )
393
353
}
394
354
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
-
421
355
fn construct_envp ( env : BTreeMap < OsString , OsString > , saw_nul : & mut bool ) -> CStringArray {
422
356
let mut result = CStringArray :: with_capacity ( env. len ( ) ) ;
423
357
for ( mut k, v) in env {
@@ -606,14 +540,16 @@ impl fmt::Debug for Command {
606
540
write ! ( f, "{}={value:?} " , key. to_string_lossy( ) ) ?;
607
541
}
608
542
}
609
- if self . program != self . args [ 0 ] {
543
+
544
+ if * self . program != self . args [ 0 ] {
610
545
write ! ( f, "[{:?}] " , self . program) ?;
611
546
}
612
- write ! ( f, "{:?}" , self . args[ 0 ] ) ?;
547
+ write ! ( f, "{:?}" , & self . args[ 0 ] ) ?;
613
548
614
- for arg in & self . args [ 1 .. ] {
549
+ for arg in self . get_args ( ) {
615
550
write ! ( f, " {:?}" , arg) ?;
616
551
}
552
+
617
553
Ok ( ( ) )
618
554
}
619
555
}
@@ -645,14 +581,16 @@ impl From<u8> for ExitCode {
645
581
}
646
582
647
583
pub struct CommandArgs < ' a > {
648
- iter : crate :: slice :: Iter < ' a , CString > ,
584
+ iter : CStringIter < ' a > ,
649
585
}
650
586
651
587
impl < ' a > Iterator for CommandArgs < ' a > {
652
588
type Item = & ' a OsStr ;
589
+
653
590
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 ( ) ) )
655
592
}
593
+
656
594
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
657
595
self . iter . size_hint ( )
658
596
}
@@ -662,6 +600,7 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> {
662
600
fn len ( & self ) -> usize {
663
601
self . iter . len ( )
664
602
}
603
+
665
604
fn is_empty ( & self ) -> bool {
666
605
self . iter . is_empty ( )
667
606
}
0 commit comments