| ... | @@ -83,7 +83,7 @@ pub coldcc fn abort() -> noreturn { | ... | @@ -83,7 +83,7 @@ pub coldcc fn abort() -> noreturn { |
| 83 | c.abort(); | 83 | c.abort(); |
| 84 | } | 84 | } |
| 85 | switch (@compileVar("os")) { | 85 | switch (@compileVar("os")) { |
| 86 | Os.linux => { | 86 | Os.linux, Os.darwin, Os.macosx, Os.ios => { |
| 87 | _ = posix.raise(posix.SIGABRT); | 87 | _ = posix.raise(posix.SIGABRT); |
| 88 | _ = posix.raise(posix.SIGKILL); | 88 | _ = posix.raise(posix.SIGKILL); |
| 89 | while (true) {} | 89 | while (true) {} |
| ... | @@ -234,12 +234,12 @@ pub const ChildProcess = struct { | ... | @@ -234,12 +234,12 @@ pub const ChildProcess = struct { |
| 234 | Close, | 234 | Close, |
| 235 | }; | 235 | }; |
| 236 | | 236 | |
| 237 | pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const []const u8, | 237 | pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const EnvPair, |
| 238 | stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess | 238 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess |
| 239 | { | 239 | { |
| 240 | switch (@compileVar("os")) { | 240 | switch (@compileVar("os")) { |
| 241 | Os.linux, Os.macosx, Os.ios, Os.darwin => { | 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 | else => @compileError("Unsupported OS"), | 244 | else => @compileError("Unsupported OS"), |
| 245 | } | 245 | } |
| ... | @@ -301,8 +301,8 @@ pub const ChildProcess = struct { | ... | @@ -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, | 304 | fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const EnvPair, |
| 305 | stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess | 305 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess |
| 306 | { | 306 | { |
| 307 | // TODO issue #295 | 307 | // TODO issue #295 |
| 308 | //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; | 308 | //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; |
| ... | @@ -358,7 +358,7 @@ pub const ChildProcess = struct { | ... | @@ -358,7 +358,7 @@ pub const ChildProcess = struct { |
| 358 | setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% | 358 | setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% |
| 359 | |err| forkChildErrReport(err_pipe[1], err); | 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 | assert(err > 0); | 362 | assert(err > 0); |
| 363 | forkChildErrReport(err_pipe[1], switch (err) { | 363 | forkChildErrReport(err_pipe[1], switch (err) { |
| 364 | errno.EFAULT => unreachable, | 364 | errno.EFAULT => unreachable, |
| ... | @@ -419,6 +419,65 @@ pub const ChildProcess = struct { | ... | @@ -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 | pub const EnvPair = struct { | 481 | pub const EnvPair = struct { |
| 423 | key: []const u8, | 482 | key: []const u8, |
| 424 | value: []const u8, | 483 | value: []const u8, |