mouse/src

Diff

6c32d9c0f434ea9ff564e7ff

Makefile

Mode 100644100644; object 23df1ae093713a8df4295e43

@@ -17,7 +17,7 @@
 	./scripts/run-qemu.sh
 
 check: image
-	./scripts/check-c1.sh
+	./scripts/check-c2.sh
 
 audit: image
 	@printf '%s\n' "static ELF audit passed during the container build"

README.md

Mode 100644100644; object 22264dd53c4d0d330f2b91e4

@@ -1,6 +1,6 @@
 # MOUSE source tree
 
-This repository builds the MOUSE C1 boot image: Linux 6.18.35 from pinned
+This repository builds the MOUSE C2 boot image: Linux 6.18.35 from pinned
 kernel.org source using MOUSE's own x86_64 configuration, a MOUSE-owned mini
 rootfs with ChimeraUtils and static OpenRC 0.63.3, and `cheesed` from the
 sibling repository as `/sbin/cheesed`.
@@ -43,7 +43,8 @@
 
 `make check` requires `expect`. It boots enabled and disabled policy variants
 under QEMU, verifies strict `/etc/rc.conf` translation into disposable
-runlevels, required-service ordering, `supervise-daemon` restart state,
+runlevels, required-service ordering, `supervise-daemon` restart exhaustion and
+administrative recovery, forced termination on the declared stop schedule,
 runtime-only `service` operations, the absence of `rc-update`, and orderly
 OpenRC shutdown before poweroff and reboot.
 

patches/openrc-mouse-tool-surface.patch

Mode 100644100644; object 4e7232bd360299cc1148992c

@@ -37,6 +37,42 @@
  subdir('supervise-daemon')
 -subdir('swclock')
  subdir('value')
+--- a/src/shared/meson.build
++++ b/src/shared/meson.build
+@@ -1,5 +1,9 @@
+-version_h = vcs_tag(input : 'version.h.in', output : 'version.h')
+-vcs_tag(input : 'version.in', output : 'version')
++version_data = configuration_data()
++version_data.set('VCS_TAG', meson.project_version())
++version_h = configure_file(input : 'version.h.in', output : 'version.h',
++  configuration : version_data)
++configure_file(input : 'version.in', output : 'version',
++  configuration : version_data)
+ 
+ shared_sources = [
+   'misc.c',
+--- a/src/service/meson.build
++++ b/src/service/meson.build
+@@ -6,6 +6,7 @@
+   'service_inactive',
+   'service_wasinactive',
+   'service_hotplugged',
++  'service_failed',
+   'service_started_daemon',
+   'service_crashed',
+   ]
+--- a/sh/supervise-daemon.sh
++++ b/sh/supervise-daemon.sh
+@@ -95,6 +95,9 @@
+ 	elif service_inactive; then
+ 		ewarn "status: inactive"
+ 		return 16
++	elif service_failed; then
++		eerror "status: failed"
++		return 32
+ 	elif service_started; then
+ 		if service_crashed; then
+ 			if ! _check_supervised; then
 --- a/sh/init.sh.Linux.in
 +++ b/sh/init.sh.Linux.in
 @@ -11,14 +11,14 @@

rootfs/etc/init.d/mouse_optional

Mode 100644100644; object 22c47ff88361173b05646a96

@@ -1,13 +1,12 @@
 #!/sbin/openrc-run
 
-description="MOUSE optional C1 proof service"
+description="MOUSE optional supervised proof service"
 supervisor=supervise-daemon
-command=/bin/sleep
-command_args="2147483647"
-respawn_delay=1
+command=/usr/libexec/mouse-c2-daemon
+respawn_delay=0
 respawn_max=3
 respawn_period=10
-retry="TERM/3/KILL/2"
+retry="TERM/1/KILL/1"
 
 depend() {
 	need mouse_ready
@@ -15,6 +14,10 @@
 
 start_post() {
 	checkpath --file /run/mouse-optional.started
+}
+
+start_pre() {
+	rm -f /run/mouse-c2-daemon.term
 }
 
 stop_post() {

scripts/build-static-base.sh

Mode 100755100755; object 9933e70c811f34ee7674690d

@@ -440,6 +440,11 @@
 install -m 0755 "$sysroot/usr/bin/tput" "$base_root/usr/bin/tput"
 ln -s tcsh "$base_root/usr/bin/csh"
 
+install -d -m 0755 "$base_root/usr/libexec"
+"$cc" -O2 -Wall -Wextra -Werror \
+    "$repo_dir/support/mouse-c2-daemon.c" \
+    -o "$base_root/usr/libexec/mouse-c2-daemon"
+
 printf '%s\n' '#!/bin/sh' 'exec /usr/bin/tput clear' >"$base_root/usr/bin/clear"
 chmod 0755 "$base_root/usr/bin/clear"
 

scripts/check-c1.exp

Mode 100755100755; object d05d6fff016955c458a50cd2

@@ -70,6 +70,10 @@
 await_exact "cheesed\r" "cheesed in /proc/1"
 await_exact "mouse:~# " "the prompt after the PID 1 check"
 
+send -- "cat /usr/lib/rc/version\r"
+await_exact "0.63.3\r" "the pinned OpenRC release identity"
+await_exact "mouse:~# " "the prompt after the OpenRC version check"
+
 send -- "sh -c 'test -f /run/mouse-ready.started'; echo READY_\$status\r"
 await_exact "READY_0\r" "the required service marker"
 await_exact "mouse:~# " "the prompt after the required service check"
@@ -91,7 +95,7 @@
     await_exact "status: started" "supervise-daemon service status"
     await_exact "mouse:~# " "the prompt after service status"
 
-    send -- "sh -c 'old_child=`cat /run/openrc/options/mouse_optional/child_pid`; kill -TERM \"\$old_child\"; sleep 3; new_child=`cat /run/openrc/options/mouse_optional/child_pid`; test \"\$old_child\" != \"\$new_child\"'; echo RESPAWN_\$status\r"
+    send -- "sh -c 'old_child=`cat /run/openrc/options/mouse_optional/child_pid`; kill -KILL \"\$old_child\"; sleep 3; new_child=`cat /run/openrc/options/mouse_optional/child_pid`; test \"\$old_child\" != \"\$new_child\"'; echo RESPAWN_\$status\r"
     await_exact "RESPAWN_0\r" "supervise-daemon replacing a terminated child"
     await_exact "mouse:~# " "the prompt after the respawn check"
 

scripts/check-c2.exp

Mode 100755; object 611947eec58e

@@ -1,0 +1,92 @@
+#!/usr/bin/expect -f
+
+if {$argc != 1} {
+    puts stderr "usage: check-c2.exp RUNNER"
+    exit 2
+}
+
+set runner [file normalize [lindex $argv 0]]
+set timeout 45
+
+proc fail {message} {
+    puts stderr "C2 check failed: $message"
+    exit 1
+}
+
+proc await_exact {text description} {
+    expect {
+        -exact $text {
+            return
+        }
+        timeout {
+            fail "timed out waiting for $description"
+        }
+        eof {
+            fail "QEMU exited while waiting for $description"
+        }
+    }
+}
+
+proc await_clean_exit {action} {
+    expect {
+        eof {
+            set result [wait]
+            set status [lindex $result 3]
+            if {$status != 0} {
+                fail "QEMU exited with status $status after $action"
+            }
+        }
+        timeout {
+            fail "QEMU did not exit after $action"
+        }
+    }
+}
+
+spawn -noecho $runner
+await_exact "cheesed: C1 bootstrap complete; cheesed is PID 1" "PID 1 confirmation"
+await_exact "cheesed: enabled optional services: mouse_optional" "enabled-service policy"
+await_exact "cheesed: OpenRC default transition complete" "the default transition"
+await_exact "mouse:~# " "the tcsh prompt"
+
+send -- "sh -c 'i=0; while \[ \"\$i\" -lt 4 \]; do child=`cat /run/openrc/options/mouse_optional/child_pid`; kill -KILL \"\$child\"; i=\$((i + 1)); sleep 1; done'; echo EXHAUST_\$status\r"
+await_exact "EXHAUST_0\r" "four supervised crashes"
+await_exact "mouse:~# " "the prompt after exhausting respawns"
+
+send -- "service mouse_optional status; echo FAILED_STATUS_\$status\r"
+await_exact "status: failed" "the failed service status"
+await_exact "FAILED_STATUS_32\r" "the failed status exit code"
+await_exact "mouse:~# " "the prompt after failed status"
+
+send -- "sh -c 'test -e /run/openrc/failed/mouse_optional'; echo FAILED_MARKER_\$status\r"
+await_exact "FAILED_MARKER_0\r" "OpenRC's failed-state marker"
+await_exact "mouse:~# " "the prompt after the failed marker"
+
+send -- "service mouse_optional restart\r"
+await_exact "Starting mouse_optional" "administrative recovery"
+await_exact "mouse:~# " "the prompt after administrative recovery"
+send -- "service mouse_optional status\r"
+await_exact "status: started" "started status after recovery"
+await_exact "mouse:~# " "the prompt after recovered status"
+send -- "sh -c 'test ! -e /run/openrc/failed/mouse_optional'; echo RECOVERED_\$status\r"
+await_exact "RECOVERED_0\r" "the cleared failed state"
+await_exact "mouse:~# " "the prompt after the recovery-state check"
+
+send -- "set stubborn=`cat /run/openrc/options/mouse_optional/child_pid`; service mouse_optional stop\r"
+await_exact "Stopping mouse_optional" "the forced runtime stop"
+await_exact "mouse:~# " "the prompt after the forced runtime stop"
+send -- "sh -c 'test -f /run/mouse-c2-daemon.term'; echo TERM_SEEN_\$status\r"
+await_exact "TERM_SEEN_0\r" "the daemon observing and ignoring SIGTERM"
+await_exact "mouse:~# " "the prompt after the SIGTERM marker check"
+send -- "sh -c '! kill -0 \"\$1\" 2>/dev/null' sh \"\$stubborn\"; echo FORCED_GONE_\$status\r"
+await_exact "FORCED_GONE_0\r" "supervise-daemon escalating to SIGKILL"
+await_exact "mouse:~# " "the prompt after forced termination"
+
+send -- "service mouse_optional start\r"
+await_exact "Starting mouse_optional" "the final runtime start"
+await_exact "mouse:~# " "the prompt after the final runtime start"
+send -- "kill -TERM 1\r"
+await_exact "cheesed: received poweroff request" "the poweroff request"
+await_exact "cheesed: OpenRC shutdown transition complete" "the shutdown transition"
+await_clean_exit "poweroff"
+
+puts "C2 QEMU supervision checks passed"

scripts/check-c2.sh

Mode 100755; object 5745b1f8d219

@@ -1,0 +1,7 @@
+#!/bin/sh
+set -eu
+
+script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+
+"$script_dir/check-c1.sh"
+"$script_dir/check-c2.exp" "$script_dir/run-qemu.sh"

support/mouse-c2-daemon.c

Mode 100644; object 81fea5db201d

@@ -1,0 +1,41 @@
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+static const char ready_path[] = "/run/mouse-c2-daemon.ready";
+static const char term_path[] = "/run/mouse-c2-daemon.term";
+
+static void write_marker(const char *path, const char *contents, size_t length)
+{
+	int descriptor = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
+	if (descriptor == -1)
+		return;
+	(void)write(descriptor, contents, length);
+	(void)close(descriptor);
+}
+
+static void handle_term(int signal_number)
+{
+	static const char marker[] = "SIGTERM\n";
+
+	(void)signal_number;
+	write_marker(term_path, marker, sizeof(marker) - 1);
+}
+
+int main(void)
+{
+	static const char marker[] = "ready\n";
+	struct sigaction action = {
+		.sa_handler = handle_term,
+	};
+
+	if (sigemptyset(&action.sa_mask) == -1)
+		return 1;
+	if (sigaction(SIGTERM, &action, NULL) == -1)
+		return 1;
+	write_marker(ready_path, marker, sizeof(marker) - 1);
+
+	for (;;)
+		pause();
+}