Files
LithosAnanke/demo/start-session.sh
T
rajamesandClaude Opus 5.5 9e711563b4 demo: StarshipOS in a browser -- a throwaway machine per visitor, as Zuse (#111-#115)
Captain Bob, 2026-11-06: a terminal with QEMU amd64 for people to play
with; "Mint Zuse for demo console" (#111); "Make the most recent of
builds that's green the demo"; a Try-it XWiki page with the console
embedded.

demo/ -- see its README:
  mint-zuse.sh       a Zuse of the demo's own, as a stick: blank pair,
                     system=v3 genesis, a second boot to confirm, make
                     zusestick. Never anyone's real Zuse
  build-iso.sh       the amd64 ISO, packed as make qemu packs it
  make-snapshot.sh   boot once to [zuse@Hera] ok>, save the machine
  start-session.sh   one visitor: the saved machine resumed, ended on
                     hang-up, close or time-out
  console.py         joins the visitor's terminal only once the machine
                     runs; keys typed while it loads are discarded
  qemu-args.sh       the machine, shared by save and resume
  starshipos-demo.service, apache-demo.conf, xwiki-try-it.xwiki

Every session is a copy: no network, read-only image, the Zuse stick's
writes discarded, QEMU's seccomp sandbox, an unprivileged user, a
fenced systemd unit, 30 minutes at most.

Tested here, from the sources master accepted (run 153): the Zuse
minted (logs/20261106-192626, -192739); the saved machine at POST
538/538 and [zuse@Hera] ok>; a session through ttyd's websocket ready
in 0.2 s, 3 4 + . -> 7 ok, 7 SQUARE . -> 49 ok; QEMU gone at once on
hang-up, close and time-out. Found and fixed on the way: a machine
saved stopped resumes stopped; a prompt matched as a regex; QEMU left
behind by a hang-up; keys lost while the machine loads. Not tested
here: Apache, several sessions at once (#116).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-06 19:41:22 +00:00

43 lines
2.2 KiB
Bash
Executable File

#!/bin/bash
# start-session.sh -- one visitor's session: the saved demo machine, resumed at its prompt, its
# serial console on this terminal; gone when the visitor leaves or the time is up (issue #112).
# ttyd runs this once per browser connection (issue #114).
#
# demo/start-session.sh [state-dir] (default: /var/lib/starshipos-demo)
#
# Nothing a visitor does survives the session: the firmware variables are a copy, the identity
# drive's writes are discarded, the image is read-only, and the guest has no network.
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
. "$here/qemu-args.sh"
dir=${1:-${DEMO_STATE:-/var/lib/starshipos-demo}}
limit=${DEMO_SESSION_LIMIT:-1800} # seconds a session may last
[ -f "$dir/state" ] || { echo "The demo is not set up yet: no saved machine in $dir." >&2; exit 1; }
tmp=$(mktemp -d "${TMPDIR:-/tmp}/starshipos-session.XXXXXX")
trap 'rm -rf "$tmp"' EXIT
cp "$dir/vars.fd" "$tmp/vars.fd"
demo_qemu_args "$dir" "$tmp/vars.fd"
printf '\r\nStarshipOS -- starting a throwaway machine, yours for up to %d minutes. Nothing you do is kept.\r\n' $((limit / 60))
printf 'Try: 3 4 + . : SQUARE DUP * ; 7 SQUARE .\r\n\r\n'
# QEMU is a tracked child, not exec'd, so that whatever ends the session ends the machine: ttyd
# hangs up (it signals this script only), the service stops, or the time runs out. Its console is
# a private socket, joined to this terminal by console.py only once the machine runs: keys typed
# while it loads would be lost half-way through a line.
qemu-system-x86_64 "${QEMU_ARGS[@]}" \
-chardev "socket,id=con,path=$tmp/con.sock,server=on,wait=off" -serial chardev:con \
-qmp "unix:$tmp/qmp.sock,server=on,wait=off" -monitor none \
-incoming "file:$dir/state" </dev/null &
qemu=$!
( sleep "$limit"; kill "$qemu" 2>/dev/null ) &
timer=$!
# The bridge is a tracked child too: bash runs a trap only once its foreground command returns,
# so a hang-up would otherwise wait on the bridge. `wait` returns to the trap at once.
python3 -I "$here/console.py" "$tmp/qmp.sock" "$tmp/con.sock" 0<&0 &
bridge=$!
trap 'kill "$bridge" "$qemu" "$timer" 2>/dev/null; rm -rf "$tmp"' EXIT
trap 'exit 0' HUP TERM INT
wait "$bridge" || true
printf '\r\n\r\nThe session has ended. Reload the page for a new one.\r\n'