summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/ctl.zig31
-rw-r--r--src/ninep/pty.zig5
2 files changed, 35 insertions, 1 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 6a8a37be..9bb9c044 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -1746,6 +1746,37 @@ test "a root exec that fails logs its err against the pane it ran at" {
try testing.expect(th.logHas(p, try std.fmt.bufPrint(&want, "err {d} exec: ", .{serialOf(p)})));
}
+test "Tty in a directory that is not there fails and makes no pane; a shell that never started answers a run" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ _ = wr(p, Node.of(serial, .name), "/tmp/pardes-no-such-dir-zz/f.txt\n");
+ // A host that starts shells (the core alone starts none, and asks
+ // nothing of a directory).
+ const Starting = struct {
+ fn spawn(_: ?*anyopaque, _: u8, _: []const u8) void {}
+ };
+ p.host = .{ .vtable = &.{ .spawn = Starting.spawn } };
+ defer p.host = .{};
+ var count: usize = 0;
+ for (p.panes) |slot| count += @intFromBool(slot != null);
+ const refused = wr(p, Node.of(serial, .ctl), "Tty\n");
+ try testing.expectEqual(E.IO, refused.errno());
+ try testing.expectStringStartsWith(refused.reply.ename, "Tty: /tmp/pardes-no-such-dir-zz: no such directory");
+ var after: usize = 0;
+ for (p.panes) |slot| after += @intFromBool(slot != null);
+ try testing.expectEqual(count, after);
+ // A terminal whose shell the host could not start.
+ _ = wr(p, Node.of(serial, .name), "/tmp/f.txt\n");
+ try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .ctl), "Tty\n").reply.status);
+ const term = p.active;
+ p.shellFailed(@intCast(term), error.FileNotFound);
+ const run_node = Node.of(p.panes[term].?.serial, .pty_run);
+ const h = call(p, .{ .tag = 1, .op = .open, .node = run_node, .omode = 2 }).reply.handle;
+ _ = call(p, .{ .tag = 2, .op = .write, .node = run_node, .handle = h, .data = "true\n" });
+ try testing.expectEqualStrings("error shell gone\n", call(p, .{ .tag = 3, .op = .read, .node = run_node, .handle = h, .size = 64 }).bytes);
+}
+
test "size is monotonic: growing is never refused, and a size once taken is taken again" {
const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 160, .rows = 60 });
defer p.deinit();
diff --git a/src/ninep/pty.zig b/src/ninep/pty.zig
index 4009af49..68f98554 100644
--- a/src/ninep/pty.zig
+++ b/src/ninep/pty.zig
@@ -196,7 +196,10 @@ pub fn writeRun(p: *Pardes, req: Req, id: usize, pane: *Pane) Reply {
const pf = &pane.fs;
const state = pane.terminal orelse return tree.failText(req.tag, E.INVAL, e_bad_line);
const marks = &state.stream.handler;
- if (pane.command != null) {
+ if (pane.shell_failed) {
+ // Its shell never started: no prompt is coming to wait for.
+ answer(p, slot, "error shell gone", .{});
+ } else if (pane.command != null) {
// Its child is the command, and no shell is there to take a line.
answer(p, slot, "error {s}", .{if (pane.command_done) "command done; not a shell" else "a command runs here, not a shell"});
} else if (pf.unmarked) {