diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 08:02:47 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:16 -0300 |
| commit | 0ec8d0dc6217486446f2fe2156dff136173a4ef5 (patch) | |
| tree | 8e20f9f0fec47f614492d31c7f03a03e3ac1d0c5 /src/exec.zig | |
| parent | ba0a0f82be43dde325012b3018b186bc808bdafc (diff) | |
| download | pardes-0ec8d0dc6217486446f2fe2156dff136173a4ef5.tar.gz pardes-0ec8d0dc6217486446f2fe2156dff136173a4ef5.zip | |
Tty in a missing directory fails and makes no pane; a shell that never started answers runs
The host could not start the shell (its chdir failed), and the pane stayed
with no pty: a run written to it waited for a prompt for ever. Tty now
refuses a directory that is not there, `Tty: <dir>: no such directory`,
before making a pane; and a terminal whose shell the host could not start
(Pardes.shellFailed, from each host's spawn) answers any run with
`error shell gone`.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/exec.zig')
| -rw-r--r-- | src/exec.zig | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/src/exec.zig b/src/exec.zig index 0bce67d2..6e437093 100644 --- a/src/exec.zig +++ b/src/exec.zig @@ -341,11 +341,20 @@ pub fn spawnV9fsTty(p: *Pardes, from: usize) void { fn spawnTtyWithMount(p: *Pardes, from: usize, v9fs: bool) ?*Pane { if (p.panes[from] == null) return null; + // A directory that is not there makes no terminal: its shell could not + // start in it, and a dead pane would answer no run. Asked only of a host + // that starts shells (none, as in the core's tests, starts none). + const dir = p.execDir(from); + if (comptime hosted) if (p.host.vtable.spawn != null) if (@import("fs.zig").localPath(dir)) |local| if (!isDirectory(local)) { + var said: [pardes.memory.limits.host_path_cap + 48]u8 = undefined; + p.reportFailure(from, std.fmt.bufPrint(&said, "Tty: {s}: no such directory", .{dir}) catch "Tty: no such directory"); + return null; + }; const free = p.freeSlot() orelse { p.reportError(from, "Tty", error.NoPaneSlots); return null; }; - const nt = p.newShell(free, p.execDir(from)) catch |err| { + const nt = p.newShell(free, dir) catch |err| { if (err == error.PathTooLong) { p.reportFailure(from, std.fmt.comptimePrint("Tty: its directory is longer than a path may be ({d} bytes)", .{pardes.memory.limits.host_path_cap})); return null; @@ -360,6 +369,17 @@ fn spawnTtyWithMount(p: *Pardes, from: usize, v9fs: bool) ?*Pane { return nt; } +/// Whether `path` is a directory on this host, the turn out while it asks +/// (it may be inside a mount this editor serves). +fn isDirectory(path: []const u8) bool { + var buf: [4096]u8 = undefined; + const z = std.fmt.bufPrintSentinel(&buf, "{s}", .{path}, 0) catch return false; + pardes.turn.yield(); + defer pardes.turn.back(); + const stat = std.Io.Dir.cwd().statFile(std.Io.Threaded.global_single_threaded.io(), z, .{}) catch return false; + return stat.kind == .directory; +} + /// With `BootShell replace`, a doc landing in `col` closes a lone pristine /// shell there, the boot's placeholder, and absorbVWeight hands its space to /// the doc. With `keep`, the default, the shell stays like any other pane. |
