summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 05:08:46 -0300
committerGabriel Schneider <[email protected]>2026-10-01 05:18:09 -0300
commitc95f2703875880e583dfbce5ce19c38faa3d5b76 (patch)
tree6fd9d3575a5a0bc91bdd5c7c2f9e8f13678357b8 /src/ninep/ctl.zig
parent1e54e82f763284f086accef902ea1316687c8851 (diff)
downloadpardes-c95f2703875880e583dfbce5ce19c38faa3d5b76.tar.gz
pardes-c95f2703875880e583dfbce5ce19c38faa3d5b76.zip
/pager refuses a directory that is not there, ENOENT, and a relative one, EINVAL: no +Pager named into a missing directory, none quietly the session's
`/(/+Pager` was made for a missing absolute directory, and a relative one fell back to the session's without a word. An empty line still asks for the session's directory. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig16
1 files changed, 12 insertions, 4 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 1fcd7a6d..1e274e0c 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -647,8 +647,14 @@ pub fn writePager(p: *Pardes, req: Req) Reply {
var it = Messages.init(p, req.data);
const line = it.next() orelse "";
if (it.next() != null) return tree.failText(req.tag, E.INVAL, "pager: one directory a write");
+ const dir = std.mem.trim(u8, line, " \t");
+ // A directory that is there, or none (the session's): never a +Pager
+ // named into one missing, nor a relative one quietly taken for none.
+ if (dir.len > 0 and dir[0] != '/') return refuseQuoting(p, req, "pager: the directory must be absolute", dir);
+ if (comptime pardes.hosted) if (dir.len > 0) if (pardes.filesystem.localPath(dir)) |local| if (!exec_line.isDirectory(local))
+ return tree.failText(req.tag, E.NOENT, std.fmt.bufPrint(&p.fs.ename, "pager: {s}: no such directory", .{dir[0..@min(dir.len, 256)]}) catch "pager: no such directory");
p.fs.results_len = 0;
- const id = pardes.panes.Output.openPager(p, p.active, std.mem.trim(u8, line, " \t")) catch |err|
+ const id = pardes.panes.Output.openPager(p, p.active, dir) catch |err|
return tree.failText(req.tag, if (err == error.NoPaneRoom or err == error.NoPaneSlots) E.NOSPC else E.IO, switch (err) {
error.NoPaneRoom, error.NoPaneSlots => "pager: no space for a +Pager pane",
else => "pager: could not make a +Pager pane",
@@ -4011,10 +4017,10 @@ test "pager answers its +Pager on the open that asked, whatever another client e
const pager = @intFromEnum(tree.TopFile.pager);
const exec = @intFromEnum(tree.TopFile.exec);
const asked = call(p, .{ .tag = 1, .op = .open, .node = pager, .omode = 2 }).reply.handle;
- try testing.expectEqual(Status.ok, call(p, .{ .tag = 2, .op = .write, .node = pager, .handle = asked, .data = "/tmp/pager-race\n" }).reply.status);
+ try testing.expectEqual(Status.ok, call(p, .{ .tag = 2, .op = .write, .node = pager, .handle = asked, .data = "/tmp\n" }).reply.status);
const paged = for (p.panes) |slot| {
const pn = slot orelse continue;
- if (pn.file) |f| if (std.mem.eql(u8, f.path, "/tmp/pager-race/+Pager")) break pn.serial;
+ if (pn.file) |f| if (std.mem.eql(u8, f.path, "/tmp/+Pager")) break pn.serial;
} else return error.NoPager;
// Another client execs between the request and its read: a pane of its own.
const racer = call(p, .{ .tag = 3, .op = .open, .node = exec, .omode = 2 }).reply.handle;
@@ -4025,8 +4031,10 @@ test "pager answers its +Pager on the open that asked, whatever another client e
// `pardes -` once read, and wrote its text into.
try testing.expect(!std.mem.eql(u8, want, rd(p, exec, 0, 64).bytes));
try testing.expectEqualStrings(want, call(p, .{ .tag = 5, .op = .read, .node = pager, .handle = asked, .size = 64 }).bytes);
- // One directory a write.
+ // One directory a write, absolute, and there.
try testing.expectEqual(E.INVAL, wr(p, pager, "/a\n/b\n").errno());
+ try testing.expectEqual(E.INVAL, wr(p, pager, "relative\n").errno());
+ try testing.expectEqual(E.NOENT, wr(p, pager, "/tmp/pardes-surely-missing-dir\n").errno());
}
test "a command pane an exec open was answered is leased to it while it stays open: another client's command gets a pane of its own" {