summaryrefslogtreecommitdiff
path: root/src/exec.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 08:02:47 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit0ec8d0dc6217486446f2fe2156dff136173a4ef5 (patch)
tree8e20f9f0fec47f614492d31c7f03a03e3ac1d0c5 /src/exec.zig
parentba0a0f82be43dde325012b3018b186bc808bdafc (diff)
downloadpardes-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.zig22
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.