master
1const errno = std.posix.errno;
2const unexpectedErrno = std.posix.unexpectedErrno;
3
4pub const Error = error{
5 SystemResources,
6 InvalidFileDescriptor,
7 NameTooLong,
8 TooBig,
9 AccessDenied,
10 PermissionDenied,
11 InputOutput,
12 FileSystem,
13 FileNotFound,
14 InvalidExe,
15 NotDir,
16 FileBusy,
17 /// Returned when the child fails to execute either in the pre-exec() initialization step, or
18 /// when exec(3) is invoked.
19 ChildExecFailed,
20} || std.posix.UnexpectedError;
21
22pub const Attr = struct {
23 attr: std.c.posix_spawnattr_t,
24
25 pub fn init() Error!Attr {
26 var attr: std.c.posix_spawnattr_t = undefined;
27 switch (errno(std.c.posix_spawnattr_init(&attr))) {
28 .SUCCESS => return Attr{ .attr = attr },
29 .NOMEM => return error.SystemResources,
30 .INVAL => unreachable,
31 else => |err| return unexpectedErrno(err),
32 }
33 }
34
35 pub fn deinit(self: *Attr) void {
36 defer self.* = undefined;
37 switch (errno(std.c.posix_spawnattr_destroy(&self.attr))) {
38 .SUCCESS => return,
39 .INVAL => unreachable, // Invalid parameters.
40 else => unreachable,
41 }
42 }
43
44 pub fn get(self: Attr) Error!std.c.POSIX_SPAWN {
45 var flags: std.c.POSIX_SPAWN = undefined;
46 switch (errno(std.c.posix_spawnattr_getflags(&self.attr, &flags))) {
47 .SUCCESS => return flags,
48 .INVAL => unreachable,
49 else => |err| return unexpectedErrno(err),
50 }
51 }
52
53 pub fn set(self: *Attr, flags: std.c.POSIX_SPAWN) Error!void {
54 switch (errno(std.c.posix_spawnattr_setflags(&self.attr, flags))) {
55 .SUCCESS => return,
56 .INVAL => unreachable,
57 else => |err| return unexpectedErrno(err),
58 }
59 }
60};
61
62pub const Actions = struct {
63 actions: std.c.posix_spawn_file_actions_t,
64
65 pub fn init() Error!Actions {
66 var actions: std.c.posix_spawn_file_actions_t = undefined;
67 switch (errno(std.c.posix_spawn_file_actions_init(&actions))) {
68 .SUCCESS => return Actions{ .actions = actions },
69 .NOMEM => return error.SystemResources,
70 .INVAL => unreachable,
71 else => |err| return unexpectedErrno(err),
72 }
73 }
74
75 pub fn deinit(self: *Actions) void {
76 defer self.* = undefined;
77 switch (errno(std.c.posix_spawn_file_actions_destroy(&self.actions))) {
78 .SUCCESS => return,
79 .INVAL => unreachable, // Invalid parameters.
80 else => unreachable,
81 }
82 }
83
84 pub fn open(self: *Actions, fd: std.c.fd_t, path: []const u8, flags: u32, mode: std.c.mode_t) Error!void {
85 const posix_path = try std.posix.toPosixPath(path);
86 return self.openZ(fd, &posix_path, flags, mode);
87 }
88
89 pub fn openZ(self: *Actions, fd: std.c.fd_t, path: [*:0]const u8, flags: u32, mode: std.c.mode_t) Error!void {
90 switch (errno(std.c.posix_spawn_file_actions_addopen(&self.actions, fd, path, @as(c_int, @bitCast(flags)), mode))) {
91 .SUCCESS => return,
92 .BADF => return error.InvalidFileDescriptor,
93 .NOMEM => return error.SystemResources,
94 .NAMETOOLONG => return error.NameTooLong,
95 .INVAL => unreachable, // the value of file actions is invalid
96 else => |err| return unexpectedErrno(err),
97 }
98 }
99
100 pub fn close(self: *Actions, fd: std.c.fd_t) Error!void {
101 switch (errno(std.c.posix_spawn_file_actions_addclose(&self.actions, fd))) {
102 .SUCCESS => return,
103 .BADF => return error.InvalidFileDescriptor,
104 .NOMEM => return error.SystemResources,
105 .INVAL => unreachable, // the value of file actions is invalid
106 .NAMETOOLONG => unreachable,
107 else => |err| return unexpectedErrno(err),
108 }
109 }
110
111 pub fn dup2(self: *Actions, fd: std.c.fd_t, newfd: std.c.fd_t) Error!void {
112 switch (errno(std.c.posix_spawn_file_actions_adddup2(&self.actions, fd, newfd))) {
113 .SUCCESS => return,
114 .BADF => return error.InvalidFileDescriptor,
115 .NOMEM => return error.SystemResources,
116 .INVAL => unreachable, // the value of file actions is invalid
117 .NAMETOOLONG => unreachable,
118 else => |err| return unexpectedErrno(err),
119 }
120 }
121
122 pub fn inherit(self: *Actions, fd: std.c.fd_t) Error!void {
123 switch (errno(std.c.posix_spawn_file_actions_addinherit_np(&self.actions, fd))) {
124 .SUCCESS => return,
125 .BADF => return error.InvalidFileDescriptor,
126 .NOMEM => return error.SystemResources,
127 .INVAL => unreachable, // the value of file actions is invalid
128 .NAMETOOLONG => unreachable,
129 else => |err| return unexpectedErrno(err),
130 }
131 }
132
133 pub fn chdir(self: *Actions, path: []const u8) Error!void {
134 const posix_path = try std.posix.toPosixPath(path);
135 return self.chdirZ(&posix_path);
136 }
137
138 pub fn chdirZ(self: *Actions, path: [*:0]const u8) Error!void {
139 switch (errno(std.c.posix_spawn_file_actions_addchdir_np(&self.actions, path))) {
140 .SUCCESS => return,
141 .NOMEM => return error.SystemResources,
142 .NAMETOOLONG => return error.NameTooLong,
143 .BADF => unreachable,
144 .INVAL => unreachable, // the value of file actions is invalid
145 else => |err| return unexpectedErrno(err),
146 }
147 }
148
149 pub fn fchdir(self: *Actions, fd: std.c.fd_t) Error!void {
150 switch (errno(std.c.posix_spawn_file_actions_addfchdir_np(&self.actions, fd))) {
151 .SUCCESS => return,
152 .BADF => return error.InvalidFileDescriptor,
153 .NOMEM => return error.SystemResources,
154 .INVAL => unreachable, // the value of file actions is invalid
155 .NAMETOOLONG => unreachable,
156 else => |err| return unexpectedErrno(err),
157 }
158 }
159};
160
161pub fn spawn(
162 path: []const u8,
163 actions: ?Actions,
164 attr: ?Attr,
165 argv: [*:null]const ?[*:0]const u8,
166 envp: [*:null]const ?[*:0]const u8,
167) Error!std.c.pid_t {
168 const posix_path = try std.posix.toPosixPath(path);
169 return spawnZ(&posix_path, actions, attr, argv, envp);
170}
171
172pub fn spawnZ(
173 path: [*:0]const u8,
174 actions: ?Actions,
175 attr: ?Attr,
176 argv: [*:null]const ?[*:0]const u8,
177 envp: [*:null]const ?[*:0]const u8,
178) Error!std.c.pid_t {
179 var pid: std.c.pid_t = undefined;
180 switch (errno(std.c.posix_spawn(
181 &pid,
182 path,
183 if (actions) |a| &a.actions else null,
184 if (attr) |a| &a.attr else null,
185 argv,
186 envp,
187 ))) {
188 .SUCCESS => return pid,
189 .@"2BIG" => return error.TooBig,
190 .NOMEM => return error.SystemResources,
191 .BADF => return error.InvalidFileDescriptor,
192 .ACCES => return error.AccessDenied,
193 .IO => return error.InputOutput,
194 .LOOP => return error.FileSystem,
195 .NAMETOOLONG => return error.NameTooLong,
196 .NOENT => return error.FileNotFound,
197 .NOEXEC => return error.InvalidExe,
198 .NOTDIR => return error.NotDir,
199 .TXTBSY => return error.FileBusy,
200 .BADARCH => return error.InvalidExe,
201 .BADEXEC => return error.InvalidExe,
202 .FAULT => unreachable,
203 .INVAL => unreachable,
204 else => |err| return unexpectedErrno(err),
205 }
206}
207
208pub fn waitpid(pid: std.c.pid_t, flags: u32) Error!std.posix.WaitPidResult {
209 var status: c_int = undefined;
210 while (true) {
211 const rc = waitpid(pid, &status, @as(c_int, @intCast(flags)));
212 switch (errno(rc)) {
213 .SUCCESS => return std.posix.WaitPidResult{
214 .pid = @as(std.c.pid_t, @intCast(rc)),
215 .status = @as(u32, @bitCast(status)),
216 },
217 .INTR => continue,
218 .CHILD => return error.ChildExecFailed,
219 .INVAL => unreachable, // Invalid flags.
220 else => unreachable,
221 }
222 }
223}
224
225const std = @import("std");