tarting subhost almost as if booted
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Thu, 3 Mar 2022 04:47:50 +0000 (15:47 +1100)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Thu, 3 Mar 2022 04:47:50 +0000 (15:47 +1100)
pretend-boot [new file with mode: 0755]
startup [deleted file]
subhost-init [new file with mode: 0755]

diff --git a/pretend-boot b/pretend-boot
new file mode 100755 (executable)
index 0000000..1eaf034
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/bash
+#
+# Boot up subhost as if a vitual machine.
+#
+# There is already an existing network namespace of the right name,
+# and there are one or more disks at /opt/subhost/$NAME/disk$i
+
+#set -x
+
+: ${NAME=$1}
+: ${NSNAME=$NAME}
+: ${SUBHOST=/opt/subhost/$NAME}
+: ${TARGET=$SUBHOST/live}
+: ${INITRD=$SUBHOST/initrd.gz}
+: ${CONFIG=$SUBHOST/config}
+
+[ -r "$CONFIG" ] && . $CONFIG
+
+# Generate a mac address for given arguments pass through 40-bit b2sum
+# and with 02: prefix.
+macaddr() {
+    local V="$(b2sum -l 40 <<< "$*" )"
+    V="$( sed 's/\(..\)/\1:/g' <<< "${V}aaaaaaaaaa")"
+    echo "02:${V:0:14}"
+}
+
+# Setup the subhost network namespace and link up the host side
+setup_cables() {
+    E=0
+    [ -e /var/run/netns/$NSNAME ] || ip netns add $NSNAME
+    for BRIDGE in ${BRIDGES[@]} ; do
+       IF=$NAME$E
+       B=( ${BRIDGE/:/ } )
+       BRIDGE="${B[0]}"
+       MAC="${B[1]}"
+       [ -z "$MAC" ] && MAC="$(macaddr "$(hostname)" "$NAME" "$IF")"
+       brctl show $BRIDGE >& /dev/null || brctl addbr $BRIDGE
+       ip link add $IF type veth peer name eth$E address $MAC netns $NSNAME 
+       ip link set $IF up
+       [ -n "$BRIDGE" ] && brctl addif $BRIDGE $IF
+       E=$((E+1))
+    done
+}
+
+# loopdev path -- Make a named device node for a loop device
+copyloop() {
+    local MKNOD="mknod $(basename $2) b $(stat -c "%t %T" $1)"
+    if [ -e "$2" ] ; then
+       rm -f $2
+    else
+       mkdir -p $(dirname $2)
+    fi
+    ( cd $(dirname $2) && $MKNOD )
+}
+
+# diskid image partition# -- set up parition device node
+mkdevnode() {
+    local LOOP="$(losetup -j "$3" | sed 's/:.*//')"
+    [ -z "$LOOP" ] && LOOP="$(losetup -f --show "$3")"
+    grep -q $TARGET /proc/mounts || \
+       mount ${LOOP}p$2 $TARGET
+    copyloop $LOOP $TARGET/dev/$1
+    copyloop ${LOOP}p$2 $TARGET/dev/$1$2
+}
+
+# Setup device nodes for VM loopbacks according to $DISKS
+setup_rootfs() {
+    for DISK in ${DISKS[@]} ; do
+       D=( $(echo $DISK | tr : ' ') )
+       case "${D[0]}" in
+           vd*|sd*)
+               mkdevnode "${D[@]}"
+               ;;
+           *)
+               echo "Unknown disk type ${D[0]}" >&2
+               exit 1
+               ;;
+       esac
+    done
+}
+
+# Change $TARGET/dev/console 
+setup_console() {
+    local SCRIPT=$$
+    CONSOLE=$TARGET/dev/console
+    rm -f $CONSOLE
+    ln -s $(tty) $CONSOLE
+}
+
+setup_cables
+setup_rootfs
+setup_console || exit 1
+
+# Install the current subhost-init startup script
+cp -p $(realpath $(dirname $0))/subhost-init startup $TARGET/
+
+######################################################################
+# Run the subhost
+ip netns exec $NSNAME unshare --fork --pid --mount-proc --kill-child \
+     --uts --ipc --mount --cgroup chroot $TARGET /startup
+######################################################################
+
+# Cleanup on exit
+umount $TARGET
+ip netns del $NSNAME
+true
diff --git a/startup b/startup
deleted file mode 100755 (executable)
index dd07b98..0000000
--- a/startup
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-#
-# This is a script to run at startup of a bespoke sub-host
-
-NOW=$(date +"%Y%m%d-%H%M%S")
-
-{
-    echo "Startup at $NOW"
-    set -x
-    
-    mkdir -p /dev/pts /dev/shm /run
-    [ -f /proc/mounts ] || mount -t proc proc /proc
-    if ! grep "^none /run tmpfs" /proc/mounts ; then
-       mount -t tmpfs -osize=80M none /run
-       mount -t tmpfs -osize=20M none /dev/shm
-       mount -t devpts none /dev/pts
-       mount -t sysfs none /sys
-       mkdir -p /run/lock /run/user
-    fi
-    
-    {
-       # Restart auto interfaces
-       for IF in $(grep "^auto" /etc/network/interfaces) ; do
-           [ -e "/sys/class/net/$IF" ] || continue
-           ifdown $IF
-           ifup $IF
-       done
-    
-       # Restart services
-       SERVICES=( )
-       for S in ${SERVICES[@]} ; do
-           service $S restart
-       done
-    } &
-    NETPID=$!
-
-} |& tee /var/log/startup-$NOW.log
-
-exec /bin/bash
diff --git a/subhost-init b/subhost-init
new file mode 100755 (executable)
index 0000000..6fbb25d
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# This is a script to run at startup of a bespoke sub-host
+
+date +"subhost startup at %Y%m%d-%H%M%S"
+    
+mkdir -p /dev/pts /dev/shm /run
+[ -f /proc/mounts ] || mount -t proc proc /proc
+if ! grep "^none /run tmpfs" /proc/mounts ; then
+    mount -t tmpfs -osize=80M none /run
+    mount -t tmpfs -osize=20M none /dev/shm
+    mount -t devpts none /dev/pts
+    mount -t sysfs none /sys
+    mkdir -p /run/lock /run/user
+fi
+
+if grep -q ' / ext4 rw,' /proc/mounts ; then
+    ##
+    ## Here's the "pretend init"
+    ##
+
+    zombie() {
+       wait
+       true # echo "zombie return $?" >&2
+    }
+    trap "zombie" 17 # SIGCHILD 
+
+    /etc/init.d/rc S < /dev/null
+    /etc/init.d/rc 2 < /dev/null
+    SUBHOSTCTL=/run/initctl
+    mkfifo $SUBHOSTCTL
+    exec cat < $SUBHOSTCTL
+    #exec /bin/bash -i
+else
+    echo "** The root filesystem is read-only; EXITING" >&2
+    exit 1
+fi