diff --git a/src/Command.zig b/src/Command.zig index 8406bc5b3..ec363e770 100644 --- a/src/Command.zig +++ b/src/Command.zig @@ -189,7 +189,7 @@ fn startPosix(self: *Command, arena: Allocator) !void { @compileError("missing env vars"); // Fork. - const pid = posix.system.fork(); + const pid = try fork(); if (pid != 0) { // Parent, return immediately. @@ -291,6 +291,17 @@ fn startPosix(self: *Command, arena: Allocator) !void { return error.ExecFailedInChild; } +/// Wrapper for the raw fork syscall. This preserves the error handling from +/// the std.posix wrapper that was removed in Zig 0.16. +fn fork() !posix.pid_t { + const rc = posix.system.fork(); + switch (posix.errno(rc)) { + .SUCCESS => return @intCast(rc), + .AGAIN, .NOMEM => return error.SystemResources, + else => |err| return posix.unexpectedErrno(err), + } +} + fn startWindows(self: *Command, arena: Allocator) !void { const cwd_w = if (self.cwd) |cwd| try std.unicode.utf8ToUtf16LeAllocZ(arena, cwd) else null; @@ -494,10 +505,10 @@ pub fn wait(self: Command, block: bool) !Exit { return .{ .Exited = exit_code }; } - const status = if (block) wait_block: { - var status: c_int = undefined; - _ = posix.system.waitpid(self.pid.?, &status, 0); - break :wait_block status; + const status: u32 = if (block) wait_block: { + var status: if (builtin.link_libc) c_int else u32 = undefined; + _ = try waitPid(self.pid.?, &status, 0); + break :wait_block @bitCast(status); } else wait_nohang: { // We specify NOHANG because its not our fault if the process we launch // for the tty doesn't properly waitpid its children. We don't want @@ -507,13 +518,32 @@ pub fn wait(self: Command, block: bool) !Exit { // wait call has not been performed, so we need to keep trying until we get // a non-zero pid back, otherwise we end up with zombie processes. while (true) { - var status: c_int = undefined; - const pid = posix.system.waitpid(self.pid.?, &status, posix.system.W.NOHANG); - if (pid != 0) break :wait_nohang status; + var status: if (builtin.link_libc) c_int else u32 = undefined; + const pid = try waitPid(self.pid.?, &status, posix.system.W.NOHANG); + if (pid != 0) break :wait_nohang @bitCast(status); } }; - return .init(@bitCast(status)); + return .init(status); +} + +/// Wrapper for the raw waitpid syscall. Status is only initialized on success; +/// interrupted waits are retried and all other errors are propagated. +fn waitPid( + pid: posix.pid_t, + status: *if (builtin.link_libc) c_int else u32, + flags: u32, +) !posix.pid_t { + while (true) { + const rc = posix.system.waitpid(pid, status, @intCast(flags)); + switch (posix.errno(rc)) { + .SUCCESS => return @intCast(rc), + .INTR => continue, + .CHILD => return error.NoChildProcess, + .INVAL => return error.InvalidWaitOptions, + else => |err| return posix.unexpectedErrno(err), + } + } } /// Sets command->data to data. diff --git a/src/cli/edit_config.zig b/src/cli/edit_config.zig index ccddc561d..9662ea444 100644 --- a/src/cli/edit_config.zig +++ b/src/cli/edit_config.zig @@ -158,9 +158,13 @@ fn runInner(alloc: Allocator, stderr: *std.Io.Writer) !u8 { defer alloc.free(command); // Run/replace process (using execve) - const argv = &.{ "/bin/sh", "-c", command }; + const argv = [_:null]?[*:0]const u8{ + "/bin/sh", + "-c", + command.ptr, + }; const envp = std.c.environ; - const err = std.posix.errno(std.posix.system.execve(argv[0], @ptrCast(argv), envp)); + const err = std.posix.errno(std.posix.system.execve(argv[0].?, &argv, envp)); // If we reached this point then exec failed. try stderr.print( diff --git a/src/global.zig b/src/global.zig index e69b3042d..3c2ddbb72 100644 --- a/src/global.zig +++ b/src/global.zig @@ -121,7 +121,6 @@ pub fn init(opts: InitOpts) !void { // Discover and save the temporary directory path self.tmp_dir_path = try allocTmpDir(self.alloc, self.environ); - errdefer freeTmpDir(self.alloc, self.tmp_dir_path.?); // We first try to parse any action that we may be executing. // Tool binaries (ghostty-bench, ghostty-gen) have their own action diff --git a/src/main_ghostty.zig b/src/main_ghostty.zig index b83505f47..cd2ef0c17 100644 --- a/src/main_ghostty.zig +++ b/src/main_ghostty.zig @@ -30,7 +30,10 @@ pub fn main(minimal: std.process.Init.Minimal) !MainReturn { // no other Zig code should EVER access the global state. global.init(.{ .main = minimal }) catch |err| { var buffer: [1024]u8 = undefined; - var stderr_writer = std.Io.File.stderr().writer(global.io(), &buffer); + var stderr_writer = std.Io.File.stderr().writer( + std.Io.Threaded.global_single_threaded.io(), + &buffer, + ); const stderr = &stderr_writer.interface; defer std.process.exit(1); const ErrSet = @TypeOf(err) || error{Unknown};