diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 19:25:00 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 57b30ba3e38153a4446626449b0fed5120da954c (patch) | |
| tree | 7b9381327a05791181a855bd8d4ba3cfb4df5301 /docs/v9fs.md | |
| parent | 0fd908eea63d04886b269438aa7529d3dd422256 (diff) | |
| download | pardes-57b30ba3e38153a4446626449b0fed5120da954c.tar.gz pardes-57b30ba3e38153a4446626449b0fed5120da954c.zip | |
The docs and the 9P skill say each fact once, in the file that owns it, and say only what a live session does
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'docs/v9fs.md')
| -rw-r--r-- | docs/v9fs.md | 130 |
1 files changed, 36 insertions, 94 deletions
diff --git a/docs/v9fs.md b/docs/v9fs.md index a105fe06..26460658 100644 --- a/docs/v9fs.md +++ b/docs/v9fs.md @@ -1,114 +1,56 @@ -# Linux terminals with a kernel 9P mount +# Tty9p: a terminal 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: +On Linux, `Tty9p` (`SPC n 9`) opens a terminal below this pane with the +session mounted through the kernel's v9fs. The pane asks for your sudo +password, mounts, and starts your shell as your normal user (with your +supplementary groups). The shell gets `PARDES_MOUNT`, the mountpoint: ```sh -ls "$PARDES_MOUNT/pane" cat "$PARDES_MOUNT/index" -cat "$PARDES_MOUNT/README" cat "$PARDES_MOUNT/pane/$PARDES_PANE/body" echo 'Msg hello' > "$PARDES_MOUNT/exec" n=$(cat "$PARDES_MOUNT/pane/new") ``` -**Opening** `pane/new` makes a pane, and reading that open file answers its -serial; address the pane as `pane/<serial>` from then on. Each open makes -another one, so read it once and keep the number. A *stat* makes nothing, -which is why `new` can be listed at all: `ls`, `ls -l` and `find` over the -whole mount create nothing, because none of them open it. - -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 -``` +The files are those of [fs.md](fs.md). The mount lives in that pane's +private mount namespace: other panes and the editor do not see it, so a +Look at a path under `$PARDES_MOUNT` opens nothing. Each `Tty9p` makes its +own mount and takes one of the session's 16 Unix/TCP connection slots. It +works in TTY, SDL and detached sessions (the session host starts the shell, +not an attached frontend). Dump/Restore does not remake the mount. -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. +## Setup -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`. +The build installs `pardes-v9fs` beside `pardes`; the host looks for it +beside its own executable, or at `PARDES_V9FS_HELPER` (an absolute path). +A running editor keeps the code it started with. -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. +Linux needs `9p` and its Unix transport (`9pnet_fd`); mounting needs +`CAP_SYS_ADMIN`, which sudo supplies. The launcher runs `sudo -E` (local +policy must allow it) and restores the caller's `PATH` after dropping +privileges. Nothing setuid, no passwordless sudo rule and no FUSE is +installed. The helper takes explicit mount paths and a command; it is not a +restricted privilege broker, so do not grant it passwordless sudo. -## Runtime organization +## How it works -`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. +`Tty9p` starts the normal shell and queues a quoted helper command, which +bash and fish run once their prompt is ready, as a foreground job, so sudo +uses the terminal. A failed or cancelled authentication returns to that +shell, as does exiting the mounted one. The unprivileged launcher makes a +private temporary mountpoint and runs sudo; the elevated helper makes a +private mount namespace, mounts the session's socket with +`trans=unix,version=9p2000,cache=none,access=any,nosuid,nodev,noexec`, drops +every root id and capability, and executes the shell. The namespace, and +the mount, go when its last process exits. Code: `src/linux/v9fs.zig`. -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, which is the helper's private -one: a path under `$PARDES_MOUNT` names nothing in the editor's own namespace, -so a Look on one from that shell opens nothing. - -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. +Linux follows `O_TRUNC` with a `Twstat` of zero length and an `mtime` hint; +pardes takes the truncation and drops the hint. ## 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 +zig build v9fs-terminal-test -Dplatform=tty # builtin, launcher, cleanup; a sudo stand-in, no mount +zig build v9fs-driver-test -Dplatform=tty # the probe launcher, no privileges +sudo -v; zig build v9fs-test -Dplatform=tty # a real kernel mount (sudo -n); fails, not skips, without it ``` - -`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 name, 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 (now `test/fs.py:615`), -also reproduced on the cached editor binary preceding the truncation fix. |
