summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 11:23:19 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit1ac8fbeedaf7cba881a7423b92ead1f739b8ac21 (patch)
treec3916f9918fb98252987331195cd1b70712c890d /src/pardes.zig
parent2c98513a23d060093d690dbd7743dda5ad86c117 (diff)
downloadpardes-1ac8fbeedaf7cba881a7423b92ead1f739b8ac21.tar.gz
pardes-1ac8fbeedaf7cba881a7423b92ead1f739b8ac21.zip
A script whose interpreter is not there is told apart from a missing shell, and Tty refuses it up front
Tty's up-front check found the script and let it through, so the pane was made, its exec failed ENOENT, and the log read new, msg shell: shell not found, del, then the err. The check now reads a script's #! line and refuses it, interpreter /no/such/interp not found, and an exec that fails ENOENT on a file that is there says the same. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig34
1 files changed, 24 insertions, 10 deletions
diff --git a/src/pardes.zig b/src/pardes.zig
index d9c69921..d2fd795b 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -5338,16 +5338,7 @@ pub const Pardes = struct {
const pane = p.panes[id] orelse return;
pane.shell_failed = true;
ctlfs.pty.shellGone(p, pane, false);
- if (err == error.FileNotFound or err == error.NotDir)
- p.reportFailure(id, "shell: directory missing (no such directory)")
- else
- p.reportError(id, "shell", err);
- // A 9P write that asked for the shell (pty/ctl's exec), waiting on
- // it, fails with what was said, as a failed Save's does.
- const said = pane.msg[0..pane.msg_len];
- const kept = @import("Messages.zig").clip(said, p.fs.late_failure.len);
- @memcpy(p.fs.late_failure[0..kept.len], kept);
- p.fs.late_failure_len = @intCast(kept.len);
+ p.sayShellFailure(id, err);
// A command that never started ended: `exit 127`, as a shell says of
// a command it could not run, so a follower waiting on its exit
// hears one, its tag stops saying it runs, and Kill finds nothing.
@@ -5362,6 +5353,29 @@ pub const Pardes = struct {
}
}
+ fn sayShellFailure(p: *Pardes, id: u8, err: anyerror) void {
+ const pane = p.panes[id] orelse return;
+ if (err == error.FileNotFound or err == error.NotDir) {
+ p.reportFailure(id, "shell: directory missing (no such directory)");
+ } else if (err == error.InterpreterNotFound) {
+ // The script is there; the program its `#!` names is not.
+ var said: [320]u8 = undefined;
+ var interp: [256]u8 = undefined;
+ var buf: [std.fs.max_path_bytes]u8 = undefined;
+ const Shell = if (comptime hosted) @import("host_io.zig").Shell else void;
+ const name: ?[]const u8 = if (comptime hosted) (if (Shell.find(pane.shell orelse p.shellBin(), &buf)) |f| Shell.missingInterpreter(f, &interp) else null) else null;
+ p.reportFailure(id, if (name) |n| std.fmt.bufPrint(&said, "shell: interpreter {s} not found", .{n}) catch "shell: interpreter not found" else "shell: interpreter not found");
+ } else {
+ p.reportError(id, "shell", err);
+ }
+ // A 9P write that asked for the shell (pty/ctl's exec), waiting on
+ // it, fails with what was said, as a failed Save's does.
+ const said = pane.msg[0..pane.msg_len];
+ const kept = @import("Messages.zig").clip(said, p.fs.late_failure.len);
+ @memcpy(p.fs.late_failure[0..kept.len], kept);
+ p.fs.late_failure_len = @intCast(kept.len);
+ }
+
pub fn saveFailed(p: *Pardes, id: u8, path: []const u8, err: anyerror) void {
if (p.panes[id]) |pane| if (pane.file) |*f| {
// The `-%` spelling fs.zig already uses for "make this dirty".