@@ -83,7 +83,7 @@ pub coldcc fn abort() -> noreturn {
83
83
c .abort ();
84
84
}
85
85
switch (@compileVar ("os" )) {
86
- Os .linux = > {
86
+ Os .linux , Os . darwin , Os . macosx , Os . ios = > {
87
87
_ = posix .raise (posix .SIGABRT );
88
88
_ = posix .raise (posix .SIGKILL );
89
89
while (true ) {}
@@ -234,12 +234,12 @@ pub const ChildProcess = struct {
234
234
Close ,
235
235
};
236
236
237
- pub fn spawn (exe_path : []const u8 , args : []const []const u8 , env : []const [] const u8 ,
238
- stdin : StdIo , stdout : StdIo , stderr : StdIo ) - > % ChildProcess
237
+ pub fn spawn (exe_path : []const u8 , args : []const []const u8 , env : []const EnvPair ,
238
+ stdin : StdIo , stdout : StdIo , stderr : StdIo , allocator : & Allocator ) - > % ChildProcess
239
239
{
240
240
switch (@compileVar ("os" )) {
241
241
Os .linux , Os .macosx , Os .ios , Os .darwin = > {
242
- return spawnPosix (exe_path , args , env , stdin , stdout , stderr );
242
+ return spawnPosix (exe_path , args , env , stdin , stdout , stderr , allocator );
243
243
},
244
244
else = > @compileError ("Unsupported OS" ),
245
245
}
@@ -301,8 +301,8 @@ pub const ChildProcess = struct {
301
301
};
302
302
}
303
303
304
- fn spawnPosix (exe_path : []const u8 , args : []const []const u8 , env : []const [] const u8 ,
305
- stdin : StdIo , stdout : StdIo , stderr : StdIo ) - > % ChildProcess
304
+ fn spawnPosix (exe_path : []const u8 , args : []const []const u8 , env : []const EnvPair ,
305
+ stdin : StdIo , stdout : StdIo , stderr : StdIo , allocator : & Allocator ) - > % ChildProcess
306
306
{
307
307
// TODO issue #295
308
308
//const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;
@@ -358,7 +358,7 @@ pub const ChildProcess = struct {
358
358
setUpChildIo (stderr , stderr_pipe [1 ], posix .STDERR_FILENO , dev_null_fd ) %%
359
359
| err | forkChildErrReport (err_pipe [1 ], err );
360
360
361
- const err = posix .getErrno (posix . execve (exe_path , args , env ));
361
+ const err = posix .getErrno (% return execve (exe_path , args , env , allocator ));
362
362
assert (err > 0 );
363
363
forkChildErrReport (err_pipe [1 ], switch (err ) {
364
364
errno .EFAULT = > unreachable ,
@@ -419,6 +419,65 @@ pub const ChildProcess = struct {
419
419
}
420
420
};
421
421
422
+ /// This function must allocate memory to add a null terminating bytes on path and each arg.
423
+ /// It must also convert to KEY=VALUE\0 format for environment variables, and include null
424
+ /// pointers after the args and after the environment variables.
425
+ /// Also make the first arg equal to path.
426
+ fn execve (path : []const u8 , argv : []const []const u8 , envp : []const EnvPair , allocator : & Allocator ) - > % usize {
427
+ const path_buf = % return allocator .alloc (u8 , path .len + 1 );
428
+ defer allocator .free (path_buf );
429
+ @memcpy (& path_buf [0 ], & path [0 ], path .len );
430
+ path_buf [path .len ] = 0 ;
431
+
432
+ const argv_buf = % return allocator .alloc (? & const u8 , argv .len + 2 );
433
+ mem .set (? & const u8 , argv_buf , null );
434
+ defer {
435
+ for (argv_buf ) | arg , i | {
436
+ const arg_buf = if (const ptr ? = arg ) ptr [0... argv [i ].len + 1 ] else break ;
437
+ allocator .free (arg_buf );
438
+ }
439
+ allocator .free (argv_buf );
440
+ }
441
+ {
442
+ // Add path to the first argument.
443
+ const arg_buf = % return allocator .alloc (u8 , path .len + 1 );
444
+ @memcpy (& arg_buf [0 ], path .ptr , path .len );
445
+ arg_buf [path .len ] = 0 ;
446
+
447
+ argv_buf [0 ] = arg_buf .ptr ;
448
+ }
449
+ for (argv ) | arg , i | {
450
+ const arg_buf = % return allocator .alloc (u8 , arg .len + 1 );
451
+ @memcpy (& arg_buf [0 ], arg .ptr , arg .len );
452
+ arg_buf [arg .len ] = 0 ;
453
+
454
+ argv_buf [i + 1 ] = arg_buf .ptr ;
455
+ }
456
+ argv_buf [argv .len + 1 ] = null ;
457
+
458
+ const envp_buf = % return allocator .alloc (? & const u8 , envp .len + 1 );
459
+ mem .set (? & const u8 , envp_buf , null );
460
+ defer {
461
+ for (envp_buf ) | env , i | {
462
+ const env_buf = if (const ptr ? = env ) ptr [0... envp [i ].key .len + envp [i ].value .len + 2 ] else break ;
463
+ allocator .free (env_buf );
464
+ }
465
+ allocator .free (envp_buf );
466
+ }
467
+ for (envp ) | pair , i | {
468
+ const env_buf = % return allocator .alloc (u8 , pair .key .len + pair .value .len + 2 );
469
+ @memcpy (& env_buf [0 ], pair .key .ptr , pair .key .len );
470
+ env_buf [pair .key .len ] = '=' ;
471
+ @memcpy (& env_buf [pair .key .len + 1 ], pair .value .ptr , pair .value .len );
472
+ env_buf [env_buf .len - 1 ] = 0 ;
473
+
474
+ envp_buf [i ] = env_buf .ptr ;
475
+ }
476
+ envp_buf [envp .len ] = null ;
477
+
478
+ return posix .execve (path_buf .ptr , argv_buf .ptr , envp_buf .ptr );
479
+ }
480
+
422
481
pub const EnvPair = struct {
423
482
key : []const u8 ,
424
483
value : []const u8 ,
0 commit comments