diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 11:26:42 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:16 -0300 |
| commit | 0e6501ce210481c095e6f70a27e7f125f7af3761 (patch) | |
| tree | 0abf4b55e8eb4f836a3ad10963cbefd94efb8599 /src/detached/server.zig | |
| parent | 1ac8fbeedaf7cba881a7423b92ead1f739b8ac21 (diff) | |
| download | pardes-0e6501ce210481c095e6f70a27e7f125f7af3761.tar.gz pardes-0e6501ce210481c095e6f70a27e7f125f7af3761.zip | |
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 <[email protected]>
Diffstat (limited to 'src/detached/server.zig')
| -rw-r--r-- | src/detached/server.zig | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/src/detached/server.zig b/src/detached/server.zig index a08a0342..676b5b95 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -485,9 +485,11 @@ pub const Session = struct { fn spawn(ctx: ?*anyopaque, pane: u8, cwd: []const u8) void { const s = of(ctx); if (pane >= s.ptys.len) return; // the core indexes its own panes - s.closePty(pane); s.harvest(); - if (s.ptys[pane].pid != 0) return s.core.reportError(pane, "shell", error.ShellClosing); + // 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].fd >= 0; + if (!running and s.ptys[pane].pid != 0) return s.core.reportError(pane, "shell", error.ShellClosing); for (s.retired_shells) |shell| { if (shell.pid == 0) break; } else return s.core.reportError(pane, "shell", error.ShellClosing); @@ -500,7 +502,17 @@ pub const Session = struct { s.core.screen_h, s.core.screen_w, s.ninep, - ) catch |err| return s.core.shellFailed(pane, err); + ) catch |err| { + if (running) return s.core.restartFailed(pane, err); + return s.core.shellFailed(pane, err); + }; + s.closePty(pane); + s.harvest(); + if (s.ptys[pane].pid != 0) { + _ = libc.close(child.file.handle); + host_io.retireShell(child.pid); + return s.core.reportError(pane, "shell", error.ShellClosing); + } const command = if (s.core.panes[pane]) |pn| pn.command != null else false; s.ptys[pane] = .{ .fd = child.file.handle, .pid = child.pid, .cmd = .{ .watched = command and host_io.watchExit(child.pid), .fd = child.file.handle } }; setNonblock(child.file.handle); |
