summaryrefslogtreecommitdiff
path: root/docs/v9fs.md
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-14 21:26:47 -0300
committerGabriel Schneider <[email protected]>2026-09-15 17:24:42 -0300
commita624a56e289e4a02a411f83741f0f2c9fc0f0b2e (patch)
treeb87e3ca10dd1c4417112164f792b5da1e26de0a6 /docs/v9fs.md
parent95681ff7017b8a9e4c8f9fa6a7371d1233432f2f (diff)
downloadpardes-a624a56e289e4a02a411f83741f0f2c9fc0f0b2e.tar.gz
pardes-a624a56e289e4a02a411f83741f0f2c9fc0f0b2e.zip
Add Linux Tty9p mounted terminals and forward raw TTY keys
Diffstat (limited to 'docs/v9fs.md')
-rw-r--r--docs/v9fs.md107
1 files changed, 107 insertions, 0 deletions
diff --git a/docs/v9fs.md b/docs/v9fs.md
new file mode 100644
index 00000000..51b35a46
--- /dev/null
+++ b/docs/v9fs.md
@@ -0,0 +1,107 @@
+# Linux terminals with a kernel 9P mount
+
+Execute `Tty9p`, or press `SPC n 9` in editor mode, to open a terminal below
+this pane with the current Pardes session mounted through Linux v9fs.
+
+The new pane asks for your sudo password when needed. After mounting, it starts
+your configured shell as your normal user, with your account's supplementary
+groups. The shell receives `PARDES_MOUNT`, the absolute mountpoint:
+
+```sh
+ls "$PARDES_MOUNT/self/pane"
+cat "$PARDES_MOUNT/self/index"
+cat "$PARDES_MOUNT/self/README"
+ls -l "$PARDES_MOUNT/self/new"
+cat "$PARDES_MOUNT/self/pane/$PARDES_PANE/body"
+```
+
+The mount belongs to that pane's subprocess tree. Other panes and the editor
+core keep their original mount namespace. It works in native Linux TTY and SDL
+sessions, including detached sessions. A frontend attaching from elsewhere does
+not perform the mount; the session host starts the new terminal.
+
+## Build and setup
+
+The normal Linux build installs the ordinary `pardes-v9fs` executable beside
+`pardes` and `pardes-gui`:
+
+```sh
+zig build
+```
+
+Start an updated editor to get the builtin. An already running core retains
+its old code. The host resolves the helper beside its own executable;
+`PARDES_V9FS_HELPER=/absolute/path/to/pardes-v9fs` overrides this for development
+builds whose editor and helper live in different build-cache directories.
+
+Linux must support `9p` and its Unix transport (`9pnet_fd`). v9fs mounting needs
+`CAP_SYS_ADMIN` in the initial user namespace, which sudo supplies. The launcher
+uses `sudo -E` to retain the shell environment; local sudo policy must allow
+that. It restores the caller's PATH after dropping privileges because sudo's
+`secure_path` can replace it even with `-E`.
+
+No setuid installation, passwordless sudo policy, system group, or FUSE is
+installed. The helper currently accepts explicit mount paths and a command;
+it is not a restricted privilege broker. Do not grant it blanket passwordless
+access. A group-authorized helper would require a separate restricted design.
+
+## Runtime organization
+
+`src/linux/v9fs.zig` builds `pardes-v9fs` and provides helper discovery to the
+native host. `Tty9p` marks the new pane for a mounted shell; `host_io.forkShell`
+starts the normal interactive shell and queues a quoted helper command. For
+bash and fish, the command waits for the shell's prompt-ready mark. The helper
+runs as a foreground shell job, so sudo uses the terminal like a manually run
+command. Authentication failure or cancellation returns to the original shell;
+exiting the mounted shell also returns there.
+
+The unprivileged launcher creates a private temporary mountpoint and invokes
+sudo inside the new PTY. The elevated helper creates a private mount namespace,
+makes propagation recursively private, and mounts the session's Unix socket
+with `version=9p2000,cache=none,access=any,nosuid,nodev,noexec`. It restores the
+calling user's account groups, drops all real/effective/saved root IDs and
+mount capabilities, and executes the shell. Ordinary commands such as sudo
+remain available for subsequent explicit authentication. The launcher waits for sudo,
+forwards termination signals, and removes its empty temporary directory on exit.
+Namespace destruction releases the mount when its last process exits.
+
+The core stays outside the mount namespace because its event loop serves 9P.
+A blocking filesystem operation through its own mount could wait for a request
+that the blocked event loop must service. Even pathname resolution may do this.
+
+Each `Tty9p` currently creates its own mount and consumes a server connection;
+the session has four application connection slots across all transports. This
+is the explicit per-pane version. A shared launcher for all pane shells remains
+future work. Detached sessions retain the running mounted pane when frontends
+leave; Dump/Restore does not reconstruct mounted-shell namespaces. Descendants
+that deliberately outlive the terminal may retain their namespace until exit.
+
+## Tests
+
+```sh
+zig build v9fs-terminal-test -Dplatform=tty
+zig build v9fs-driver-test -Dplatform=tty
+zig build 9p-test -Dplatform=tty
+sudo -v
+zig build v9fs-test -Dplatform=tty
+```
+
+`v9fs-terminal-test` exercises the builtin, real launcher, PTY input, session
+environment, quoted helper paths, hidden password input, and core responsiveness
+using an unprivileged sudo stand-in. It checks that authentication failure and
+interruption clean up the temporary mountpoint and leave the original shell usable. It does not claim kernel-mount coverage.
+
+`v9fs-test` mounts through the same runtime helper. Its driver keeps the editor
+unprivileged and uses `sudo -n`, retaining the calling terminal's authorization.
+Missing authorization or kernel support fails the test instead of skipping it.
+It checks mount isolation, privilege dropping, inherited access, directory
+refresh, body reads and truncation, independent wire updates, addressed edits,
+shell redirection to ctl, Exec dispatch, rendered screen JSON, and OS-file reads.
+
+Linux follows `O_TRUNC` with a `Twstat` carrying zero length and an `mtime` hint.
+Pardes accepts this truncation without storing caller-selected timestamps;
+standalone timestamp, permission, and ownership changes remain unsupported.
+
+The initial kernel probe passed on this host on 2026-09-14. The broader
+`fs-test` has an existing syntax-bold assertion failure at `test/fs.py:459`,
+also reproduced on the cached editor binary preceding the truncation fix.