From 0e6501ce210481c095e6f70a27e7f125f7af3761 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 11:26:42 -0300 Subject: A pty/ctl exec that cannot start its shell keeps the one running Each host closed the running shell before it forked the new one, so an exec whose shell failed left the pane with none and later runs answered error shell gone. A shell not there is now refused up front, and every host starts the new shell first, replacing the old only once the close-on-exec pipe says it ran; a failure there is only said (restartFailed). Co-Authored-By: Claude Opus 5.5 --- src/gui/gui.zig | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/gui/gui.zig') diff --git a/src/gui/gui.zig b/src/gui/gui.zig index cb3bdd97..851218bb 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -4553,10 +4553,20 @@ fn gridPostPresent(ctx: ?*anyopaque) void { fn spawnPane(ctx: ?*anyopaque, pane: u8, cwd: []const u8) void { const s = shellOf(ctx); s.reap(); + // The new shell starts before a running one goes: one that cannot + // start leaves the running one be (pty/ctl's exec). + const running = s.ptys[pane] != null; + const child = host_io.forkShell(s.core, pane, s.prompt_rcs, s.core.shellBin(), cwd, s.core.screen_h, s.core.screen_w, s.fs) catch |err| { + if (running) return s.core.restartFailed(pane, err); + return s.core.shellFailed(pane, err); + }; s.closePty(pane); - if (s.ptys[pane] != null) return s.core.reportError(pane, "shell", error.WorkersBusy); + if (s.ptys[pane] != null) { + _ = libc.close(child.file.handle); + host_io.retireShell(child.pid); + return s.core.reportError(pane, "shell", error.WorkersBusy); + } s.gens[pane] +%= 1; - const child = host_io.forkShell(s.core, pane, s.prompt_rcs, s.core.shellBin(), cwd, s.core.screen_h, s.core.screen_w, s.fs) catch |err| return s.core.shellFailed(pane, err); const command = s.core.panes[pane].?.command != null; const pt: Pty = .{ .fd = child.file.handle, .pid = child.pid, .serial = s.core.panes[pane].?.serial, .cmd = .{ .watched = command and host_io.watchExit(child.pid), .fd = child.file.handle } }; s.ptys[pane] = pt; -- cgit v1.3