nilmbuntu/enter.sh

139 lines
3.9 KiB
Bash
Executable File

#!/bin/bash
# make sure this was run as root
if [ $UID -ne 0 ] ; then
echo "Need to be root; trying sudo"
exec sudo env BUILD_CONFIG=$BUILD_CONFIG $0 "$@"
fi
. config || exit 0
# Spawn a systemd container that boots the machine, then run the given
# command. We can't execute systemd-nspawn directly, because that
# only allows us to either boot the machine, or run a command (not
# both). Instead let's execute systemd-nspawn in a transient systemd
# unit, then enter it using machinectl.
UNIT=nilmbuntu-run-$NONPRIV_UID-$VERSION
MACH=nilmbuntu-$NONPRIV_UID-$VERSION
setup_networking() {
# We use a virtual ethernet adapter -- this requires that
# systemd-networkd is installed and running on the host.
if ! systemctl is-active systemd-networkd ; then
echo "Starting systemd-networkd"
systemctl start systemd-networkd
fi
# However, the current systemd-networkd from Debian is broken and
# won't enable masquerading -- so do it manually
# IFACE=$(ip -4 route list default | head -1 | awk '{print $5}')
# echo 1 > /proc/sys/net/ipv4/ip_forward
# iptables -t nat -D POSTROUTING -o $IFACE -j MASQUERADE >/dev/null || true
# iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE
}
kill_container() {
# Kill any running container
if systemctl --quiet is-active $UNIT ; then
echo "Stopping container..."
# We could use "machinectl terminate", but that will wait
# for a clean shutdown or timeout; we don't need a clean
# shutdown, so send a SIGTERM twice to get systemd-nspawn
# to terminate pretty quickly
systemctl kill $UNIT
sleep 2
systemctl kill $UNIT
# Then wait for it to really stop
systemctl stop $UNIT
fi
# If systemd-nspawn returned with a failure code,
# the transient service unit file will stick around,
# so make sure we clear that.
if systemctl --quiet is-failed $UNIT ; then
systemctl reset-failed $UNIT
fi
}
start_container() {
kill_container
echo "Starting container..."
systemd-run --unit=$UNIT systemd-nspawn \
--quiet \
--keep-unit \
--boot \
--network-veth \
--directory $(realpath $FS) \
--machine $MACH
echo "Waiting..."
while ! env SYSTEMD_LOG_LEVEL=0 machinectl shell $MACH /bin/true ; do
sleep 0.1
done
}
FAILED=0
run() {
# Run a command inside the container
echo "+" "$1"
# machinectl doesn't propagate return codes, so append something
# to the command that saves the result of what we ran.
echo "99" > $FS/jim-cmd-result
CMD="$1 ; echo \$? > /jim-cmd-result"
# Run it
env SYSTEMD_LOG_LEVEL=notice machinectl \
shell $MACH /usr/bin/env IN_CHROOT=1 \
bash -c "$CMD"
# Check result
RET=$(cat $FS/jim-cmd-result)
rm -f $FS/jim-cmd-result
if [ $RET -ne 0 ] && [ "$1" != "exec bash" ] ; then
printf "%s\n" "----------- WARNING: failed with exit code $RET"
FAILED=$RET
sleep 5
fi
}
set -e
rsync -avP --delete files/ ${FS}/root/files/
setup_networking
start_container
run "cat /etc/hosts.nilm >>/etc/hosts 2>/dev/null || true"
run "hostnamectl --transient set-hostname nilmbuntu"
set +e
if [ -z "$1" ] ; then
run "exec bash"
else
run "$1"
fi
echo "Cleaning up..."
# Manually clean up some things that show up after booting an image
# and installing packages. This doesn't get everything, but what's
# left should be fine.
run "apt clean"
run "dpkg --clear-avail"
run "> /etc/machine-id"
run "rm -f /core /boot/grub/grubenv"
run "rm -f /var/lib/systemd/random-seed"
run "rm -f /var/lib/ubuntu-drivers-common/last_gfx_boot"
run "rm -f /var/lib/NetworkManager/*"
run "rm -f /root/.bash_history"
run "rm -rf /root/files"
kill_container
echo "Done"
if [ $FAILED -ne 0 ] ; then
exit $FAILED
fi
exit 0