| ... | @@ -7028,6 +7028,11 @@ fn fileRealPathPosix(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.R | ... | @@ -7028,6 +7028,11 @@ fn fileRealPathPosix(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.R |
| 7028 | } | 7028 | } |
| 7029 | | 7029 | |
| 7030 | fn realPathPosix(fd: posix.fd_t, out_buffer: []u8) File.RealPathError!usize { | 7030 | fn realPathPosix(fd: posix.fd_t, out_buffer: []u8) File.RealPathError!usize { |
| | 7031 | if (fd == posix.AT.FDCWD) return processCurrentPathPosix(out_buffer) catch |err| switch (err) { |
| | 7032 | else => |e| return e, |
| | 7033 | error.CurrentDirUnlinked => return error.FileNotFound, |
| | 7034 | error.PathExceedsLimit => return error.NameTooLong, |
| | 7035 | }; |
| 7031 | switch (native_os) { | 7036 | switch (native_os) { |
| 7032 | .dragonfly, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => { | 7037 | .dragonfly, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => { |
| 7033 | var sufficient_buffer: [posix.PATH_MAX]u8 = undefined; | 7038 | var sufficient_buffer: [posix.PATH_MAX]u8 = undefined; |
| ... | @@ -14143,6 +14148,7 @@ fn unlockStderr(userdata: ?*anyopaque) void { | ... | @@ -14143,6 +14148,7 @@ fn unlockStderr(userdata: ?*anyopaque) void { |
| 14143 | fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathError!usize { | 14148 | fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathError!usize { |
| 14144 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 14149 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 14145 | _ = t; | 14150 | _ = t; |
| | 14151 | |
| 14146 | if (is_windows) { | 14152 | if (is_windows) { |
| 14147 | var wtf16le_buf: [windows.PATH_MAX_WIDE:0]u16 = undefined; | 14153 | var wtf16le_buf: [windows.PATH_MAX_WIDE:0]u16 = undefined; |
| 14148 | const n = windows.ntdll.RtlGetCurrentDirectory_U(wtf16le_buf.len * 2 + 2, &wtf16le_buf) / 2; | 14154 | const n = windows.ntdll.RtlGetCurrentDirectory_U(wtf16le_buf.len * 2 + 2, &wtf16le_buf) / 2; |
| ... | @@ -14158,12 +14164,18 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr | ... | @@ -14158,12 +14164,18 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr |
| 14158 | end_index += std.unicode.wtf8Encode(codepoint, buffer[end_index..]) catch unreachable; | 14164 | end_index += std.unicode.wtf8Encode(codepoint, buffer[end_index..]) catch unreachable; |
| 14159 | } | 14165 | } |
| 14160 | return end_index; | 14166 | return end_index; |
| 14161 | } else if (native_os == .wasi and !builtin.link_libc) { | 14167 | } |
| | 14168 | |
| | 14169 | if (native_os == .wasi and !builtin.link_libc) { |
| 14162 | if (buffer.len == 0) return error.NameTooLong; | 14170 | if (buffer.len == 0) return error.NameTooLong; |
| 14163 | buffer[0] = '.'; | 14171 | buffer[0] = '.'; |
| 14164 | return 1; | 14172 | return 1; |
| 14165 | } | 14173 | } |
| 14166 | | 14174 | |
| | 14175 | return processCurrentPathPosix(buffer); |
| | 14176 | } |
| | 14177 | |
| | 14178 | fn processCurrentPathPosix(buffer: []u8) process.CurrentPathError!usize { |
| 14167 | const err: posix.E = if (builtin.link_libc) err: { | 14179 | const err: posix.E = if (builtin.link_libc) err: { |
| 14168 | const c_err = if (std.c.getcwd(buffer.ptr, buffer.len)) |_| 0 else std.c._errno().*; | 14180 | const c_err = if (std.c.getcwd(buffer.ptr, buffer.len)) |_| 0 else std.c._errno().*; |
| 14169 | break :err @fromBackingInt(@intCast(c_err)); | 14181 | break :err @fromBackingInt(@intCast(c_err)); |
| ... | @@ -15131,12 +15143,54 @@ fn processReplace(userdata: ?*anyopaque, options: process.ReplaceOptions) proces | ... | @@ -15131,12 +15143,54 @@ fn processReplace(userdata: ?*anyopaque, options: process.ReplaceOptions) proces |
| 15131 | }); | 15143 | }); |
| 15132 | }; | 15144 | }; |
| 15133 | | 15145 | |
| | 15146 | if (is_darwin) if (t.spawnDarwin( |
| | 15147 | .replace, |
| | 15148 | options.exe, |
| | 15149 | argv_buf.ptr, |
| | 15150 | options.cwd, |
| | 15151 | env_block, |
| | 15152 | options.expand_arg0, |
| | 15153 | .none, |
| | 15154 | .inherit, |
| | 15155 | .inherit, |
| | 15156 | .inherit, |
| | 15157 | options.inherit_dirs, |
| | 15158 | options.inherit_files, |
| | 15159 | null, |
| | 15160 | options.start_suspended, |
| | 15161 | PATH, |
| | 15162 | )) |_| unreachable else |err| switch (err) { |
| | 15163 | else => |e| return e, |
| | 15164 | error.WouldBlock => return error.SystemResources, |
| | 15165 | error.FileTooBig, |
| | 15166 | error.NoSpaceLeft, |
| | 15167 | error.PathAlreadyExists, |
| | 15168 | error.SymLinkLoop, |
| | 15169 | error.NetworkNotFound, |
| | 15170 | error.PipeBusy, |
| | 15171 | error.AntivirusInterference, |
| | 15172 | => return error.FileNotFound, |
| | 15173 | error.DeviceBusy, |
| | 15174 | error.NoDevice, |
| | 15175 | error.UnrecognizedVolume, |
| | 15176 | error.ReadOnlyFileSystem, |
| | 15177 | => return error.FileSystem, |
| | 15178 | error.ResourceLimitReached => return error.SystemResources, |
| | 15179 | error.FileLocksUnsupported => unreachable, // lock not requested |
| | 15180 | error.InvalidWtf8 => unreachable, // windows only |
| | 15181 | error.InvalidBatchScriptArg => unreachable, // windows only |
| | 15182 | error.InvalidUserId => unreachable, // not supported |
| | 15183 | error.InvalidProcessGroupId => unreachable, // passed null |
| | 15184 | error.InvalidName => unreachable, // windows only |
| | 15185 | error.ProcessAlreadyExec => unreachable, // linux only |
| | 15186 | }; |
| 15134 | return posixExec(options.exe, argv_buf.ptr, options.expand_arg0, env_block, PATH); | 15187 | return posixExec(options.exe, argv_buf.ptr, options.expand_arg0, env_block, PATH); |
| 15135 | } | 15188 | } |
| 15136 | | 15189 | |
| 15137 | const processSpawn = switch (native_os) { | 15190 | const processSpawn = switch (native_os) { |
| 15138 | .wasi, .emscripten, .ios, .tvos, .visionos, .watchos => processSpawnUnsupported, | 15191 | .wasi, .emscripten, .ios, .tvos, .visionos, .watchos => processSpawnUnsupported, |
| 15139 | .windows => processSpawnWindows, | 15192 | .windows => processSpawnWindows, |
| | 15193 | .driverkit, .maccatalyst, .macos => processSpawnDarwin, |
| 15140 | else => processSpawnPosix, | 15194 | else => processSpawnPosix, |
| 15141 | }; | 15195 | }; |
| 15142 | | 15196 | |
| ... | @@ -15743,6 +15797,56 @@ fn destroyPipe(pipe: [2]posix.fd_t) void { | ... | @@ -15743,6 +15797,56 @@ fn destroyPipe(pipe: [2]posix.fd_t) void { |
| 15743 | if (pipe[0] != pipe[1]) closeFd(pipe[1]); | 15797 | if (pipe[0] != pipe[1]) closeFd(pipe[1]); |
| 15744 | } | 15798 | } |
| 15745 | | 15799 | |
| | 15800 | fn processSpawnDarwin(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child { |
| | 15801 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| | 15802 | |
| | 15803 | t.scanEnviron(); // for PATH |
| | 15804 | const PATH = t.environ.string.PATH orelse default_PATH; |
| | 15805 | |
| | 15806 | var arena_allocator = std.heap.ArenaAllocator.init(t.allocator); |
| | 15807 | defer arena_allocator.deinit(); |
| | 15808 | const arena = arena_allocator.allocator(); |
| | 15809 | |
| | 15810 | const argv_buf = try arena.allocSentinel(?[*:0]const u8, options.argv.len, null); |
| | 15811 | for (options.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeSentinel(u8, arg, 0)).ptr; |
| | 15812 | |
| | 15813 | const env_block = env_block: { |
| | 15814 | const prog_fd: i32 = -1; |
| | 15815 | if (options.environ_map) |environ_map| break :env_block try environ_map.createPosixBlock(arena, .{ |
| | 15816 | .zig_progress_fd = prog_fd, |
| | 15817 | }); |
| | 15818 | break :env_block try t.environ.process_environ.createPosixBlock(arena, .{ |
| | 15819 | .zig_progress_fd = prog_fd, |
| | 15820 | }); |
| | 15821 | }; |
| | 15822 | |
| | 15823 | const spawned = try t.spawnDarwin( |
| | 15824 | .spawn, |
| | 15825 | options.exe, |
| | 15826 | argv_buf.ptr, |
| | 15827 | options.cwd, |
| | 15828 | env_block, |
| | 15829 | options.expand_arg0, |
| | 15830 | options.progress_node, |
| | 15831 | options.stdin, |
| | 15832 | options.stdout, |
| | 15833 | options.stderr, |
| | 15834 | options.inherit_dirs, |
| | 15835 | options.inherit_files, |
| | 15836 | options.pgid, |
| | 15837 | options.start_suspended, |
| | 15838 | PATH, |
| | 15839 | ); |
| | 15840 | return .{ |
| | 15841 | .id = spawned.pid, |
| | 15842 | .thread_handle = {}, |
| | 15843 | .stdin = spawned.stdin, |
| | 15844 | .stdout = spawned.stdout, |
| | 15845 | .stderr = spawned.stderr, |
| | 15846 | .request_resource_usage_statistics = options.request_resource_usage_statistics, |
| | 15847 | }; |
| | 15848 | } |
| | 15849 | |
| 15746 | fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child { | 15850 | fn processSpawnWindows(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child { |
| 15747 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 15851 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 15748 | | 15852 | |
| ... | @@ -17037,6 +17141,7 @@ fn posixExec( | ... | @@ -17037,6 +17141,7 @@ fn posixExec( |
| 17037 | .path = .cwd(), | 17141 | .path = .cwd(), |
| 17038 | } else .search, | 17142 | } else .search, |
| 17039 | .search => { | 17143 | .search => { |
| | 17144 | if (Dir.path.isAbsolute(arg0_slice)) continue :exe .{ .path = .cwd() }; |
| 17040 | // Use of PATH_MAX here is valid as the path_buf will be passed | 17145 | // Use of PATH_MAX here is valid as the path_buf will be passed |
| 17041 | // directly to the operating system in posixExecveat. | 17146 | // directly to the operating system in posixExecveat. |
| 17042 | var path_buf: [posix.PATH_MAX]u8 = undefined; | 17147 | var path_buf: [posix.PATH_MAX]u8 = undefined; |
| ... | @@ -17047,7 +17152,7 @@ fn posixExec( | ... | @@ -17047,7 +17152,7 @@ fn posixExec( |
| 17047 | const path_len = search_path.len + arg0_slice.len + 1; | 17152 | const path_len = search_path.len + arg0_slice.len + 1; |
| 17048 | if (path_buf.len < path_len + 1) return error.NameTooLong; | 17153 | if (path_buf.len < path_len + 1) return error.NameTooLong; |
| 17049 | @memcpy(path_buf[0..search_path.len], search_path); | 17154 | @memcpy(path_buf[0..search_path.len], search_path); |
| 17050 | path_buf[search_path.len] = '/'; | 17155 | path_buf[search_path.len] = Dir.path.sep; |
| 17051 | @memcpy(path_buf[search_path.len + 1 ..][0..arg0_slice.len], arg0_slice); | 17156 | @memcpy(path_buf[search_path.len + 1 ..][0..arg0_slice.len], arg0_slice); |
| 17052 | path_buf[path_len] = 0; | 17157 | path_buf[path_len] = 0; |
| 17053 | const full_path = path_buf[0..path_len :0].ptr; | 17158 | const full_path = path_buf[0..path_len :0].ptr; |
| ... | @@ -17065,7 +17170,7 @@ fn posixExec( | ... | @@ -17065,7 +17170,7 @@ fn posixExec( |
| 17065 | } | 17170 | } |
| 17066 | return err; | 17171 | return err; |
| 17067 | }, | 17172 | }, |
| 17068 | .path => |path| return posixExecveat(path.handle, argv[0], argv, env_block), | 17173 | .path => |path| return posixExecveat(path.handle, arg0_slice, argv, env_block), |
| 17069 | .file => |file| return posixExecveat(file.handle, null, argv, env_block), | 17174 | .file => |file| return posixExecveat(file.handle, null, argv, env_block), |
| 17070 | .explicit => |explicit| { | 17175 | .explicit => |explicit| { |
| 17071 | var path_buffer: [posix.PATH_MAX]u8 = undefined; | 17176 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| ... | @@ -17100,7 +17205,7 @@ pub fn posixExecveat( | ... | @@ -17100,7 +17205,7 @@ pub fn posixExecveat( |
| 17100 | .NOSYS => {}, | 17205 | .NOSYS => {}, |
| 17101 | } | 17206 | } |
| 17102 | } | 17207 | } |
| 17103 | var path_buffer: [posix.PATH_MAX:0]u8 = undefined; | 17208 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 17104 | var path_len = realPathPosix(dir, &path_buffer) catch |err| switch (err) { | 17209 | var path_len = realPathPosix(dir, &path_buffer) catch |err| switch (err) { |
| 17105 | else => |e| return e, | 17210 | else => |e| return e, |
| 17106 | error.InputOutput, | 17211 | error.InputOutput, |
| ... | @@ -17125,7 +17230,9 @@ pub fn posixExecveat( | ... | @@ -17125,7 +17230,9 @@ pub fn posixExecveat( |
| 17125 | path_len += path_slice.len; | 17230 | path_len += path_slice.len; |
| 17126 | } | 17231 | } |
| 17127 | path_buffer[path_len] = 0; | 17232 | path_buffer[path_len] = 0; |
| 17128 | break :err posix.errno(posix.system.execve(&path_buffer, argv, env_block.slice.ptr)); | 17233 | break :err posix.errno( |
| | 17234 | posix.system.execve(path_buffer[0..path_len :0], argv, env_block.slice.ptr), |
| | 17235 | ); |
| 17129 | }) { | 17236 | }) { |
| 17130 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. | 17237 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. |
| 17131 | .@"2BIG" => return error.SystemResources, | 17238 | .@"2BIG" => return error.SystemResources, |
| ... | @@ -17158,6 +17265,334 @@ pub fn posixExecveat( | ... | @@ -17158,6 +17265,334 @@ pub fn posixExecveat( |
| 17158 | } | 17265 | } |
| 17159 | } | 17266 | } |
| 17160 | | 17267 | |
| | 17268 | fn spawnDarwin( |
| | 17269 | t: *Threaded, |
| | 17270 | mode: enum { spawn, replace }, |
| | 17271 | exe: process.ReplaceOptions.Exe, |
| | 17272 | argv: [*:null]?[*:0]const u8, |
| | 17273 | cwd: process.Child.Cwd, |
| | 17274 | env_block: process.Environ.PosixBlock, |
| | 17275 | expand_arg0: process.ArgExpansion, |
| | 17276 | progress_node: std.Progress.Node, |
| | 17277 | stdin: process.SpawnOptions.StdIo, |
| | 17278 | stdout: process.SpawnOptions.StdIo, |
| | 17279 | stderr: process.SpawnOptions.StdIo, |
| | 17280 | inherit_dirs: []const Dir, |
| | 17281 | inherit_files: []const File, |
| | 17282 | pgid: ?posix.pid_t, |
| | 17283 | start_suspended: bool, |
| | 17284 | PATH: []const u8, |
| | 17285 | ) (process.SpawnError || process.ReplaceError)!Spawned { |
| | 17286 | var fa: std.c.posix_spawn_file_actions_t = undefined; |
| | 17287 | switch (@as(std.c.E, @fromBackingInt(@intCast(std.c.posix_spawn_file_actions_init(&fa))))) { |
| | 17288 | .SUCCESS => {}, |
| | 17289 | .NOMEM => return error.SystemResources, |
| | 17290 | else => |err| return posix.unexpectedErrno(err), |
| | 17291 | } |
| | 17292 | defer switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17293 | std.c.posix_spawn_file_actions_destroy(&fa), |
| | 17294 | )))) { |
| | 17295 | .SUCCESS => {}, |
| | 17296 | .INVAL => recoverableOsBugDetected(), |
| | 17297 | else => recoverableOsBugDetected(), |
| | 17298 | }; |
| | 17299 | |
| | 17300 | var attr: std.c.posix_spawnattr_t = undefined; |
| | 17301 | switch (@as(std.c.E, @fromBackingInt(@intCast(std.c.posix_spawnattr_init(&attr))))) { |
| | 17302 | .SUCCESS => {}, |
| | 17303 | .NOMEM => return error.SystemResources, |
| | 17304 | else => |err| return posix.unexpectedErrno(err), |
| | 17305 | } |
| | 17306 | defer switch (@as(std.c.E, @fromBackingInt(@intCast(std.c.posix_spawnattr_destroy(&attr))))) { |
| | 17307 | .SUCCESS => {}, |
| | 17308 | .INVAL => recoverableOsBugDetected(), |
| | 17309 | else => recoverableOsBugDetected(), |
| | 17310 | }; |
| | 17311 | |
| | 17312 | // The child process does need to access (one end of) these pipes. However, |
| | 17313 | // we must initially set CLOEXEC to avoid a race condition. If another thread |
| | 17314 | // is racing to spawn a different child process, we don't want it to inherit |
| | 17315 | // these FDs in any scenario; that would mean that, for instance, calls to |
| | 17316 | // `poll` from the parent would not report the child's stdout as closing when |
| | 17317 | // expected, since the other child may retain a reference to the write end of |
| | 17318 | // the pipe. So, we create the pipes with CLOEXEC initially. After fork, we |
| | 17319 | // need to do something in the new child to make sure we preserve the reference |
| | 17320 | // we want. We could use `fcntl` to remove CLOEXEC from the FD, but as it |
| | 17321 | // turns out, we `dup2` everything anyway, so there's no need! |
| | 17322 | const pipe_flags: posix.O = .{ .CLOEXEC = true }; |
| | 17323 | |
| | 17324 | const stdin_pipe = if (stdin == .pipe) try pipe2(pipe_flags) else undefined; |
| | 17325 | errdefer if (stdin == .pipe) { |
| | 17326 | destroyPipe(stdin_pipe); |
| | 17327 | }; |
| | 17328 | |
| | 17329 | const stdout_pipe = if (stdout == .pipe) try pipe2(pipe_flags) else undefined; |
| | 17330 | errdefer if (stdout == .pipe) { |
| | 17331 | destroyPipe(stdout_pipe); |
| | 17332 | }; |
| | 17333 | |
| | 17334 | const stderr_pipe = if (stderr == .pipe) try pipe2(pipe_flags) else undefined; |
| | 17335 | errdefer if (stderr == .pipe) { |
| | 17336 | destroyPipe(stderr_pipe); |
| | 17337 | }; |
| | 17338 | |
| | 17339 | const any_ignore = (stdin == .ignore or stdout == .ignore or stderr == .ignore); |
| | 17340 | const dev_null_fd = if (any_ignore) try t.getDevNullFd() else undefined; |
| | 17341 | |
| | 17342 | const prog_pipe: [2]posix.fd_t = if (progress_node.index != .none) pipe: { |
| | 17343 | // We use CLOEXEC for the same reason as in `pipe_flags`. |
| | 17344 | break :pipe try pipe2(.{ .NONBLOCK = true, .CLOEXEC = true }); |
| | 17345 | } else .{ -1, -1 }; |
| | 17346 | errdefer destroyPipe(prog_pipe); |
| | 17347 | |
| | 17348 | var cwd_buffer: [posix.PATH_MAX]u8 = undefined; |
| | 17349 | switch (cwd) { |
| | 17350 | .inherit => {}, |
| | 17351 | .dir => |dir| switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17352 | std.c.posix_spawn_file_actions_addfchdir_np(&fa, dir.handle), |
| | 17353 | )))) { |
| | 17354 | .SUCCESS => {}, |
| | 17355 | .BADF => |err| return errnoBug(err), |
| | 17356 | .INVAL => |err| return errnoBug(err), |
| | 17357 | .NOMEM => return error.SystemResources, |
| | 17358 | else => |err| return posix.unexpectedErrno(err), |
| | 17359 | }, |
| | 17360 | .path => |path| switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17361 | std.c.posix_spawn_file_actions_addchdir_np(&fa, try pathToPosix(path, &cwd_buffer)), |
| | 17362 | )))) { |
| | 17363 | .SUCCESS => {}, |
| | 17364 | .BADF => |err| return errnoBug(err), |
| | 17365 | .INVAL => |err| return errnoBug(err), |
| | 17366 | .NAMETOOLONG => return error.NameTooLong, |
| | 17367 | .NOMEM => return error.SystemResources, |
| | 17368 | else => |err| return posix.unexpectedErrno(err), |
| | 17369 | }, |
| | 17370 | } |
| | 17371 | |
| | 17372 | for (inherit_dirs) |inherit_dir| switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17373 | std.c.posix_spawn_file_actions_addinherit_np(&fa, inherit_dir.handle), |
| | 17374 | )))) { |
| | 17375 | .SUCCESS => {}, |
| | 17376 | .BADF => |err| return errnoBug(err), |
| | 17377 | .INVAL => |err| return errnoBug(err), |
| | 17378 | .NOMEM => return error.SystemResources, |
| | 17379 | else => |err| return posix.unexpectedErrno(err), |
| | 17380 | }; |
| | 17381 | for (inherit_files) |inherit_file| switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17382 | std.c.posix_spawn_file_actions_addinherit_np(&fa, inherit_file.handle), |
| | 17383 | )))) { |
| | 17384 | .SUCCESS => {}, |
| | 17385 | .BADF => |err| return errnoBug(err), |
| | 17386 | .INVAL => |err| return errnoBug(err), |
| | 17387 | .NOMEM => return error.SystemResources, |
| | 17388 | else => |err| return posix.unexpectedErrno(err), |
| | 17389 | }; |
| | 17390 | if (prog_pipe[1] != -1) switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17391 | std.c.posix_spawn_file_actions_addinherit_np(&fa, prog_pipe[1]), |
| | 17392 | )))) { |
| | 17393 | .SUCCESS => {}, |
| | 17394 | .BADF => |err| return errnoBug(err), |
| | 17395 | .INVAL => |err| return errnoBug(err), |
| | 17396 | .NOMEM => return error.SystemResources, |
| | 17397 | else => |err| return posix.unexpectedErrno(err), |
| | 17398 | }; |
| | 17399 | for ( |
| | 17400 | [_]process.SpawnOptions.StdIo{ stdin, stdout, stderr }, |
| | 17401 | [_]posix.fd_t{ stdin_pipe[0], stdout_pipe[1], stderr_pipe[1] }, |
| | 17402 | [_]posix.fd_t{ posix.STDIN_FILENO, posix.STDOUT_FILENO, posix.STDERR_FILENO }, |
| | 17403 | ) |stdio, pipe_fd, std_fd| switch (@as(std.c.E, @fromBackingInt(@intCast(switch (stdio) { |
| | 17404 | .pipe => std.c.posix_spawn_file_actions_adddup2(&fa, pipe_fd, std_fd), |
| | 17405 | .close => std.c.posix_spawn_file_actions_addclose(&fa, std_fd), |
| | 17406 | .inherit => std.c.posix_spawn_file_actions_addinherit_np(&fa, std_fd), |
| | 17407 | .ignore => std.c.posix_spawn_file_actions_adddup2(&fa, dev_null_fd, std_fd), |
| | 17408 | .file => |file| std.c.posix_spawn_file_actions_adddup2(&fa, file.handle, std_fd), |
| | 17409 | })))) { |
| | 17410 | .SUCCESS => {}, |
| | 17411 | .BADF => |err| return errnoBug(err), |
| | 17412 | .INVAL => |err| return errnoBug(err), |
| | 17413 | .NOMEM => return error.SystemResources, |
| | 17414 | else => |err| return posix.unexpectedErrno(err), |
| | 17415 | }; |
| | 17416 | |
| | 17417 | if (pgid) |pid| switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17418 | std.c.posix_spawnattr_setpgroup(&attr, pid), |
| | 17419 | )))) { |
| | 17420 | .SUCCESS => {}, |
| | 17421 | .INVAL => return error.InvalidProcessGroupId, |
| | 17422 | else => |err| return posix.unexpectedErrno(err), |
| | 17423 | }; |
| | 17424 | |
| | 17425 | switch (@as(std.c.E, @fromBackingInt(@intCast(std.c.posix_spawnattr_setflags(&attr, .{ |
| | 17426 | .SETPGROUP = pgid != null, |
| | 17427 | .SETEXEC = switch (mode) { |
| | 17428 | .spawn => false, |
| | 17429 | .replace => true, |
| | 17430 | }, |
| | 17431 | .START_SUSPENDED = start_suspended, |
| | 17432 | }))))) { |
| | 17433 | .SUCCESS => {}, |
| | 17434 | .INVAL => |err| return errnoBug(err), |
| | 17435 | else => |err| return posix.unexpectedErrno(err), |
| | 17436 | } |
| | 17437 | |
| | 17438 | var pid: posix.pid_t = undefined; |
| | 17439 | const arg0_slice = std.mem.span(argv[0].?); |
| | 17440 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| | 17441 | switch (err: { |
| | 17442 | break :err @as(std.c.E, @fromBackingInt(@intCast(exe: switch (exe) { |
| | 17443 | .detect => if (std.mem.findScalar(u8, arg0_slice, '/')) |_| |
| | 17444 | std.c.posix_spawn(&pid, arg0_slice, &fa, &attr, argv, env_block.slice.ptr) |
| | 17445 | else |
| | 17446 | continue :exe .search, |
| | 17447 | .search => if (!Dir.path.isAbsolute(arg0_slice)) { |
| | 17448 | // Use of PATH_MAX here is valid as the path_buf will be passed |
| | 17449 | // directly to the operating system in posixExecveat. |
| | 17450 | var path_buf: [posix.PATH_MAX]u8 = undefined; |
| | 17451 | var it = std.mem.tokenizeScalar(u8, PATH, ':'); |
| | 17452 | var err: error{ AccessDenied, FileNotFound, NotDir } = error.FileNotFound; |
| | 17453 | |
| | 17454 | while (it.next()) |search_path| { |
| | 17455 | const path_len = search_path.len + arg0_slice.len + 1; |
| | 17456 | if (path_buf.len < path_len + 1) return error.NameTooLong; |
| | 17457 | @memcpy(path_buf[0..search_path.len], search_path); |
| | 17458 | path_buf[search_path.len] = Dir.path.sep; |
| | 17459 | @memcpy(path_buf[search_path.len + 1 ..][0..arg0_slice.len], arg0_slice); |
| | 17460 | path_buf[path_len] = 0; |
| | 17461 | const full_path = path_buf[0..path_len :0].ptr; |
| | 17462 | switch (expand_arg0) { |
| | 17463 | .expand => argv[0] = full_path, |
| | 17464 | .no_expand => {}, |
| | 17465 | } |
| | 17466 | switch (@as(std.c.E, @fromBackingInt(@intCast( |
| | 17467 | std.c.posix_spawn(&pid, full_path, &fa, &attr, argv, env_block.slice.ptr), |
| | 17468 | )))) { |
| | 17469 | else => |e| break :err e, |
| | 17470 | .ACCES, .NOENT, .NOTDIR => |e| switch (err) { |
| | 17471 | error.AccessDenied => {}, |
| | 17472 | error.FileNotFound, error.NotDir => err = switch (e) { |
| | 17473 | else => unreachable, |
| | 17474 | .ACCES => error.AccessDenied, |
| | 17475 | .NOENT => error.FileNotFound, |
| | 17476 | .NOTDIR => error.NotDir, |
| | 17477 | }, |
| | 17478 | }, |
| | 17479 | } |
| | 17480 | } |
| | 17481 | return err; |
| | 17482 | } else std.c.posix_spawn(&pid, arg0_slice, &fa, &attr, argv, env_block.slice.ptr), |
| | 17483 | .path => |path| if (path.handle != posix.AT.FDCWD and !Dir.path.isAbsolute(arg0_slice)) { |
| | 17484 | var path_len = realPathPosix(path.handle, &path_buffer) catch |err| switch (err) { |
| | 17485 | else => |e| return e, |
| | 17486 | error.InputOutput => return error.FileNotFound, |
| | 17487 | }; |
| | 17488 | path_buffer[path_len] = Dir.path.sep; |
| | 17489 | path_len += 1; |
| | 17490 | @memcpy(path_buffer[path_len..][0..arg0_slice.len], arg0_slice); |
| | 17491 | path_len += arg0_slice.len; |
| | 17492 | path_buffer[path_len] = 0; |
| | 17493 | break :exe std.c.posix_spawn( |
| | 17494 | &pid, |
| | 17495 | path_buffer[0..path_len :0], |
| | 17496 | &fa, |
| | 17497 | &attr, |
| | 17498 | argv, |
| | 17499 | env_block.slice.ptr, |
| | 17500 | ); |
| | 17501 | } else std.c.posix_spawn(&pid, arg0_slice, &fa, &attr, argv, env_block.slice.ptr), |
| | 17502 | .file => |file| { |
| | 17503 | const path_len = realPathPosix(file.handle, &path_buffer) catch |err| switch (err) { |
| | 17504 | else => |e| return e, |
| | 17505 | error.InputOutput => return error.FileNotFound, |
| | 17506 | }; |
| | 17507 | path_buffer[path_len] = 0; |
| | 17508 | break :exe std.c.posix_spawn( |
| | 17509 | &pid, |
| | 17510 | path_buffer[0..path_len :0], |
| | 17511 | &fa, |
| | 17512 | &attr, |
| | 17513 | argv, |
| | 17514 | env_block.slice.ptr, |
| | 17515 | ); |
| | 17516 | }, |
| | 17517 | .explicit => |explicit| if (explicit.dir.handle != posix.AT.FDCWD and |
| | 17518 | !Dir.path.isAbsolute(explicit.path)) |
| | 17519 | { |
| | 17520 | var path_len = realPathPosix( |
| | 17521 | explicit.dir.handle, |
| | 17522 | &path_buffer, |
| | 17523 | ) catch |err| switch (err) { |
| | 17524 | else => |e| return e, |
| | 17525 | error.InputOutput => return error.FileNotFound, |
| | 17526 | }; |
| | 17527 | path_buffer[path_len] = Dir.path.sep; |
| | 17528 | path_len += 1; |
| | 17529 | @memcpy(path_buffer[path_len..][0..explicit.path.len], explicit.path); |
| | 17530 | path_len += explicit.path.len; |
| | 17531 | path_buffer[path_len] = 0; |
| | 17532 | break :exe std.c.posix_spawn( |
| | 17533 | &pid, |
| | 17534 | path_buffer[0..path_len :0], |
| | 17535 | &fa, |
| | 17536 | &attr, |
| | 17537 | argv, |
| | 17538 | env_block.slice.ptr, |
| | 17539 | ); |
| | 17540 | } else std.c.posix_spawn( |
| | 17541 | &pid, |
| | 17542 | try pathToPosix(explicit.path, &path_buffer), |
| | 17543 | &fa, |
| | 17544 | &attr, |
| | 17545 | argv, |
| | 17546 | env_block.slice.ptr, |
| | 17547 | ), |
| | 17548 | }))); |
| | 17549 | }) { |
| | 17550 | .SUCCESS => {}, |
| | 17551 | .AGAIN => return error.SystemResources, |
| | 17552 | .INVAL => |err| return errnoBug(err), |
| | 17553 | .@"2BIG" => return error.SystemResources, |
| | 17554 | .ACCES => return error.AccessDenied, |
| | 17555 | .FAULT => |err| return errnoBug(err), |
| | 17556 | .IO => return error.FileSystem, |
| | 17557 | .LOOP => return error.FileSystem, |
| | 17558 | .NAMETOOLONG => return error.NameTooLong, |
| | 17559 | .NOENT => return error.FileNotFound, |
| | 17560 | .NOEXEC => return error.InvalidExe, |
| | 17561 | .NOMEM => return error.SystemResources, |
| | 17562 | .NOTDIR => return error.NotDir, |
| | 17563 | .TXTBSY => return error.FileBusy, |
| | 17564 | .BADARCH => return error.InvalidExe, |
| | 17565 | .BADF => |err| return errnoBug(err), |
| | 17566 | else => |err| return posix.unexpectedErrno(err), |
| | 17567 | } |
| | 17568 | |
| | 17569 | errdefer comptime unreachable; // The child is spawned; we must not error from now on |
| | 17570 | |
| | 17571 | if (stdin == .pipe) closeFd(stdin_pipe[0]); |
| | 17572 | if (stdout == .pipe) closeFd(stdout_pipe[1]); |
| | 17573 | if (stderr == .pipe) closeFd(stderr_pipe[1]); |
| | 17574 | |
| | 17575 | if (prog_pipe[1] != -1) closeFd(prog_pipe[1]); |
| | 17576 | progress_node.setIpcFile(t, .{ .handle = prog_pipe[0], .flags = .{ .nonblocking = true } }); |
| | 17577 | |
| | 17578 | return .{ |
| | 17579 | .pid = pid, |
| | 17580 | .err_fd = -1, |
| | 17581 | .stdin = switch (stdin) { |
| | 17582 | .pipe => .{ .handle = stdin_pipe[1], .flags = .{ .nonblocking = false } }, |
| | 17583 | else => null, |
| | 17584 | }, |
| | 17585 | .stdout = switch (stdout) { |
| | 17586 | .pipe => .{ .handle = stdout_pipe[0], .flags = .{ .nonblocking = false } }, |
| | 17587 | else => null, |
| | 17588 | }, |
| | 17589 | .stderr = switch (stderr) { |
| | 17590 | .pipe => .{ .handle = stderr_pipe[0], .flags = .{ .nonblocking = false } }, |
| | 17591 | else => null, |
| | 17592 | }, |
| | 17593 | }; |
| | 17594 | } |
| | 17595 | |
| 17161 | pub const CreatePipeOptions = struct { | 17596 | pub const CreatePipeOptions = struct { |
| 17162 | server: End, | 17597 | server: End, |
| 17163 | client: End, | 17598 | client: End, |
| ... | @@ -18469,7 +18904,7 @@ const CreateFileMapError = error{ | ... | @@ -18469,7 +18904,7 @@ const CreateFileMapError = error{ |
| 18469 | | 18904 | |
| 18470 | fn createFileMap( | 18905 | fn createFileMap( |
| 18471 | file: File, | 18906 | file: File, |
| 18472 | protection: std.process.MemoryProtection, | 18907 | protection: process.MemoryProtection, |
| 18473 | offset: u64, | 18908 | offset: u64, |
| 18474 | populate: bool, | 18909 | populate: bool, |
| 18475 | len: usize, | 18910 | len: usize, |