#!/usr/bin/env bash # Copyright (C) 2023 Umorpha Systems # SPDX-License-Identifier: AGPL-3.0-or-later # Dependencies: # - /usr/bin/env (coreutils, busybox) # - cat (coreutils, busybox) # - dd (coreutils, busybox) # - install (coreutils, busybox) # - mkdir (coreutils, busybox) # - mktemp (coreutils, busybox) # - rm (coreutils, busybox) # - rmdir (coreutils, busybox) # - losetup (optional) (util-linux; the busybox one doesn't work) # - umount (util-linux, busybox) # - blkid (util-linux) # - mount (util-linux) # - bash (bash) # - systemd-repart (systemd) # - lvcreate (lvm2) # - pvcreate (lvm2) # - vgchange (lvm2) # - vgcreate (lvm2) # - vgremove (lvm2) # - pv (pv) # - mkfs.ext4 (e2fsprogs) # - mkfs.vfat (dosfstools) # - arch-chroot (arch-install-scripts) # # Dependencies of arch-chroot (as of v28): # - cat (coreutils, busybox) # - install (coreutils, busybox) # - ln (coreutils, busybox) # - touch (coreutils, busybox) # - chroot (coreutils; the busybox one doesn't work) # - readlink (coreutils; the busybox one doesn't work) # - mountpoint (util-linux, busybox) # - umount (util-linux, busybox) # - unshare (util-linux, busybox) # - mount (util-linux) # - grep (grep, busybox) # - bash (bash) # # Of those, these are the ones that aren't already in an initcpio: # - arch-chroot (arch-install-scripts) # - bash (bash) # - chroot (coreutils) # - readlink (coreutils) # - pv (pv) # - systemd-repart (systemd) # - mkfs.ext4 (e2fsprogs) # - mkfs.vfat (dosfstools) # - pvcreate (lvm2) # - vgchange (lvm2) # - vgcreate (lvm2) # - vgremove (lvm2) # - lvcreate (lvm2) set -euE -o pipefail v() { printf >&2 ' $ %s\n' "${*@Q}" "$@" } main() { local typ device rootfs typ=$1 rootfs=$2 device=$3 echo ":: Installing '${rootfs}' to '${device}' for '${typ}'" if [[ "$rootfs" != *rootfs* ]]; then echo >&2 "!! Filename '${rootfs}' does not look like a rootfs filename" return 2 fi case "$typ" in uefi|bios) :;; *) echo >&2 "!! Install type '${typ}' is not valid" return 2 ;; esac ######################################################################## cleanup=() _do_cleanup() { if [[ $? == 0 ]]; then echo "::Cleaning up..." else echo >&2 "!! ERROR! Cleaning up..." fi for (( i=${#cleanup[@]}-1; i >= 0; i-- )); do eval "${cleanup[$i]}" done } trap '_do_cleanup' EXIT local tmpdir tmpdir="$(mktemp -dt "${0##*/}.XXXXXXXXXX")" cleanup+="rmdir -- ${tmpdir@Q}" ######################################################################## local is_loop=false if [[ -f "$device" ]]; then echo " file '${device}' is not a block device, setting up a loopback device..." device=$(v losetup --find --show --partscan -- "$device") echo " ... '${device}'" cleanup+=("v losetup --detach ${device@Q}") is_loop=true fi local devicep="$device" if [[ "$devicep" == *[0-9] ]]; then devicep+='p' fi v vgremove --yes vg_umorpha || true ######################################################################## echo ":: Setting up GPT" dd if=/dev/zero of="$device" bs=512 count=4 n=0 cat >"$tmpdir/00-esp.conf" <<-EOF [Partition] Type=esp Format=vfat Label=Umorpha EFI System Partition SizeMinBytes=512M SizeMaxBytes=512M EOF n_esp=$((++n)) if [[ $typ == bios ]]; then cat >"$tmpdir/05-bios.conf" <<-EOF [Partition] Type=21686148-6449-6E6F-744E-656564454649 Label=Umorpha BIOS Boot Partition SizeMinBytes=1M SizeMaxBytes=1M EOF n_bios=$((++n)) fi cat >"$tmpdir/10-lvm.conf" <<-EOF [Partition] # https://en.wikipedia.org/w/index.php?title=User_talk:Claunia&diff=prev&oldid=1182832243 Type=E6D6D379-F507-44C2-A23C-238F2A3DF928 Label=Umorpha LVM Partition EOF n_lvm=$((++n)) v systemd-repart \ --empty=allow --dry-run=no \ --no-pager \ --definitions="$tmpdir" \ "$device" rm -- "$tmpdir"/*.conf ######################################################################## echo ":: Setting up LVM" v pvcreate "${devicep}${n_lvm}" v vgcreate vg_umorpha "${devicep}${n_lvm}" if $is_loop; then cleanup+=("v vgchange --activate=n vg_umorpha") fi # Use short `-c` instead of `--format` so this works with busybox. v lvcreate --zero=y --wipesignatures=y --yes --name=lv_root_a \ --size="$(stat -c '%s' -- "$rootfs")b" vg_umorpha v pv -- "$rootfs" >/dev/mapper/vg_umorpha-lv_root_a v lvcreate --zero=y --wipesignatures=y --yes \ --name=lv_root_overlay --size=1G vg_umorpha v mkfs.ext4 /dev/mapper/vg_umorpha-lv_root_overlay ######################################################################## echo ":: Configuring boot" local selector_boot selector_root selector_overlay selector_boot="$( blkid --output=export "${devicep}${n_esp}" | grep ^UUID=)" selector_root="$( blkid --output=export /dev/mapper/vg_umorpha-lv_root_a | grep ^UUID=)" selector_overlay="$(blkid --output=export /dev/mapper/vg_umorpha-lv_root_overlay | grep ^UUID=)" v declare -p selector_boot selector_root selector_overlay mkdir "$tmpdir/root" cleanup+=("rmdir -- ${tmpdir@Q}/root") v mount -o ro -- /dev/mapper/vg_umorpha-lv_root_a "$tmpdir/root" cleanup+=("v umount ${tmpdir@Q}/root") mkdir "$tmpdir/overlay" cleanup+=("rmdir -- ${tmpdir@Q}/overlay") v mount -- /dev/mapper/vg_umorpha-lv_root_overlay "$tmpdir/overlay" cleanup+=("v umount ${tmpdir@Q}/overlay") mkdir "$tmpdir/mnt" "$tmpdir/overlay/upperdir" "$tmpdir/overlay/workdir" cleanup+=("rmdir -- ${tmpdir@Q}/mnt") v mount -t overlay -o "lowerdir=${tmpdir}/root,upperdir=${tmpdir}/overlay/upperdir,workdir=${tmpdir}/overlay/workdir" umorpha-rootfs \ "${tmpdir}/mnt" cleanup+=("v umount ${tmpdir@Q}/mnt") v mount -- "${devicep}${n_esp}" "$tmpdir/mnt/boot" cleanup+=("v umount ${tmpdir@Q}/mnt/boot") case "$typ" in uefi) mkdir -p -- "$tmpdir/mnt/etc/kernel" echo "root=$selector_root overlay_root=$selector_overlay boot=$selector_boot rw" >"$tmpdir/mnt/etc/kernel/cmdline" mkdir -p -- "$tmpdir/mnt/boot/EFI/Linux" v install -D "$tmpdir/mnt/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "$tmpdir/mnt/boot/EFI/BOOT/BOOTX64.EFI" ;; bios) v arch-chroot -- "$tmpdir/mnt" grub-install --target=i386-pc "$device" install -Dm600 /dev/stdin "$tmpdir/mnt/boot/grub/grub.cfg" <<-EOF insmod part_gpt insmod part_msdos if [ -s \$prefix/grubenv ]; then load_env fi if [ -s \$prefix/grub_a.cfg ]; then configfile \$prefix/grub_a.cfg fi if [ -s \$prefix/grub_b.cfg ]; then configfile \$prefix/grub_b.cfg fi EOF { for krnl in "$tmpdir/mnt"/usr/lib/modules/*/vmlinuz; do pkgbase=$(cat -- ${krnl%vmlinuz}pkgbase) cat <<-EOF menuentry 'Parabola GNU/Linux-libre, slot a, ${pkgbase} kernel' set search --no-floppy --fs-uuid --set=root ${selector_boot#UUID=} echo 'Loading ${pkgbase} kernel...' linux /vmlinuz-${pkgbase} root=$selector_root overlay_root=$selector_overlay boot=$selector_boot rw echo 'Loading initial ramdisk...' initrd /initramfs-${pkgbase}.img echo 'Booting...' boot EOF done } | install -Dm600 /dev/stdin "$tmpdir/mnt/boot/grub/grub_a.cfg" <<-EOF ;; esac v arch-chroot -- "$tmpdir/mnt" sh -c "printf '%s\n' usr/lib/modules/*/vmlinuz | /usr/share/libalpm/scripts/mkinitcpio install" v arch-chroot -- "$tmpdir/mnt" ldconfig v arch-chroot -- "$tmpdir/mnt" systemd-machine-id-setup v arch-chroot -- "$tmpdir/mnt" update-ca-trust } main "$@"