Commit 266c81322e

Jakub Konka <kubkon@jakubkonka.com>
2023-03-16 18:48:16
darwin: resurrect posix_spawn wrappers
1 parent e35c8a2
Changed files (1)
lib
lib/std/c/darwin.zig
@@ -203,47 +203,6 @@ pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) kern_retu
 pub extern "c" fn malloc_size(?*const anyopaque) usize;
 pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
 
-pub const posix_spawnattr_t = *opaque {};
-pub const posix_spawn_file_actions_t = *opaque {};
-pub extern "c" fn posix_spawnattr_init(attr: *posix_spawnattr_t) c_int;
-pub extern "c" fn posix_spawnattr_destroy(attr: *posix_spawnattr_t) c_int;
-pub extern "c" fn posix_spawnattr_setflags(attr: *posix_spawnattr_t, flags: c_short) c_int;
-pub extern "c" fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *c_short) c_int;
-pub extern "c" fn posix_spawn_file_actions_init(actions: *posix_spawn_file_actions_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_destroy(actions: *posix_spawn_file_actions_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_addclose(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_addopen(
-    actions: *posix_spawn_file_actions_t,
-    filedes: fd_t,
-    path: [*:0]const u8,
-    oflag: c_int,
-    mode: mode_t,
-) c_int;
-pub extern "c" fn posix_spawn_file_actions_adddup2(
-    actions: *posix_spawn_file_actions_t,
-    filedes: fd_t,
-    newfiledes: fd_t,
-) c_int;
-pub extern "c" fn posix_spawn_file_actions_addinherit_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
-pub extern "c" fn posix_spawn_file_actions_addchdir_np(actions: *posix_spawn_file_actions_t, path: [*:0]const u8) c_int;
-pub extern "c" fn posix_spawn_file_actions_addfchdir_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
-pub extern "c" fn posix_spawn(
-    pid: *pid_t,
-    path: [*:0]const u8,
-    actions: ?*const posix_spawn_file_actions_t,
-    attr: ?*const posix_spawnattr_t,
-    argv: [*:null]?[*:0]const u8,
-    env: [*:null]?[*:0]const u8,
-) c_int;
-pub extern "c" fn posix_spawnp(
-    pid: *pid_t,
-    path: [*:0]const u8,
-    actions: ?*const posix_spawn_file_actions_t,
-    attr: ?*const posix_spawnattr_t,
-    argv: [*:null]?[*:0]const u8,
-    env: [*:null]?[*:0]const u8,
-) c_int;
-
 pub extern "c" fn kevent64(
     kq: c_int,
     changelist: [*]const kevent64_s,
@@ -2176,18 +2135,6 @@ pub const E = enum(u16) {
     _,
 };
 
-pub fn getKernError(err: kern_return_t) KernE {
-    return @intToEnum(KernE, @truncate(u32, @intCast(usize, err)));
-}
-
-pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
-    if (std.os.unexpected_error_tracing) {
-        std.debug.print("unexpected errno: {d}\n", .{@enumToInt(err)});
-        std.debug.dumpCurrentStackTrace(null);
-    }
-    return error.Unexpected;
-}
-
 /// Kernel return values
 pub const KernE = enum(u32) {
     SUCCESS = 0,
@@ -3063,6 +3010,29 @@ pub const CPUFAMILY = enum(u32) {
     _,
 };
 
+pub const PT = struct {
+    pub const TRACE_ME = 0;
+    pub const READ_I = 1;
+    pub const READ_D = 2;
+    pub const READ_U = 3;
+    pub const WRITE_I = 4;
+    pub const WRITE_D = 5;
+    pub const WRITE_U = 6;
+    pub const CONTINUE = 7;
+    pub const KILL = 8;
+    pub const STEP = 9;
+    pub const DETACH = 11;
+    pub const SIGEXC = 12;
+    pub const THUPDATE = 13;
+    pub const ATTACHEXC = 14;
+    pub const FORCEQUOTA = 30;
+    pub const DENY_ATTACH = 31;
+};
+
+pub const caddr_t = ?[*]u8;
+
+pub extern "c" fn ptrace(request: c_int, pid: pid_t, addr: caddr_t, data: c_int) c_int;
+
 pub const POSIX_SPAWN_RESETIDS = 0x0001;
 pub const POSIX_SPAWN_SETPGROUP = 0x0002;
 pub const POSIX_SPAWN_SETSIGDEF = 0x0004;
@@ -3074,26 +3044,283 @@ pub const POSIX_SPAWN_SETSID = 0x0400;
 pub const _POSIX_SPAWN_RESLIDE = 0x0800;
 pub const POSIX_SPAWN_CLOEXEC_DEFAULT = 0x4000;
 
-pub const PT_TRACE_ME = 0;
-pub const PT_READ_I = 1;
-pub const PT_READ_D = 2;
-pub const PT_READ_U = 3;
-pub const PT_WRITE_I = 4;
-pub const PT_WRITE_D = 5;
-pub const PT_WRITE_U = 6;
-pub const PT_CONTINUE = 7;
-pub const PT_KILL = 8;
-pub const PT_STEP = 9;
-pub const PT_DETACH = 11;
-pub const PT_SIGEXC = 12;
-pub const PT_THUPDATE = 13;
-pub const PT_ATTACHEXC = 14;
-pub const PT_FORCEQUOTA = 30;
-pub const PT_DENY_ATTACH = 31;
+pub const posix_spawnattr_t = *opaque {};
+pub const posix_spawn_file_actions_t = *opaque {};
+pub extern "c" fn posix_spawnattr_init(attr: *posix_spawnattr_t) c_int;
+pub extern "c" fn posix_spawnattr_destroy(attr: *posix_spawnattr_t) c_int;
+pub extern "c" fn posix_spawnattr_setflags(attr: *posix_spawnattr_t, flags: c_short) c_int;
+pub extern "c" fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, flags: *c_short) c_int;
+pub extern "c" fn posix_spawn_file_actions_init(actions: *posix_spawn_file_actions_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_destroy(actions: *posix_spawn_file_actions_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_addclose(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_addopen(
+    actions: *posix_spawn_file_actions_t,
+    filedes: fd_t,
+    path: [*:0]const u8,
+    oflag: c_int,
+    mode: mode_t,
+) c_int;
+pub extern "c" fn posix_spawn_file_actions_adddup2(
+    actions: *posix_spawn_file_actions_t,
+    filedes: fd_t,
+    newfiledes: fd_t,
+) c_int;
+pub extern "c" fn posix_spawn_file_actions_addinherit_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+pub extern "c" fn posix_spawn_file_actions_addchdir_np(actions: *posix_spawn_file_actions_t, path: [*:0]const u8) c_int;
+pub extern "c" fn posix_spawn_file_actions_addfchdir_np(actions: *posix_spawn_file_actions_t, filedes: fd_t) c_int;
+pub extern "c" fn posix_spawn(
+    pid: *pid_t,
+    path: [*:0]const u8,
+    actions: ?*const posix_spawn_file_actions_t,
+    attr: ?*const posix_spawnattr_t,
+    argv: [*:null]?[*:0]const u8,
+    env: [*:null]?[*:0]const u8,
+) c_int;
+pub extern "c" fn posix_spawnp(
+    pid: *pid_t,
+    path: [*:0]const u8,
+    actions: ?*const posix_spawn_file_actions_t,
+    attr: ?*const posix_spawnattr_t,
+    argv: [*:null]?[*:0]const u8,
+    env: [*:null]?[*:0]const u8,
+) c_int;
+
+pub const PosixSpawn = struct {
+    const errno = std.os.errno;
+    const unexpectedErrno = std.os.unexpectedErrno;
+
+    pub const Error = error{
+        SystemResources,
+        InvalidFileDescriptor,
+        NameTooLong,
+        TooBig,
+        PermissionDenied,
+        InputOutput,
+        FileSystem,
+        FileNotFound,
+        InvalidExe,
+        NotDir,
+        FileBusy,
+        /// Returned when the child fails to execute either in the pre-exec() initialization step, or
+        /// when exec(3) is invoked.
+        ChildExecFailed,
+    } || std.os.UnexpectedError;
+
+    pub const Attr = struct {
+        attr: posix_spawnattr_t,
+
+        pub fn init() Error!Attr {
+            var attr: posix_spawnattr_t = undefined;
+            switch (errno(posix_spawnattr_init(&attr))) {
+                .SUCCESS => return Attr{ .attr = attr },
+                .NOMEM => return error.SystemResources,
+                .INVAL => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
 
-pub const caddr_t = ?[*]u8;
+        pub fn deinit(self: *Attr) void {
+            defer self.* = undefined;
+            switch (errno(posix_spawnattr_destroy(&self.attr))) {
+                .SUCCESS => return,
+                .INVAL => unreachable, // Invalid parameters.
+                else => unreachable,
+            }
+        }
 
-pub extern "c" fn ptrace(request: c_int, pid: pid_t, addr: caddr_t, data: c_int) c_int;
+        pub fn get(self: Attr) Error!u16 {
+            var flags: c_short = undefined;
+            switch (errno(posix_spawnattr_getflags(&self.attr, &flags))) {
+                .SUCCESS => return @bitCast(u16, flags),
+                .INVAL => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+
+        pub fn set(self: *Attr, flags: u16) Error!void {
+            switch (errno(posix_spawnattr_setflags(&self.attr, @bitCast(c_short, flags)))) {
+                .SUCCESS => return,
+                .INVAL => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+    };
+
+    pub const Actions = struct {
+        actions: posix_spawn_file_actions_t,
+
+        pub fn init() Error!Actions {
+            var actions: posix_spawn_file_actions_t = undefined;
+            switch (errno(posix_spawn_file_actions_init(&actions))) {
+                .SUCCESS => return Actions{ .actions = actions },
+                .NOMEM => return error.SystemResources,
+                .INVAL => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+
+        pub fn deinit(self: *Actions) void {
+            defer self.* = undefined;
+            switch (errno(posix_spawn_file_actions_destroy(&self.actions))) {
+                .SUCCESS => return,
+                .INVAL => unreachable, // Invalid parameters.
+                else => unreachable,
+            }
+        }
+
+        pub fn open(self: *Actions, fd: fd_t, path: []const u8, flags: u32, mode: mode_t) Error!void {
+            const posix_path = try std.os.toPosixPath(path);
+            return self.openZ(fd, &posix_path, flags, mode);
+        }
+
+        pub fn openZ(self: *Actions, fd: fd_t, path: [*:0]const u8, flags: u32, mode: mode_t) Error!void {
+            switch (errno(posix_spawn_file_actions_addopen(&self.actions, fd, path, @bitCast(c_int, flags), mode))) {
+                .SUCCESS => return,
+                .BADF => return error.InvalidFileDescriptor,
+                .NOMEM => return error.SystemResources,
+                .NAMETOOLONG => return error.NameTooLong,
+                .INVAL => unreachable, // the value of file actions is invalid
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+
+        pub fn close(self: *Actions, fd: fd_t) Error!void {
+            switch (errno(posix_spawn_file_actions_addclose(&self.actions, fd))) {
+                .SUCCESS => return,
+                .BADF => return error.InvalidFileDescriptor,
+                .NOMEM => return error.SystemResources,
+                .INVAL => unreachable, // the value of file actions is invalid
+                .NAMETOOLONG => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+
+        pub fn dup2(self: *Actions, fd: fd_t, newfd: fd_t) Error!void {
+            switch (errno(posix_spawn_file_actions_adddup2(&self.actions, fd, newfd))) {
+                .SUCCESS => return,
+                .BADF => return error.InvalidFileDescriptor,
+                .NOMEM => return error.SystemResources,
+                .INVAL => unreachable, // the value of file actions is invalid
+                .NAMETOOLONG => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+
+        pub fn inherit(self: *Actions, fd: fd_t) Error!void {
+            switch (errno(posix_spawn_file_actions_addinherit_np(&self.actions, fd))) {
+                .SUCCESS => return,
+                .BADF => return error.InvalidFileDescriptor,
+                .NOMEM => return error.SystemResources,
+                .INVAL => unreachable, // the value of file actions is invalid
+                .NAMETOOLONG => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+
+        pub fn chdir(self: *Actions, path: []const u8) Error!void {
+            const posix_path = try std.os.toPosixPath(path);
+            return self.chdirZ(&posix_path);
+        }
+
+        pub fn chdirZ(self: *Actions, path: [*:0]const u8) Error!void {
+            switch (errno(posix_spawn_file_actions_addchdir_np(&self.actions, path))) {
+                .SUCCESS => return,
+                .NOMEM => return error.SystemResources,
+                .NAMETOOLONG => return error.NameTooLong,
+                .BADF => unreachable,
+                .INVAL => unreachable, // the value of file actions is invalid
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+
+        pub fn fchdir(self: *Actions, fd: fd_t) Error!void {
+            switch (errno(posix_spawn_file_actions_addfchdir_np(&self.actions, fd))) {
+                .SUCCESS => return,
+                .BADF => return error.InvalidFileDescriptor,
+                .NOMEM => return error.SystemResources,
+                .INVAL => unreachable, // the value of file actions is invalid
+                .NAMETOOLONG => unreachable,
+                else => |err| return unexpectedErrno(err),
+            }
+        }
+    };
+
+    pub fn spawn(
+        path: []const u8,
+        actions: ?Actions,
+        attr: ?Attr,
+        argv: [*:null]?[*:0]const u8,
+        envp: [*:null]?[*:0]const u8,
+    ) Error!pid_t {
+        const posix_path = try std.os.toPosixPath(path);
+        return spawnZ(&posix_path, actions, attr, argv, envp);
+    }
+
+    pub fn spawnZ(
+        path: [*:0]const u8,
+        actions: ?Actions,
+        attr: ?Attr,
+        argv: [*:null]?[*:0]const u8,
+        envp: [*:null]?[*:0]const u8,
+    ) Error!pid_t {
+        var pid: pid_t = undefined;
+        switch (errno(posix_spawn(
+            &pid,
+            path,
+            if (actions) |a| &a.actions else null,
+            if (attr) |a| &a.attr else null,
+            argv,
+            envp,
+        ))) {
+            .SUCCESS => return pid,
+            .@"2BIG" => return error.TooBig,
+            .NOMEM => return error.SystemResources,
+            .BADF => return error.InvalidFileDescriptor,
+            .ACCES => return error.PermissionDenied,
+            .IO => return error.InputOutput,
+            .LOOP => return error.FileSystem,
+            .NAMETOOLONG => return error.NameTooLong,
+            .NOENT => return error.FileNotFound,
+            .NOEXEC => return error.InvalidExe,
+            .NOTDIR => return error.NotDir,
+            .TXTBSY => return error.FileBusy,
+            .BADARCH => return error.InvalidExe,
+            .BADEXEC => return error.InvalidExe,
+            .FAULT => unreachable,
+            .INVAL => unreachable,
+            else => |err| return unexpectedErrno(err),
+        }
+    }
+
+    pub fn waitpid(pid: pid_t, flags: u32) Error!std.os.WaitPidResult {
+        var status: c_int = undefined;
+        while (true) {
+            const rc = waitpid(pid, &status, @intCast(c_int, flags));
+            switch (errno(rc)) {
+                .SUCCESS => return std.os.WaitPidResult{
+                    .pid = @intCast(pid_t, rc),
+                    .status = @bitCast(u32, status),
+                },
+                .INTR => continue,
+                .CHILD => return error.ChildExecFailed,
+                .INVAL => unreachable, // Invalid flags.
+                else => unreachable,
+            }
+        }
+    }
+};
+
+pub fn getKernError(err: kern_return_t) KernE {
+    return @intToEnum(KernE, @truncate(u32, @intCast(usize, err)));
+}
+
+pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
+    if (std.os.unexpected_error_tracing) {
+        std.debug.print("unexpected errno: {d}\n", .{@enumToInt(err)});
+        std.debug.dumpCurrentStackTrace(null);
+    }
+    return error.Unexpected;
+}
 
 pub const MachError = error{
     /// Not enough permissions held to perform the requested kernel