| ... | ... | @@ -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, |