#! /usr/bin/env bash # Bootstrap build2 buildos. # # Assumptions/expectations: # # - host debootstrap/debian-archive-keyring matching release # # - /btrfs/ is a btrfs directory where the current user can create # snapshots # # - sudo is passwordless (used to run debootstrap, systemd-nspawn, etc) # # Options: # # --stage # Jump straigh to stage by clonning the previous stage snapshot. # Stages are: # # 1 - bootstrap phase 1 # 2 - bootstrap phase 2 # 3 - setup # 4 - create footfs # 5 - create kernel image and initrd # usage="usage: $0" id="$(id -un)" btrfs=/btrfs release="unstable" mirror="https://deb.debian.org/debian/" passwd="123" #@@ TMP root passwd. macaddr="de:ad:be:ef:b8:da" # Mac address for testing. root="$btrfs/$id/buildos" owd="$(pwd)" trap "{ cd '$owd'; exit 1; }" ERR set -o errtrace # Trap in functions. function info () { echo "$*" 1>&2; } function error () { info "$*"; exit 1; } stage="1" stage_max="5" while [ "$#" -gt 0 ]; do case "$1" in --stage) shift stage="$1" shift ;; -*) error "unknown option: $1" ;; *) break ;; esac done if [ "$stage" -lt "1" -o "$stage" -gt "$stage_max" ]; then error "invalid stage number $stage" fi # Btrfs subvolume manipulation. # function subvol_delete () # { # The subvol show (just as list) needs root. # if sudo btrfs subvol show "$1" 1>/dev/null 2>&1; then btrfs property set -ts "$1" ro false btrfs subvol delete "$1" fi } function subvol_create () # { btrfs subvol create "$@" } function subvol_snapshot () # [-r] { btrfs subvol snapshot "$@" } # Clean up the working subvolume and all the snapshots starting from the # requested stage. Also, if stage is not 1, then restore the working subvolume # from the previous stage snapshot. # subvol_delete "$root" for i in $(seq "$stage" "$stage_max"); do subvol_delete "$root-$i" done if [ "$stage" -gt "1" ]; then i="$(($stage - 1))" info "restoring working subvolume from stage $i snapshot" subvol_snapshot "$root-$i" "$root" fi # Spawn a systemd namespace container (systemd-nspawn) # function nspawn () # { sudo systemd-nspawn --register=no -D "$root" "$@" # systemd-nspawn may create the /var/lib/machines subvolume which prevents # the deletion of the containing submodule. So we clean it up. # if sudo btrfs subvol show "$root/var/lib/machines" 1>/dev/null 2>&1; then sudo btrfs subvol delete "$root/var/lib/machines" fi } # (Over)write or append to a file in the installation root, for example: # # write <<<'localhost' /etc/hostname # function write () # { sudo tee "$root$1" >/dev/null } function append () # { sudo tee -a "$root$1" >/dev/null } # Stage 1: debootstrap, phase 1. # if [ "$stage" -eq "1" ]; then subvol_create "$root" # Notes: # # - systemd-container seems to be required by host systemd-nspawn. # pkgs="locales,systemd-container" pkgs+=",linux-image-amd64,irqbalance,pciutils" pkgs+=",hdparm,btrfs-progs" pkgs+=",net-tools,iproute2,iptables,isc-dhcp-client" pkgs+=",ifupdown,bridge-utils,dnsmasq,ntp" pkgs+=",iputils-ping,wget,curl" pkgs+=",less" sudo debootstrap \ --foreign \ --arch=amd64 \ --merged-usr \ --variant=minbase \ --include="$pkgs" \ "$release" "$root" "$mirror" # Post-phase 1 fixups. # # Set the initial hostname to '(none)'. This value is detected and # overriden by /sbin/dhclient-script if the DHCP server sends host-name. # write <<<'(none)' /etc/hostname # Set timezone to UTC (picked up by tzdata package during stage 2). # write <<<'Etc/UTC' /etc/timezone subvol_snapshot -r "$root" "$root-1" fi # Stage 2: debootstrap, phase 2. # if [ "$stage" -le "2" ]; then # Create a bootstrap script that will finish the bootstrap from within the # installation via systemd-nspawn. # sudo mkdir "$root/bootstrap" write </etc/default/locale LANG="en_US.UTF-8" LANGUAGE="en_US:en" EOF1 EOF sudo chmod u+x "$root/bootstrap/bootstrap" # Notes: # # - Failed to create directory .../sys/fs/selinux: Read-only file system is # harmless and fixed upstream (systemd issue#3748). # nspawn /bootstrap/bootstrap subvol_snapshot -r "$root" "$root-2" fi # Stage 3: setup. # if [ "$stage" -le "3" ]; then # Create the setup script/service that will finish the setup from within the # installation via systemd-nspawn --boot. # sudo mkdir -p "$root/bootstrap" write < "$owd/buildos-rootfs.cpio.gz" cd "$owd" subvol_snapshot -r "$root" "$root-4" fi # Stage 5: generate initrd. # if [ "$stage" -le "5" ]; then # @@ TODO: init location # sudo cp -f ./init "$root/" info "generating buildos-init.cpio.gz..." sudo echo 'init' | \ sudo cpio -o -H newc | \ gzip -9 > "$owd/buildos-init.cpio.gz" cat buildos-rootfs.cpio.gz buildos-init.cpio.gz >buildos-initrd # Copy the kernel image next to the initramfs for convenience. # cp "$root/vmlinuz" buildos-image subvol_snapshot -r "$root" "$root-5" fi # Test. # # To test PXE boot, replace -kernel/-initrd with '-boot n'. # sudo kvm \ -m 8G \ -netdev 'tap,id=net0,script=./qemu-ifup' \ -device "e1000,netdev=net0,mac=$macaddr" \ -kernel buildos-image -initrd buildos-initrd