| ... | @@ -203,15 +203,11 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { | ... | @@ -203,15 +203,11 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { |
| 203 | /// This function must allocate memory to add a null terminating bytes on path and each arg. | 203 | /// This function must allocate memory to add a null terminating bytes on path and each arg. |
| 204 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null | 204 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null |
| 205 | /// pointers after the args and after the environment variables. | 205 | /// pointers after the args and after the environment variables. |
| 206 | /// Also make the first arg equal to path. | 206 | /// Also make the first arg equal to exe_path. |
| 207 | pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const BufMap, | 207 | /// This function also uses the PATH environment variable to get the full path to the executable. |
| 208 | allocator: &Allocator) -> %usize | 208 | pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap, |
| | 209 | allocator: &Allocator) -> %void |
| 209 | { | 210 | { |
| 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 | | | |
| 215 | const argv_buf = %return allocator.alloc(?&const u8, argv.len + 2); | 211 | const argv_buf = %return allocator.alloc(?&const u8, argv.len + 2); |
| 216 | mem.set(?&const u8, argv_buf, null); | 212 | mem.set(?&const u8, argv_buf, null); |
| 217 | defer { | 213 | defer { |
| ... | @@ -222,10 +218,10 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B | ... | @@ -222,10 +218,10 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B |
| 222 | allocator.free(argv_buf); | 218 | allocator.free(argv_buf); |
| 223 | } | 219 | } |
| 224 | { | 220 | { |
| 225 | // Add path to the first argument. | 221 | // Add exe_path to the first argument. |
| 226 | const arg_buf = %return allocator.alloc(u8, path.len + 1); | 222 | const arg_buf = %return allocator.alloc(u8, exe_path.len + 1); |
| 227 | @memcpy(&arg_buf[0], path.ptr, path.len); | 223 | @memcpy(&arg_buf[0], exe_path.ptr, exe_path.len); |
| 228 | arg_buf[path.len] = 0; | 224 | arg_buf[exe_path.len] = 0; |
| 229 | | 225 | |
| 230 | argv_buf[0] = arg_buf.ptr; | 226 | argv_buf[0] = arg_buf.ptr; |
| 231 | } | 227 | } |
| ... | @@ -266,7 +262,58 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B | ... | @@ -266,7 +262,58 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B |
| 266 | } | 262 | } |
| 267 | envp_buf[envp_count] = null; | 263 | envp_buf[envp_count] = null; |
| 268 | | 264 | |
| 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 | }; |
| 270 | } | 317 | } |
| 271 | | 318 | |
| 272 | pub var environ_raw: []&u8 = undefined; | 319 | pub var environ_raw: []&u8 = undefined; |