#!/bin/busybox sh
# The disk form's first process: mounts the root filesystem the computer's image became, brings up the network, reads
# the image's start (/etc/agentenv/vm/image.env, from its OCI config) and the deploy's environment (the NoCloud seed's
# user-data), then becomes that start, as its user, as the container runtime would: PID 1 is the image's entrypoint.
# As a container finds this machine at host.docker.internal, it finds the launcher at QEMU's address for it, which
# forwards a local grant server's port, and trusts the local transfer CA the seed carries, as a container does.
/bin/busybox --install -s /bin
export PATH=/bin
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
log() { echo "agentenv-init: $*" > /dev/console; }
fail() { log "$*"; sleep 2; poweroff -f; }
. /seed-env
while read -r module; do insmod "$module" 2>/dev/null; done < /modules.order
root=""
for _ in $(seq 200); do root=$(findfs LABEL=agentenv-root 2>/dev/null) && break; sleep 0.05; done
[ -n "$root" ] || fail "no filesystem labelled agentenv-root"
mount -t ext4 -o rw,noatime "$root" /newroot || fail "can't mount $root"
ifconfig lo 127.0.0.1 up
iface=$(ls /sys/class/net | grep -vx lo | head -n 1)
[ -n "$iface" ] && ifconfig "$iface" up && timeout 30 udhcpc -i "$iface" -s /udhcpc.script -q -n -t 10 -T 2 -f >/dev/null 2>&1 \
    || log "no DHCP lease on ${iface:-any interface}"
seed=$(findfs LABEL=CIDATA 2>/dev/null || true)
[ -n "$seed" ] && mount -o ro "$seed" /seed
config=/newroot/etc/agentenv/vm/image.env
[ -f "$config" ] || fail "the root filesystem has no $config"
for name in $(env | cut -d= -f1); do case "$name" in PATH|PWD|SHLVL) ;; *) unset "$name" ;; esac; done
user=root workdir=/
set --
while read -r line; do
    key=${line%%=*} value=${line#*=}
    case "$key" in
        env) decode "$value"; export "$decoded" ;;
        argv) decode "$value"; set -- "$@" "$decoded" ;;
        user) decode "$value"; user=$decoded ;;
        workdir) decode "$value"; workdir=$decoded ;;
    esac
done < "$config"
if [ -f /seed/trust/ca-bundle.pem ]; then
    cp /seed/trust/ca-bundle.pem /seed/trust/ca.pem /newroot/etc/agentenv/ || fail "can't copy the seed's trust files"
    export SSL_CERT_FILE=/etc/agentenv/ca-bundle.pem REQUESTS_CA_BUNDLE=/etc/agentenv/ca-bundle.pem \
        NODE_EXTRA_CA_CERTS=/etc/agentenv/ca.pem
fi
[ -n "$seed" ] && { seed_environment /seed || fail "$refused"; }
hostname=$( [ -f /seed/meta-data ] && sed -n 's/^local-hostname: *//p' /seed/meta-data)
hostname "${hostname:-computer}"
hostname > /newroot/etc/hostname
printf '127.0.0.1\tlocalhost\n::1\tlocalhost ip6-localhost ip6-loopback\n127.0.1.1\t%s\n10.0.2.2\thost.docker.internal\n' \
    "$(hostname)" > /newroot/etc/hosts
[ -s /resolv.conf ] && cp /resolv.conf /newroot/etc/resolv.conf
entry=$(awk -F: -v u="${user%%:*}" '$1 == u || $3 == u' /newroot/etc/passwd | head -n 1)
[ -n "$entry" ] || fail "the image's user ${user%%:*} isn't in /etc/passwd"
uid=$(echo "$entry" | cut -d: -f3) gid=$(echo "$entry" | cut -d: -f4)
export HOME="${HOME:-$(echo "$entry" | cut -d: -f6)}" HOSTNAME="$(hostname)"
[ "$PATH" = /bin ] && export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
umount /seed 2>/dev/null
[ "$#" -gt 0 ] || fail "the image names no command"
mount --move /sys /newroot/sys
mount --move /dev /newroot/dev
mkdir -p /newroot/dev/pts /newroot/dev/shm
mount -t devpts -o gid=5,mode=620,ptmxmode=666 devpts /newroot/dev/pts
# /dev/shm holds what the computer's apps need (AGENTENV_SHM_MB, in MiB) when the deploy says, else 512 MiB.
case "$AGENTENV_SHM_MB" in ''|0|*[!0-9]*) shm_mb=512 ;; *) shm_mb=$AGENTENV_SHM_MB ;; esac
unset AGENTENV_SHM_MB
mount -t tmpfs -o mode=1777,size="${shm_mb}m" shm /newroot/dev/shm
log "starting $* as $user ($uid:$gid) in $workdir"
# Last, as busybox runs its applets through /proc/self/exe.
mount --move /proc /newroot/proc
exec /bin/busybox switch_root /newroot /usr/bin/setpriv --reuid="$uid" --regid="$gid" --init-groups \
    /usr/bin/env -C "$workdir" "$@"
