summaryrefslogtreecommitdiff
path: root/9player/README.md
diff options
context:
space:
mode:
Diffstat (limited to '9player/README.md')
-rw-r--r--9player/README.md156
1 files changed, 0 insertions, 156 deletions
diff --git a/9player/README.md b/9player/README.md
deleted file mode 100644
index 77081d6..0000000
--- a/9player/README.md
+++ /dev/null
@@ -1,156 +0,0 @@
-# 9player
-
-Mount a 9P2000 file tree into a fresh mount namespace and run a program in it,
-as a plain user, without touching the host's mount table.
-
-```sh
-9player --unix /run/user/1000/acme -- fish # a shell that sees the tree at /mnt/9p
-9player --tcp 127.0.0.1:564 -- claude # an agent that sees it too
-9player --spawn 'introspect --stdio' -- bash # start the server yourself, talk over a socketpair
-```
-
-Inside, the tree is ordinary files: `ls`, `cat`, `echo x > ctl`, editors,
-`find`, `rsync`, whatever. `$NINEPLAYER_MOUNT` tells programs where it is
-(default `/mnt/9p`). When the program exits, 9player exits with its status
-and the namespace, mount and connection disappear.
-
-## How it works
-
-The kernel's own `9p` filesystem cannot be mounted inside an unprivileged user
-namespace, so 9player is a small FUSE server that speaks 9P2000 to the real
-server. There is no libfuse and no libc: `src/fuse.zig` implements the subset
-of the kernel FUSE protocol needed, straight from `linux/fuse.h`.
-
-```
- program (fish/bash/claude) 9player (parent) 9P server
- in a new user+mount namespace │
- /mnt/9p ── FUSE ──▶ kernel ────▶│ fuse.zig ─▶ bridge.zig ─▶ nine.zig ──▶ unix / tcp / socketpair
- │ (framing) (translation) (cloud9 Client)
-```
-
-1. The parent connects to the 9P server (version + attach) so failures are
- reported before anything is forked.
-2. The child does `unshare(CLONE_NEWUSER|CLONE_NEWNS)`, maps its own uid/gid,
- makes every mount private, opens `/dev/fuse` (it must be opened inside the
- new user namespace), mounts it on the mountpoint and passes the descriptor
- back to the parent over `SCM_RIGHTS`, then execs the program.
-3. The parent serves FUSE requests by translating them into 9P transactions
- (`Twalk`, `Topen`, `Tread`, `Twrite`, `Tcreate`, `Tremove`, `Tstat`,
- `Twstat`) until the child exits or the namespace disappears.
-
-Files are opened with `FOPEN_DIRECT_IO`, so synthetic files that report length
-0 (the 9P convention for control files) still read correctly, and `O_TRUNC`
-travels inside the 9P open mode (`OTRUNC`) rather than as a separate
-truncate. Repeated lookups of the same qid map to the same inode.
-
-If `/mnt/9p` does not exist and cannot be created (the normal case), 9player
-mounts a tmpfs over `/mnt` *inside the namespace only* and bind-mounts every
-existing entry of `/mnt` back into it, so nothing is hidden. Pass `--mount DIR`
-to use any other directory.
-
-## Building and testing
-
-9player lives in the [cloud9](../) repository as `cloud9/9player/`, beside
-the 9P2000 protocol library it is built on, and is wired into cloud9's
-`build.zig` through the fragment `9player/build.zig`. Everything is run from
-the cloud9 root with Zig 0.16:
-
-```sh
-zig build # zig-out/bin/{9player,introspect,cloud9-http,cloud9-probe}
-zig build 9player # build and install only zig-out/bin/9player
-zig build 9player-test # unit tests (protocol structs, session, bridge, namespace helpers)
-zig build 9player-itest # integration tests: real namespaces, real FUSE,
- # introspect over unix/tcp/socketpair, and plan9port's
- # ramfs when /usr/lib/plan9/bin/ramfs is installed
-zig build 9player-adv # adversarial suites: hostile 9P servers, FUSE semantics,
- # namespace/signal edge cases, stress (several minutes)
-zig build -Doptimize=ReleaseSafe
-zig build -D9player=false # leave 9player out (the default on non-Linux targets)
-```
-
-The integration suites mount the `introspect` demo server (`../introspect`),
-so they need `-Dintrospect=true` (the default on Linux), unprivileged user
-namespaces (`kernel.unprivileged_userns_clone=1` on distributions that have
-the knob), `/dev/fuse` and Python 3; they skip themselves otherwise.
-`zig build programs-test` and `programs-itest` run the unit and integration
-steps of every program in the repository.
-
-## Usage
-
-```
-9player [options] -- PROGRAM [ARGS...]
-
-Transport (exactly one):
- --unix PATH Unix stream socket
- --tcp IP:PORT TCP (IPv4/IPv6 literal)
- --fd N an already-connected inherited descriptor
- --spawn CMD run CMD via /bin/sh -c with a socketpair on its stdin/stdout
-
-Options:
- --mount PATH mountpoint inside the new namespace (default /mnt/9p)
- --uname NAME 9P user name (default $USER)
- --aname NAME 9P tree to attach (default "")
- --msize BYTES maximum 9P message size to request (default 131072, max 16 MiB)
- --cache SECONDS attr/entry cache validity, fractional allowed (default 1)
- --no-direct-io let the kernel cache file pages (trusts stat length)
- --debug trace FUSE and 9P operations on stderr
- --help, --version
-```
-
-PROGRAM defaults to `$SHELL`. Exit status is the program's (`128+signal` if it
-was killed); 125 means 9player itself failed (usage, connect, namespace,
-mount); 126/127 are exec failures as usual.
-
-## introspect: a demo 9P server
-
-`introspect` is a single-binary 9P2000 server whose file tree is the binary
-itself: build-time facts, `comptime` reflection and live runtime state. It is
-the demo of the [introspect library](../introspect) (`../introspect/demo/main.zig`),
-built and installed by `zig build introspect`.
-
-```
-/README
-/build/{zig_version,target,optimize,time,change} captured by build.zig (jj change id, UTC time)
-/comptime/types/<T>/{name,size,align,fields} @sizeOf/@alignOf/@typeInfo, generated at comptime
-/comptime/decls pub declarations of the server module
-/runtime/{pid,ppid,uptime,argv,cwd,env,clients}
-/runtime/fn/<name> reading calls a Zig function (hostname, now, random, uname, fib30);
- the directory is generated from @typeInfo of the Fns struct
-/runtime/ctl write "fib N" | "add A B" | "echo TEXT" | "sleep-ms N", read the result
-/scratch/ in-memory read/write tree
-```
-
-`/runtime/env` exposes the server's whole environment, so serve introspect on
-a Unix socket or loopback only.
-
-```sh
-zig-out/bin/introspect --unix /tmp/intro.sock &
-zig-out/bin/9player --unix /tmp/intro.sock -- sh -c '
- cat $NINEPLAYER_MOUNT/build/zig_version; echo
- cat $NINEPLAYER_MOUNT/comptime/types/Qid/fields
- echo "fib 20" > $NINEPLAYER_MOUNT/runtime/ctl; cat $NINEPLAYER_MOUNT/runtime/ctl'
-```
-
-The same command with `claude -p "explore /mnt/9p ..."` as the program gives an
-agent a live, file-shaped view into a running process; that is the intended
-use.
-
-## Limitations
-
-* One 9P request is in flight at a time; a server read that blocks (event
- files) stalls the mount until it returns.
-* Base 9P2000 only: no symlinks, ownership, xattrs or locks. Every file is
- reported as owned by the invoking user. Cross-directory rename is `EXDEV`.
-* No PID namespace and no `/proc` remount. `--tcp` takes IP literals only
- (no libc, no resolver).
-* Linux only.
-
-## Relation to cloud9
-
-9player consumes cloud9 as the module `cloud9` and keeps all mounting,
-namespace and process policy on its side, which is what cloud9's design asks
-of applications. It ships from the cloud9 repository as the sibling directory
-`9player/` (sources in `src/`, suites in `test/`, this README and
-`docs/DESIGN.md`) with a build fragment that the root `build.zig` enables with
-`-D9player` on Linux targets; nothing in the code depends on that layout.
-`docs/DESIGN.md` has the full module contracts.