authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-05 17:55:50-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-05 17:55:50-04:00
logd15bcdce691c1f42f70a5e9943817eb5ba974893
tree53d71b9b19498cda9a56dfe54430523666169207
parentd65cd73a8bfe39349be09a5f76f8477f3e3210b9

std: ChildProcess.spawn looks at PATH env var

closes #303

3 files changed, 72 insertions(+), 26 deletions(-)

std/mem.zig+10
......@@ -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.
140pub 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+2-13
......@@ -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+60-13
......@@ -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.
207pub 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.
208pub 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
304fn 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
272319pub var environ_raw: []&u8 = undefined;