summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 13:26:10 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commit917e9a099f3a5048ac436aafcfabbf3d40d1c24f (patch)
tree334ca7e2cee44cd106533d57562a7a3f2cfb013d /src/ninep/ctl.zig
parentf4fdeb4f0f5f08699f77bd2cc6cac5a87d9f5091 (diff)
downloadpardes-917e9a099f3a5048ac436aafcfabbf3d40d1c24f.tar.gz
pardes-917e9a099f3a5048ac436aafcfabbf3d40d1c24f.zip
docs: through a mount a malformed write is EINVAL and one that fails is EIO, and the error words keep it so
The served README said every refused write reads as EINVAL, but a mount's errno is 9ns's reading of the error's words, so a no-match or out-of-range address and a refused Exit came back EIO, as the dogfood run saw. That split is the useful one, malformed against failed, so the docs now state it rather than the words being bent to EINVAL; a test pins each error's words to its side of it. It caught one: 'regular expression search took too long' read as ENAMETOOLONG, and now says it gave up past its step budget. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 382cc0e7..386fd9a9 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -926,3 +926,28 @@ test "look and exec read back what the last command touched, a ctl write's too"
try testing.expectEqual(tree.Status.ok, wr(p, @intFromEnum(tree.TopFile.ctl), "Verbose off\n").reply.status);
try testing.expectEqualStrings(try std.fmt.bufPrint(&want, "{d}\n", .{made}), rd(p, root_exec, 0, 64).bytes);
}
+
+test "an error's words give the errno a mount reads: EINVAL for what is malformed, EIO for what failed" {
+ // 9ns (cloud9's 9ns/src/nine.zig) maps an error to an errno by its
+ // words, and EIO when none of them match: these words must not.
+ const addressing = @import("addr.zig");
+ const einval = [_][]const u8{ "control message", "invalid", "bad " };
+ const other = [_][]const u8{ "interrupt", "shut down", "not exist", "not found", "no such", "exists", "not empty", "not a dir", "is a dir", "permission", "denied", "read-only", "read only", "no space", "not allowed", "not permitted", "cannot", "fid", "busy", "in use", "too long", "not supported", "unsupported" };
+ const Case = struct { text: []const u8, malformed: bool };
+ for ([_]Case{
+ .{ .text = addressing.e_syntax, .malformed = true },
+ .{ .text = addressing.e_regexp, .malformed = true },
+ .{ .text = e_prompt, .malformed = true },
+ .{ .text = addressing.e_no_match, .malformed = false },
+ .{ .text = addressing.e_range, .malformed = false },
+ .{ .text = addressing.e_order, .malformed = false },
+ .{ .text = addressing.e_slow, .malformed = false },
+ .{ .text = "/tmp/x.txt: Modified (Exit again to discard)", .malformed = false },
+ }) |c| {
+ const says_einval = for (einval) |w| {
+ if (std.ascii.findIgnoreCase(c.text, w) != null) break true;
+ } else false;
+ try testing.expectEqual(c.malformed, says_einval);
+ for (other) |w| try testing.expect(std.ascii.findIgnoreCase(c.text, w) == null);
+ }
+}