Skip to content

Commit d15bcdc

Browse files
committed
std: ChildProcess.spawn looks at PATH env var
closes #303
1 parent d65cd73 commit d15bcdc

File tree

3 files changed

+72
-26
lines changed

3 files changed

+72
-26
lines changed

std/mem.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool {
136136
return true;
137137
}
138138

139+
/// Linear search for the index of a scalar value inside a slice.
140+
pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize {
141+
for (slice) |item, i| {
142+
if (item == value) {
143+
return i;
144+
}
145+
}
146+
return null;
147+
}
148+
139149
/// Reads an integer from memory with size equal to bytes.len.
140150
/// T specifies the return type, which must be large enough to store
141151
/// the result.

std/os/child_process.zig

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,8 @@ pub const ChildProcess = struct {
154154
setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
155155
|err| forkChildErrReport(err_pipe[1], err);
156156

157-
const err = posix.getErrno(%return os.posixExecve(exe_path, args, env_map, allocator));
158-
assert(err > 0);
159-
forkChildErrReport(err_pipe[1], switch (err) {
160-
errno.EFAULT => unreachable,
161-
errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources,
162-
errno.EACCES, errno.EPERM => error.AccessDenied,
163-
errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
164-
errno.EIO, errno.ELOOP => error.FileSystem,
165-
errno.EISDIR => error.IsDir,
166-
errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
167-
errno.ETXTBSY => error.FileBusy,
168-
else => error.Unexpected,
169-
});
157+
os.posixExecve(exe_path, args, env_map, allocator) %%
158+
|err| forkChildErrReport(err_pipe[1], err);
170159
}
171160

172161
// we are the parent

std/os/index.zig

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,11 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
203203
/// This function must allocate memory to add a null terminating bytes on path and each arg.
204204
/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
205205
/// pointers after the args and after the environment variables.
206-
/// Also make the first arg equal to path.
207-
pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const BufMap,
208-
allocator: &Allocator) -> %usize
206+
/// Also make the first arg equal to exe_path.
207+
/// This function also uses the PATH environment variable to get the full path to the executable.
208+
pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap,
209+
allocator: &Allocator) -> %void
209210
{
210-
const path_buf = %return allocator.alloc(u8, path.len + 1);
211-
defer allocator.free(path_buf);
212-
@memcpy(&path_buf[0], &path[0], path.len);
213-
path_buf[path.len] = 0;
214-
215211
const argv_buf = %return allocator.alloc(?&const u8, argv.len + 2);
216212
mem.set(?&const u8, argv_buf, null);
217213
defer {
@@ -222,10 +218,10 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B
222218
allocator.free(argv_buf);
223219
}
224220
{
225-
// Add path to the first argument.
226-
const arg_buf = %return allocator.alloc(u8, path.len + 1);
227-
@memcpy(&arg_buf[0], path.ptr, path.len);
228-
arg_buf[path.len] = 0;
221+
// Add exe_path to the first argument.
222+
const arg_buf = %return allocator.alloc(u8, exe_path.len + 1);
223+
@memcpy(&arg_buf[0], exe_path.ptr, exe_path.len);
224+
arg_buf[exe_path.len] = 0;
229225

230226
argv_buf[0] = arg_buf.ptr;
231227
}
@@ -266,7 +262,58 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B
266262
}
267263
envp_buf[envp_count] = null;
268264

269-
return posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);
265+
266+
if (mem.indexOfScalar(u8, exe_path, '/') != null) {
267+
// +1 for the null terminating byte
268+
const path_buf = %return allocator.alloc(u8, exe_path.len + 1);
269+
defer allocator.free(path_buf);
270+
@memcpy(&path_buf[0], &exe_path[0], exe_path.len);
271+
path_buf[exe_path.len] = 0;
272+
return posixExecveErrnoToErr(posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr)));
273+
}
274+
275+
const PATH = getEnv("PATH") ?? ([]const u8)("/usr/local/bin:/bin/:/usr/bin"); // TODO issue #299
276+
// PATH.len because it is >= the largest search_path
277+
// +1 for the / to join the search path and exe_path
278+
// +1 for the null terminating byte
279+
const path_buf = %return allocator.alloc(u8, PATH.len + exe_path.len + 2);
280+
defer allocator.free(path_buf);
281+
var it = mem.split(PATH, ':');
282+
var seen_eacces = false;
283+
var err: usize = undefined;
284+
while (true) {
285+
const search_path = it.next() ?? break;
286+
mem.copy(u8, path_buf, search_path);
287+
path_buf[search_path.len] = '/';
288+
mem.copy(u8, path_buf[search_path.len + 1 ...], exe_path);
289+
path_buf[search_path.len + exe_path.len + 2] = 0;
290+
err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
291+
assert(err > 0);
292+
if (err == errno.EACCES) {
293+
seen_eacces = true;
294+
} else if (err != errno.ENOENT) {
295+
return posixExecveErrnoToErr(err);
296+
}
297+
}
298+
if (seen_eacces) {
299+
err = errno.EACCES;
300+
}
301+
return posixExecveErrnoToErr(err);
302+
}
303+
304+
fn posixExecveErrnoToErr(err: usize) -> error {
305+
assert(err > 0);
306+
return switch (err) {
307+
errno.EFAULT => unreachable,
308+
errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources,
309+
errno.EACCES, errno.EPERM => error.AccessDenied,
310+
errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
311+
errno.EIO, errno.ELOOP => error.FileSystem,
312+
errno.EISDIR => error.IsDir,
313+
errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
314+
errno.ETXTBSY => error.FileBusy,
315+
else => error.Unexpected,
316+
};
270317
}
271318

272319
pub var environ_raw: []&u8 = undefined;

0 commit comments

Comments
 (0)