diff options
Diffstat (limited to 'src/ninep')
| -rw-r--r-- | src/ninep/cols.zig | 24 | ||||
| -rw-r--r-- | src/ninep/ctl.zig | 2 |
2 files changed, 24 insertions, 2 deletions
diff --git a/src/ninep/cols.zig b/src/ninep/cols.zig index ef2e6cbd..ebe3279a 100644 --- a/src/ninep/cols.zig +++ b/src/ninep/cols.zig @@ -136,7 +136,12 @@ pub fn writeCtl(p: *Pardes, req: Req, serial: u32) Reply { const takes = for ([_][]const u8{ "Delcol", "Joincol", "New", "Tty" }) |w| { if (std.mem.eql(u8, w, word)) break true; } else false; - if (!takes) return tree.failText(req.tag, E.INVAL, "a column's ctl takes Delcol, Joincol, New or Tty"); + // Plan 9's words for it, so a mount's errno is EINVAL as the root's + // and a pane's ctl give (9ns reads "control message"). + if (!takes) return tree.failText(req.tag, E.INVAL, std.fmt.bufPrint(&p.fs.ename, "unknown control message \"{s}\": a column's ctl takes Delcol, Joincol, New or Tty", .{line[0..@min(line.len, 64)]}) catch "unknown control message"); + // Only Tty takes a word (its shell); `New extra` is no New. + if (!std.mem.eql(u8, word, "Tty") and word.len != line.len) + return tree.failText(req.tag, E.INVAL, std.fmt.bufPrint(&p.fs.ename, "wrong #args in control message \"{s}\"", .{line[0..@min(line.len, 64)]}) catch "wrong #args in control message"); const col = layout.columnBySerial(p, serial) orelse return Reply.fail(req.tag, E.NOENT); p.exec_column = col; defer p.exec_column = null; @@ -272,7 +277,7 @@ test "a column's ctl and exec act on it as its tag would, and rmdir closes it on try testing.expectEqual(@as(usize, 1), p.col_n[1]); try testing.expectEqual(E.INVAL, th.wr(p, Node.ofCol(empty, .ctl), "Exit\n").errno()); var rec: [64]u8 = undefined; - try testing.expect(th.logHas(p, try std.fmt.bufPrint(&rec, "err - col/{d}/ctl: a column's ctl takes", .{empty}))); + try testing.expect(th.logHas(p, try std.fmt.bufPrint(&rec, "err - col/{d}/ctl: unknown control message \"Exit\"", .{empty}))); // rmdir refuses a column with a pane, and says why. const full = th.call(p, .{ .tag = 1, .op = .release, .node = Node.ofCol(empty, .dir), .remove = true }); try testing.expectEqual(E.NOTEMPTY, full.errno()); @@ -356,3 +361,18 @@ test "a command run from a column's tag gets its pane in that column, not the la try testing.expect(other != made); try testing.expectEqual(@as(usize, 1), layout.findPane(p, other).?.col); } + +test "a column's ctl refuses an unknown word and an argument as the other ctls do" { + const p = try th.withFile(testing.allocator, "x\n"); + defer p.deinit(); + const ctl_node = Node.ofCol(layout.columnSerial(p, 0), .ctl); + const unknown = th.wr(p, ctl_node, "Bogus\n"); + try testing.expectEqual(E.INVAL, unknown.errno()); + try testing.expect(std.mem.startsWith(u8, unknown.reply.ename, "unknown control message \"Bogus\"")); + const extra = th.wr(p, ctl_node, "New extra\n"); + try testing.expectEqual(E.INVAL, extra.errno()); + try testing.expect(std.mem.startsWith(u8, extra.reply.ename, "wrong #args")); + try testing.expectEqual(@as(usize, 1), p.col_n[0]); + // A pane's bare answer and a winsize of no size say what they take. + try testing.expectEqualStrings("answer takes a choice or -", th.wr(p, Node.of(p.panes[0].?.serial, .ctl), "answer\n").reply.ename); +} diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 1b1288a1..424245eb 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -660,6 +660,8 @@ pub fn writePane(p: *Pardes, req: Req, pane: *Pane) Reply { if (!held) return tree.failText(req.tag, E.INVAL, e_not_locked); held = false; if (apply) pane.fs.lock = null; + } else if (std.mem.eql(u8, line, "answer")) { + return tree.failText(req.tag, E.INVAL, "answer takes a choice or -"); } else if (std.mem.startsWith(u8, line, "answer ")) { // The pane's question (its `ask` in the log), answered. const choice = std.mem.trim(u8, line["answer ".len..], " "); |
