aboutsummaryrefslogtreecommitdiff
path: root/lib/std/process.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-12-26 16:33:38 -0800
committerGitHub <noreply@github.com>2020-12-26 16:33:38 -0800
commite5894221f7a886c8b0cc21b8369e4d3bf11890b0 (patch)
tree3697490677b01c796b62881adffa769f72560f0a /lib/std/process.zig
parent641bf4c46eb2d5c1f3e95898ed74848a56e0d999 (diff)
parentcb290ed6c99681ade0bace286ae5040546542395 (diff)
downloadzig-e5894221f7a886c8b0cc21b8369e4d3bf11890b0.tar.gz
zig-e5894221f7a886c8b0cc21b8369e4d3bf11890b0.zip
Merge pull request #7553 from ziglang/fix-the-damn-deadlock
Fix the damn deadlock
Diffstat (limited to 'lib/std/process.zig')
-rw-r--r--lib/std/process.zig66
1 files changed, 66 insertions, 0 deletions
diff --git a/lib/std/process.zig b/lib/std/process.zig
index e12bc28c0c..909b337f89 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -13,6 +13,7 @@ const math = std.math;
const Allocator = mem.Allocator;
const assert = std.debug.assert;
const testing = std.testing;
+const child_process = @import("child_process.zig");
pub const abort = os.abort;
pub const exit = os.exit;
@@ -778,3 +779,68 @@ pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]
else => @compileError("getSelfExeSharedLibPaths unimplemented for this target"),
}
}
+
+/// Tells whether calling the `execv` or `execve` functions will be a compile error.
+pub const can_execv = std.builtin.os.tag != .windows;
+
+pub const ExecvError = std.os.ExecveError || error{OutOfMemory};
+
+/// Replaces the current process image with the executed process.
+/// This function must allocate memory to add a null terminating bytes on path and each arg.
+/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
+/// pointers after the args and after the environment variables.
+/// `argv[0]` is the executable path.
+/// This function also uses the PATH environment variable to get the full path to the executable.
+/// Due to the heap-allocation, it is illegal to call this function in a fork() child.
+/// For that use case, use the `std.os` functions directly.
+pub fn execv(allocator: *mem.Allocator, argv: []const []const u8) ExecvError {
+ return execve(allocator, argv, null);
+}
+
+/// Replaces the current process image with the executed process.
+/// This function must allocate memory to add a null terminating bytes on path and each arg.
+/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
+/// pointers after the args and after the environment variables.
+/// `argv[0]` is the executable path.
+/// This function also uses the PATH environment variable to get the full path to the executable.
+/// Due to the heap-allocation, it is illegal to call this function in a fork() child.
+/// For that use case, use the `std.os` functions directly.
+pub fn execve(
+ allocator: *mem.Allocator,
+ argv: []const []const u8,
+ env_map: ?*const std.BufMap,
+) ExecvError {
+ if (!can_execv) @compileError("The target OS does not support execv");
+
+ var arena_allocator = std.heap.ArenaAllocator.init(allocator);
+ defer arena_allocator.deinit();
+ const arena = &arena_allocator.allocator;
+
+ const argv_buf = try arena.alloc(?[*:0]u8, argv.len + 1);
+ for (argv) |arg, i| {
+ const arg_buf = try arena.alloc(u8, arg.len + 1);
+ @memcpy(arg_buf.ptr, arg.ptr, arg.len);
+ arg_buf[arg.len] = 0;
+ argv_buf[i] = arg_buf[0..arg.len :0].ptr;
+ }
+ argv_buf[argv.len] = null;
+ const argv_ptr = argv_buf[0..argv.len :null].ptr;
+
+ const envp = m: {
+ if (env_map) |m| {
+ const envp_buf = try child_process.createNullDelimitedEnvMap(arena, m);
+ break :m envp_buf.ptr;
+ } else if (std.builtin.link_libc) {
+ break :m std.c.environ;
+ } else if (std.builtin.output_mode == .Exe) {
+ // Then we have Zig start code and this works.
+ // TODO type-safety for null-termination of `os.environ`.
+ break :m @ptrCast([*:null]?[*:0]u8, os.environ.ptr);
+ } else {
+ // TODO come up with a solution for this.
+ @compileError("missing std lib enhancement: std.process.execv implementation has no way to collect the environment variables to forward to the child process");
+ }
+ };
+
+ return os.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_ptr, envp);
+}