--- /dev/null
+# This file implements common functions for all boot methods
+
+die() {
+ echo "$*" >&2
+ exit 1
+}
+
+# grab and set a configuration variable
+# $1 = variable, [ $2 = default .. error otherwise ]
+config() {
+ eval $1="$(sed "/^$1=.*/{s|^$1=||;b};d" $CONFIG)"
+ [ -z "$(eval echo "\$$1")" ] || return 0
+ [ $# -lt 2 ] && die "Missing $1=... in $CONFIG"
+ eval $1="'$2'"
+ eval echo "$1=\$$1"
+}
+
+# Unless the subhost already has a private /etc/network/interfaces,
+# install an "empty" one
+setup_networking() {
+ [ -r $UPPER/etc/network/interfaces ] && return 0
+ [ "$UPPER/etc/network" = "/etc/network" ] && exit 1
+ mkdir -p $UPPER/etc/network
+ cat <<EOF > $UPPER/etc/network/interfaces
+# Generated for $NAME subhost
+auto lo
+iface lo inet loopback
+EOF
+ return 1
+}
+
+# Setup the network namespace for the given $CABLES
+# $1=netns ( $2="br=mac" .. )
+setup_veth_cables() {
+ local NETNS BR IF MAC C i ADD
+ NETNS="$1"
+ shift 1
+ i=0
+ ADD=false
+ setup_networking || ADD=true
+ for C in "$@" ; do
+ IF=$NETNS$i
+ MAC="${C#*=}"
+ [ -z "$MAC" ] || MAC="address $MAC"
+ ip link add $IF type veth peer name eth$i $MAC netns $NETNS
+ ip link set $IF up
+ $ADD && cat <<EOF >> $UPPER/etc/network/interfaces
+
+auto eth$i
+iface eth$i inet manual
+EOF
+ BR="${C%=*}"
+ [ -z "$BR" ] || brctl addif $BR $IF
+ i=$((i+1))
+ done
+}
+
+REAPER=$(dirname $(realpath $0))/reaper/reaper
+# (name live system root work)
+# Set up an overlay fmr $name on $live, with a new tmpfs on its /run,
+# and "install" a "reaper" as the upcoming pid 1
+setup_overlay() {
+ set -x
+ mkdir -p $4/run
+ mount -t tmpfs -osize=100M tmpfs $4/run
+ mkdir -p $4/run/lock
+ grep -q "$1 $2" /proc/mounts || \
+ mount -t overlay -olowerdir=$3,upperdir=$4,workdir=$5 $1 $2 || \
+ die "Cannot set up the overlay mount $2"
+ mount --bind $4/run $2/run
+ cp $REAPER $LIVE/.reaper
+}
+
+
+# Check if $SRV is "live" ; will
+is_live() {
+ pgrep -f ".reaper $SRV" > /dev/null
+}
+
+start_services() {
+ for S in "$@" ; do
+ service $S start
+ done
+}
--- /dev/null
+#!/bin/sh
+#
+# This boot method runs a service subhost with a root filesystem that
+# is an overlay of the subhost's root and an OS root. The service
+# subhost is defined by a configuration file named on teh command line
+
+[ $(id -u) = 0 ] || exec sudo $0 $@
+
+. $(dirname $(realpath $0))/functions
+
+CONFIG="$1"
+[ -r "$CONFIG" ] || die "Missing configuration $CONFIG"
+
+config NAME $(basename $1 .${1##*.})
+config LOG /tmp/oly-$NAME.log
+
+if [ -z "$UNSHARED" ] ; then
+ # Pre-unsharing:
+ #
+ # Create the network namespace for the subhost, then trigger
+ # detached re-run with unshared mount namespace
+ [ -r /run/netns/$NAME ] || ip netns add $NAME
+ exec env UNSHARED=yes unshare -m $0 $@ > $LOG 2>&1 &
+ echo "Logging to $LOG" >&2
+ exit 0
+fi
+
+config BASE
+config LIVE "$BASE/live"
+config UPPER "$BASE/root"
+config WORK "$BASE/work"
+config LOWER "/"
+config CABLES ""
+config START "networking ssh"
+config SUBSHELL /bin/sh
+config STOP ""
+
+# Setup virtual cabling and subhost's /etc/network/interfaces
+setup_veth_cables $NAME $CABLES
+
+# Set up the mount for this subhost, including a new tmpfs on its /run
+echo setup_overlay "$NAME" "$LIVE" "$LOWER" "$UPPER" "$WORK"
+setup_overlay "$NAME" "$LIVE" "$LOWER" "$UPPER" "$WORK"
+
+exithandler() {
+ ip netns del $NAME
+ umount -R "$LIVE"
+}
+trap "exithandler" 0
+
+CMD="unshare -fp --mount-proc ip netns exec $NAME chroot $LIVE /bin/sh"
+echo "$CMD"
+cat <<EOF | $CMD
+set -x
+mount --bind $UPPER/run /run
+for srv in $START ; do service \$srv start ; done
+exec /.reaper $NAME
+EOF
+echo "EXITED $CMD"
+#echo "$STOP" | ip netns exec $NAME chroot $LIVE $SUBSHELL
--- /dev/null
+#!/bin/sh
+set -x
+X="$(pgrep -f ".reaper $1")"
+grep -q "^proc " /proc/$X/mounts || \
+ sudo nsenter -t "$X" -m -p -r -w mount -t proc proc /proc
+ROOT="$(sudo nsenter -t "$X" -m -p -r -w mount | \
+ awk -v S="$1" '$1==S{print $3;exit;}')"
+sudo nsenter -t "$X" -n -m -p -r -w -u -C /bin/bash