summaryrefslogtreecommitdiff
path: root/src/ninep/pty.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/pty.zig')
-rw-r--r--src/ninep/pty.zig33
1 files changed, 27 insertions, 6 deletions
diff --git a/src/ninep/pty.zig b/src/ninep/pty.zig
index c657d27d..b34bd59d 100644
--- a/src/ninep/pty.zig
+++ b/src/ninep/pty.zig
@@ -76,6 +76,18 @@ fn verb(p: *Pardes, id: usize, line: []const u8, apply: bool) bool {
return true;
}
+/// ctl reads back its state in the words it takes, as a Plan 9 ctl does.
+pub fn readCtl(p: *Pardes, req: Req, pane: *Pane) Reply {
+ p.fs.stage(p.gpa).print(p.gpa, "winsize {d} {d}\n", .{ pane.cols, pane.rows }) catch
+ return Reply.fail(req.tag, E.NOMEM);
+ return tree.stagedReply(p, req);
+}
+
+pub fn ctlLen(pane: *const Pane) u64 {
+ var buf: [32]u8 = undefined;
+ return (std.fmt.bufPrint(&buf, "winsize {d} {d}\n", .{ pane.cols, pane.rows }) catch unreachable).len;
+}
+
/// Three right-aligned fields: cols, rows and whether the host holds the tty.
pub const status_len: u64 = 36;
@@ -183,7 +195,7 @@ test "a terminal pane's pty/ holds exactly ctl, status and data" {
const ctl = look_up(p, Node.of(serial, .pty), "ctl");
try testing.expectEqual(Node.of(serial, .pty_ctl), ctl.reply.attr.node);
- try testing.expectEqual(@as(u16, 0o222), ctl.reply.attr.mode);
+ try testing.expectEqual(@as(u16, 0o666), ctl.reply.attr.mode);
try testing.expectEqual(@as(u16, 0o444), look_up(p, Node.of(serial, .pty), "status").reply.attr.mode);
try testing.expectEqual(E.NOENT, look_up(p, Node.of(serial, .pty), "body").errno());
try testing.expectEqual(E.NOENT, look_up(p, Node.of(serial, .pty), "pty").errno());
@@ -191,7 +203,7 @@ test "a terminal pane's pty/ holds exactly ctl, status and data" {
try testing.expectEqual(E.NOTDIR, look_up(p, Node.of(serial, .pty_ctl), "x").errno());
try testing.expectEqual(E.NOTDIR, rdir(p, Node.of(serial, .pty_ctl), 0).errno());
try testing.expectEqual(E.PERM, rd(p, Node.of(serial, .pty), 0, 16).errno());
- try testing.expectEqual(E.PERM, rd(p, Node.of(serial, .pty_ctl), 0, 16).errno());
+ try testing.expect(std.mem.startsWith(u8, rd(p, Node.of(serial, .pty_ctl), 0, 64).bytes, "winsize "));
try testing.expectEqual(E.PERM, wr(p, Node.of(serial, .pty_status), "x").errno());
}
@@ -204,6 +216,8 @@ test "every pty/ctl verb, and every refusal" {
const pane = p.panes[0].?;
const cols = pane.cols;
const rows = pane.rows;
+ var said: [32]u8 = undefined;
+ try testing.expectEqualStrings(try std.fmt.bufPrint(&said, "winsize {d} {d}\n", .{ cols, rows }), rd(p, ctl, 0, 64).bytes);
const ws = wr(p, ctl, "winsize 132 44\n");
try testing.expectEqual(@as(u32, "winsize 132 44\n".len), ws.reply.written);
try testing.expectEqual(@as(u16, 132), ws.winsize.?.cols);
@@ -331,7 +345,12 @@ test "pty/data writes at the shell and reads the raw stream" {
try testing.expectEqual(@as(usize, 0), p.fs.panes[0].pty_out.buf.items.len);
try testing.expectEqual(Status.again, rd(p, data, 0, 64).reply.status);
- _ = call(p, .{ .tag = 5, .op = .open, .node = data });
+ // An open that only writes is not a reader: nothing queues for it.
+ const writer = call(p, .{ .tag = 4, .op = .open, .node = data, .omode = 1 });
+ try testing.expectEqual(@as(u16, 0), p.fs.panes[0].pty_readers);
+ _ = call(p, .{ .tag = 4, .op = .release, .node = data, .handle = writer.reply.handle });
+
+ const reader = call(p, .{ .tag = 5, .op = .open, .node = data });
try testing.expectEqual(@as(u16, 1), p.fs.panes[0].pty_readers);
try testing.expectEqual(@as(u16, 0), p.fs.listeners);
try testing.expect(!p.fs.scripted(0));
@@ -351,14 +370,16 @@ test "pty/data writes at the shell and reads the raw stream" {
p.update(.{ .output = .{ .pane = 0, .bytes = "orphan" } });
while (p.nextEffect()) |_| {}
- _ = call(p, .{ .tag = 6, .op = .release, .node = data });
+ _ = call(p, .{ .tag = 6, .op = .release, .node = data, .handle = reader.reply.handle });
try testing.expectEqual(@as(u16, 0), p.fs.panes[0].pty_readers);
try testing.expectEqual(@as(usize, 0), p.fs.panes[0].pty_out.buf.capacity);
try testing.expectEqual(Status.again, rd(p, data, 0, 64).reply.status);
+ // A second reader would take half the stream from the first: refused.
_ = call(p, .{ .tag = 7, .op = .open, .node = data });
- _ = call(p, .{ .tag = 8, .op = .open, .node = data });
- _ = call(p, .{ .tag = 9, .op = .release, .node = data });
+ const second = call(p, .{ .tag = 8, .op = .open, .node = data, .omode = 2 });
+ try testing.expectEqual(Status.err, second.reply.status);
+ try testing.expectEqualStrings(tree.e_in_use, second.reply.ename);
try testing.expectEqual(@as(u16, 1), p.fs.panes[0].pty_readers);
p.update(.{ .output = .{ .pane = 0, .bytes = "still" } });
while (p.nextEffect()) |_| {}