diff options
Diffstat (limited to 'debian/tests/utils/init')
-rwxr-xr-x | debian/tests/utils/init | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/debian/tests/utils/init b/debian/tests/utils/init new file mode 100755 index 0000000..331cd6f --- /dev/null +++ b/debian/tests/utils/init @@ -0,0 +1,273 @@ +#!/bin/sh + +# PID1 at initramfs stage +# +# Copyright © 2021-2022 Guilhem Moulin <guilhem@debian.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -eux +PATH="/usr/sbin:/usr/bin:/sbin:/bin" +export PATH + +trap "echo \"ALERT! Couldn't setup system, dropping to a shell.\" >&2; sh -i" 0 + +# set VT100 autowrap mode again (QEMU might mess the terminal up) +printf '\033[?7h' + +mount -t devtmpfs -o noexec,nosuid,mode=0755 udev /dev + +mkdir /dev/pts /proc /run /sys +mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts +mount -t proc -o nodev,noexec,nosuid proc /proc +mount -t tmpfs -o nodev,noexec,nosuid,size=5%,mode=0755 tmpfs /run +mount -t sysfs -o nodev,noexec,nosuid sysfs /sys + +modprobe virtio_rng # /dev/hwrng (avoid entropy starvation) +modprobe virtio_pci +modprobe virtio_blk # /dev/vd[a-z] +modprobe virtio_console # /dev/hvc[0-7] + +# start udevd +/lib/systemd/systemd-udevd --daemon +udevadm trigger --type=subsystems --action=add +udevadm trigger --type=devices --action=add +udevadm settle + +. /init.conf + +# https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs +GUID_TYPE_MBR="024DEE41-33E7-11D3-9D69-0008C781F39F" # MBR partition scheme +GUID_TYPE_EFI="C12A7328-F81F-11D2-BA4B-00A0C93EC93B" # EFI boot partition +GUID_TYPE_BIOS_boot="21686148-6449-6E6F-744E-656564454649" # BIOS boot partition +GUID_TYPE_Linux_FS="0FC63DAF-8483-4772-8E79-3D69D8477DE4" # Linux filesystem data +GUID_TYPE_LUKS="CA7D7CCB-63ED-4C53-861C-1742536059CC" # LUKS partition +GUID_TYPE_DMCRYPT="7FFEC5C9-2D00-49B7-8941-3EA10A5586B7" # Plain dm-crypt partition +GUID_TYPE_LVM="E6D6D379-F507-44C2-A23C-238F2A3DF928" # Logical Volume Manager partition +GUID_TYPE_RAID="A19D880F-05FC-4D3B-A006-743F0F84911E" # RAID partition + +if [ "$BOOT" = "bios" ]; then + BOOT_PARTITION_SIZE=2 + BOOT_PARTITION_TYPE="$GUID_TYPE_BIOS_boot" +elif [ "$BOOT" = "efi" ]; then + BOOT_PARTITION_SIZE=63 + BOOT_PARTITION_TYPE="$GUID_TYPE_EFI" +else + echo "ERROR unknown boot method '$BOOT'" >&2 + exit 1 +fi + +# format the target disk and create a BIOS/EFI partition +sfdisk /dev/vda <<-EOF + label: gpt + unit: sectors + + start=$((1024*2)), size=$((BOOT_PARTITION_SIZE*1024*2)), type=$BOOT_PARTITION_TYPE +EOF +udevadm settle + +ROOT="/target" +mkdir -m0755 "$ROOT" +# /init.setup is expected to create the root filesystem of the target +# system and mount it (alongside other filesystems) on $ROOT +. /init.setup +udevadm settle + +# inspired by debootstrap's /usr/share/debootstrap/functions +if [ "$MERGED_USR" = "yes" ]; then + case "$ARCH" in + amd64) libdir="lib32 lib64 libx32";; + i386) libdir="lib64 libx32";; + mips|mipsel) libdir="lib32 lib64";; + mips64*|mipsn32*) libdir="lib32 lib64 libo32";; + loongarch64*) libdir="lib32 lib64";; + powerpc) libdir="lib64";; + ppc64) libdir="lib32 lib64";; + ppc64el) libdir="lib64";; + s390x) libdir="lib32";; + sparc) libdir="lib64";; + sparc64) libdir="lib32 lib64";; + x32) libdir="lib32 lib64 libx32";; + *) libdir="";; + esac + for dir in bin sbin lib $libdir; do + ln -s "usr/$dir" "$ROOT/$dir" + mkdir -p "$ROOT/usr/$dir" + done +fi + +mkdir /media +DEBIAN_DIST="$(blkid -l -t LABEL="debian_dist" -o device)" +mount -t ext2 -o ro "$DEBIAN_DIST" /media +for pkg in /media/__stage1__/*.deb; do + dpkg-deb --fsys-tarfile "$pkg" | tar -C "$ROOT" -xf - --keep-directory-symlink +done + +# setup hosts(5) and hostname(5) +echo "$HOSTNAME" >"$ROOT/etc/hostname" +echo "127.0.0.1 localhost $HOSTNAME" >"$ROOT/etc/hosts" + +# EFI +if [ "$BOOT" = "efi" ]; then + modprobe efivarfs + mount -t efivarfs efivarfs /sys/firmware/efi/efivars + + mkfs.vfat -F 32 /dev/vda1 + mkdir "$ROOT/boot/efi" + mount -t vfat /dev/vda1 "$ROOT/boot/efi" + + cat >>"$ROOT/etc/fstab" <<-EOF + UUID=$(blkid -s UUID -o value /dev/vda1) /boot/efi auto defaults 0 2 + EOF +fi + +# bind mount pseudo and temporary filesystems to "$ROOT" +mount -no bind /dev "$ROOT/dev" +mount -no bind /proc "$ROOT/proc" +mount -no bind /sys "$ROOT/sys" +mount -t tmpfs -o nodev,noexec,nosuid,size=5%,mode=0755 tmpfs "$ROOT/run" + +# prevent any services from starting during package installation, taken +# from debootstrap(8) +cat >"$ROOT/usr/sbin/policy-rc.d" <<-EOF + #!/bin/sh + exit 101 +EOF +chmod +x "$ROOT/usr/sbin/policy-rc.d" + +mv "$ROOT/sbin/start-stop-daemon" "$ROOT/sbin/start-stop-daemon.REAL" +cat >"$ROOT/sbin/start-stop-daemon" <<-EOF + #!/bin/sh + echo + echo "Warning: Fake start-stop-daemon called, doing nothing" +EOF +chmod +x "$ROOT/usr/sbin/policy-rc.d" "$ROOT/sbin/start-stop-daemon" + +DEBIAN_FRONTEND="noninteractive" +DEBCONF_NONINTERACTIVE_SEEN="true" +export DEBIAN_FRONTEND DEBCONF_NONINTERACTIVE_SEEN + +# debootstrap the target system +mkdir "$ROOT/media" +mount -no move /media "$ROOT/media" +cp -p /debootstrap "$ROOT/debootstrap" +chroot "$ROOT" /debootstrap +rm -f "$ROOT/debootstrap" + +# use MODULES=dep (if it works with fewer modules then it also works +# with the default MODULES=most) +mkdir -p "$ROOT/etc/initramfs-tools/conf.d" +echo "MODULES=dep" >"$ROOT/etc/initramfs-tools/conf.d/modules" + +cp /init.preinst "$ROOT/init.preinst" +chroot "$ROOT" /bin/sh -eux /init.preinst +rm -f "$ROOT/init.preinst" +udevadm settle + +# install extra packages +chroot "$ROOT" apt-get -oAPT::Sandbox::User="root" install --yes $PACKAGES +rm -f "$ROOT/etc/apt/sources.list" + +# configure and install GRUB +cat >"$ROOT/etc/default/grub" <<-EOF + GRUB_DEFAULT=0 + GRUB_TIMEOUT=0 + GRUB_CMDLINE_LINUX_DEFAULT="" + GRUB_CMDLINE_LINUX="console=$CONSOLE,115200n8" + GRUB_DISABLE_RECOVERY=true + GRUB_TERMINAL="console serial" + GRUB_SERIAL_COMMAND="serial --speed=115200" +EOF +chroot "$ROOT" grub-install --no-floppy --modules=part_gpt /dev/vda +chroot "$ROOT" update-grub + +chroot "$ROOT" passwd --delete root # make root account passwordless + +# show some system info right after login to ease troubleshooting +cat >"$ROOT/root/.profile" <<-EOF + run_verbose() { + printf "\\\`%s\\\` output:\\\\n" "\$*" + "\$@" + } + stty cols 150 + run_verbose dmsetup table + run_verbose lsblk + run_verbose df -h +EOF + +cat >"$ROOT/root/.inputrc" <<-EOF + # disabled bracketed paste mode + set enable-bracketed-paste off +EOF + +if [ -d "$ROOT/etc/systemd/system" ]; then + # systemd + if [ -c "$ROOT/dev/hvc0" ]; then + # serial-getty@ttyS0.service is automatically enabled due to the console= kernel parameter + ln -s "/dev/null" "$ROOT/etc/systemd/system/serial-getty@ttyS0.service" + ln -s "/lib/systemd/system/serial-getty@.service" \ + "$ROOT/etc/systemd/system/getty.target.wants/serial-getty@hvc0.service" + fi + + # mask all timer units + for t in "$ROOT"/lib/systemd/system/*.timer; do + test -f "$t" || continue + ln -s "/dev/null" "$ROOT/etc/systemd/system/${t##*/}" + done + + # mask systemd-firstboot.service + ln -s "/dev/null" "/root/etc/systemd/system/systemd-firstboot.service" +fi + +if [ -f "$ROOT/etc/inittab" ]; then + # sysvinit + if [ -c "$ROOT/dev/hvc0" ]; then + echo "h0:2345:respawn:/sbin/agetty -8 -L 115200 hvc0 linux" + else + echo "S0:23:respawn:/sbin/getty -8 -L 115200 $CONSOLE linux" + fi >>"$ROOT/etc/inittab" +fi + +if [ -f /init.postinst ]; then + cp /init.postinst "$ROOT/init.postinst" + chroot "$ROOT" /bin/sh -eux /init.postinst + rm -f "$ROOT/init.postinst" +fi + +# allow service startup again +mv "$ROOT/sbin/start-stop-daemon.REAL" "$ROOT/sbin/start-stop-daemon" +rm "$ROOT/usr/sbin/policy-rc.d" + +# unmount pseudo filesystems from the target system +umount "$ROOT/dev" +umount "$ROOT/proc" +umount "$ROOT/sys" + +if [ "$BOOT" = "efi" ]; then + umount "$ROOT/boot/efi" +fi +umount "$ROOT/media" +umount "$ROOT/run" + +# /init.bottom is expected to umount $ROOT and its submounts +ROOT="$ROOT" sh -eux /init.bottom + +# stop udevd +udevadm control --exit + +# exiting this script yields "Kernel panic - not syncing: Attempted to +# kill init!", so give the asyncronous SysRq trigger a chance to power +# off (sending a racy C-d would still trigger a panic but we don't care) +echo o >/proc/sysrq-trigger +exec cat >/dev/null |