summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 21:52:42 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commitcc8b72c1b1fd19cd3ef159fe4f56c7b7916380ce (patch)
treefd35f74770e43c019ad36df46be603a9c2e8f99f
parentea4ee39629b8690803c9e5b8b45ec07bdb9738ac (diff)
downloadpardes-cc8b72c1b1fd19cd3ef159fe4f56c7b7916380ce.tar.gz
pardes-cc8b72c1b1fd19cd3ef159fe4f56c7b7916380ce.zip
Mount with no dial is wrong #args, and a dial that is no address says bad dial address, both EINVAL
Mount name alone failed "Mount name dial: missing argument" and a malformed dial "Mount: bad dial", both EIO, though each is a malformed request. They now say wrong #args and bad dial address (with the forms a dial takes), and a builtin failure in those words answers EINVAL, as 9ns reads them. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--src/builtins.zig11
-rw-r--r--src/ninep/ctl.zig21
2 files changed, 27 insertions, 5 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index bc9bb075..89d89c3a 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -790,10 +790,15 @@ pub const Mount = struct {
pub fn run(c: Ctx) void {
if (comptime !enabled) unreachable;
var args = std.mem.tokenizeAny(u8, c.arg orelse "", " \t");
- const name = args.next() orelse return c.p.reportError(c.id, "Mount name dial", error.MissingArgument);
+ const e_args = "wrong #args in control message \"Mount\": Mount name dial";
+ const name = args.next() orelse return c.p.reportFailure(c.id, e_args);
const dial = std.mem.trim(u8, args.rest(), " \t");
- if (dial.len == 0) return c.p.reportError(c.id, "Mount name dial", error.MissingArgument);
- c.p.fs.mount(c.p.gpa, name, dial) catch |err| return c.p.reportError(c.id, "Mount", err);
+ if (dial.len == 0) return c.p.reportFailure(c.id, e_args);
+ c.p.fs.mount(c.p.gpa, name, dial) catch |err| {
+ var said: [200]u8 = undefined;
+ if (err == error.BadDial) return c.p.reportFailure(c.id, std.fmt.bufPrint(&said, "Mount: bad dial address: {s} (unix!/path, tcp!host!port, or a session name)", .{dial[0..@min(dial.len, 100)]}) catch "Mount: bad dial address");
+ return c.p.reportError(c.id, "Mount", err);
+ };
// A mount that cannot be reached is said now, and taken back, not
// found out by the first look through it.
const reached = reached: {
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 6e09084b..5b63080e 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -302,6 +302,9 @@ fn failureErrno(failure: []const u8) u16 {
// so is a word this build has not (`invalid: acme's Put ...`).
if (std.mem.indexOf(u8, failure, "bad regular expression") != null or std.mem.startsWith(u8, failure, "invalid") or
std.mem.startsWith(u8, failure, "address out of range")) return E.INVAL;
+ // A word's arguments wrong, or a dial that is no address: what 9ns
+ // reads as EINVAL from the same words (`control message`, `bad `).
+ if (std.mem.indexOf(u8, failure, "control message") != null or std.mem.indexOf(u8, failure, "bad dial address") != null) return E.INVAL;
return E.IO;
}
@@ -1280,9 +1283,9 @@ test "the root ctl reads the settings as a write takes them, and takes the sessi
try testing.expect(!p.settings.verbose);
// A builtin that fails as it runs fails the write, quoting its error and
// its line; the lines before it have taken effect, as in acme.
- const failed = wr(p, root_ctl, "Verbose on\nMount x\nVerbose off");
+ const failed = wr(p, root_ctl, "Verbose on\nMount x /tmp/pardes-no-such-sock-zz\nVerbose off");
try testing.expectEqual(E.IO, failed.errno());
- try testing.expectEqualStrings("Mount name dial: missing argument", failed.reply.ename);
+ try testing.expectStringStartsWith(failed.reply.ename, "Mount x /tmp/pardes-no-such-sock-zz: dial failed");
try testing.expect(p.settings.verbose);
try testing.expect(!p.fs.no_prompt);
try testing.expectEqual(Status.ok, wr(p, root_ctl, "Verbose off").reply.status);
@@ -1674,6 +1677,20 @@ test "Save path of a file pane logs a save record naming that path" {
try testing.expect(th.logHas(p, try std.fmt.bufPrint(&want, "save {d} /tmp/pardes-save-copy.txt\n", .{serial})));
}
+test "Mount with no dial is wrong #args, and a dial that is no address says bad dial address" {
+ if (comptime !pardes.hosted) return;
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const root_ctl = @intFromEnum(tree.TopFile.ctl);
+ const bare = wr(p, root_ctl, "Mount work\n");
+ try testing.expectEqual(E.INVAL, bare.errno());
+ try testing.expectStringStartsWith(bare.reply.ename, "wrong #args");
+ const bad = wr(p, root_ctl, "Mount work tcp!nohost\n");
+ try testing.expectEqual(E.INVAL, bad.errno());
+ try testing.expectStringStartsWith(bad.reply.ename, "Mount: bad dial address: tcp!nohost");
+ try testing.expectEqual(@as(usize, 0), p.fs.mounts.items.len);
+}
+
test "an address looked at in an image pane names the image, never an empty subject" {
const p = try withFile(testing.allocator, "x\n");
defer p.deinit();