291 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
#!/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)
 | 
						|
#  - 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)
 | 
						|
#  - lvresize           (lvm2)
 | 
						|
#  - pvcreate           (lvm2)
 | 
						|
#  - pvs                (lvm2)
 | 
						|
#  - vgchange           (lvm2)
 | 
						|
#  - vgcreate           (lvm2)
 | 
						|
#  - vgremove           (lvm2)
 | 
						|
#  - vgs                (lvm2)
 | 
						|
#  - pv                 (pv)
 | 
						|
#  - mkfs.ext4          (e2fsprogs)
 | 
						|
#  - mkfs.vfat          (dosfstools)
 | 
						|
#  - arch-chroot        (arch-install-scripts)
 | 
						|
#  - umorpha-mount
 | 
						|
#
 | 
						|
# 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)
 | 
						|
#
 | 
						|
# Dependencies of umorpha-mount:
 | 
						|
#  - sh     (bash, busybox)
 | 
						|
#  - getopt (util-linux, busybox)
 | 
						|
#  - mkdir  (coreutils, busybox)
 | 
						|
#  - mount  (util-linux)
 | 
						|
#
 | 
						|
# 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)
 | 
						|
#  - lvcreate       (lvm2)
 | 
						|
#  - lvresize       (lvm2)
 | 
						|
#  - pvcreate       (lvm2)
 | 
						|
#  - pvs            (lvm2)
 | 
						|
#  - vgchange       (lvm2)
 | 
						|
#  - vgcreate       (lvm2)
 | 
						|
#  - vgremove       (lvm2)
 | 
						|
#  - vgs            (lvm2)
 | 
						|
 | 
						|
set -euE -o pipefail
 | 
						|
 | 
						|
v() {
 | 
						|
	printf >&2 '  $ %s\n' "${*@Q}"
 | 
						|
	"$@"
 | 
						|
}
 | 
						|
 | 
						|
in_array() {
 | 
						|
	local needle haystack straw
 | 
						|
	needle=$1
 | 
						|
	haystack=("${@:2}")
 | 
						|
	for straw in "${haystack[@]}"; do
 | 
						|
		if [[ "$needle" == "$straw" ]]; then
 | 
						|
			return 0
 | 
						|
		fi
 | 
						|
	done
 | 
						|
	return 1
 | 
						|
}
 | 
						|
 | 
						|
main() {
 | 
						|
	local typ device rootfs slot
 | 
						|
	typ=$1
 | 
						|
	rootfs=$2
 | 
						|
	device=$3
 | 
						|
	slot='a'
 | 
						|
 | 
						|
	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
 | 
						|
 | 
						|
	########################################################################
 | 
						|
 | 
						|
	echo ":: Setting up GPT"
 | 
						|
 | 
						|
	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"
 | 
						|
 | 
						|
	if ! in_array "${devicep}${n_lvm}" $(pvs --noheadings --options=pv_name); then
 | 
						|
		v pvcreate "${devicep}${n_lvm}"
 | 
						|
	fi
 | 
						|
	if ! in_array vg_umorpha $(vgs --noheadings --options=vg_name); then
 | 
						|
		v vgcreate vg_umorpha "${devicep}${n_lvm}"
 | 
						|
	fi
 | 
						|
	if $is_loop; then
 | 
						|
		cleanup+=("v vgchange --activate=n vg_umorpha")
 | 
						|
	fi
 | 
						|
 | 
						|
	# Use short `-c` instead of `--format` so this works with busybox.
 | 
						|
	size="$(stat -c '%s' -- "$rootfs")"
 | 
						|
 | 
						|
	if [[ -e /dev/mapper/vg_umorpha-lv_root_$slot ]]; then
 | 
						|
		# Ugg, lvresize exits with non-zero for no-ops, which we can't
 | 
						|
		# even really do a pre-flight check for since it might round a
 | 
						|
		# size up.
 | 
						|
		v lvresize --size="${size}b" "/dev/mapper/vg_umorpha-lv_root_$slot" || true
 | 
						|
	else
 | 
						|
		v lvcreate --zero=y --wipesignatures=y --yes --name="lv_root_$slot" \
 | 
						|
			 --size="${size}b" vg_umorpha
 | 
						|
	fi
 | 
						|
 | 
						|
	v pv -- "$rootfs" >"/dev/mapper/vg_umorpha-lv_root_$slot"
 | 
						|
 | 
						|
	if ! [[ -e /dev/mapper/vg_umorpha-lv_root_overlay ]]; then
 | 
						|
		v lvcreate --zero=y --wipesignatures=y --yes \
 | 
						|
		        --name=lv_root_overlay --size=1G vg_umorpha
 | 
						|
	fi
 | 
						|
	if [[ -z "$(blkid --output=export /dev/mapper/vg_umorpha-lv_root_overlay | sed -n s/^TYPE=//p)" ]]; then
 | 
						|
		v mkfs.ext4 /dev/mapper/vg_umorpha-lv_root_overlay
 | 
						|
	fi
 | 
						|
 | 
						|
	########################################################################
 | 
						|
 | 
						|
	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_$slot" | 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
 | 
						|
 | 
						|
	v umorpha-mount \
 | 
						|
		--root="/dev/mapper/vg_umorpha-lv_root_$slot:auto:ro" \
 | 
						|
		--overlay='/dev/mapper/vg_umorpha-lv_root_overlay:auto:rw' \
 | 
						|
		--boot="${devicep}${n_esp}:auto:rw" \
 | 
						|
		--basedir="$tmpdir"
 | 
						|
	cleanup+=("rmdir -- ${tmpdir@Q}/root")
 | 
						|
	cleanup+=("v umount ${tmpdir@Q}/root")
 | 
						|
	cleanup+=("rmdir -- ${tmpdir@Q}/overlay")
 | 
						|
	cleanup+=("v umount ${tmpdir@Q}/overlay")
 | 
						|
	cleanup+=("rmdir -- ${tmpdir@Q}/mnt")
 | 
						|
	cleanup+=("v umount ${tmpdir@Q}/mnt")
 | 
						|
	cleanup+=("v umount ${tmpdir@Q}/mnt/boot")
 | 
						|
 | 
						|
	case "$typ" in
 | 
						|
		uefi)
 | 
						|
			mkdir -p -- "$tmpdir/mnt/etc/kernel"
 | 
						|
			echo "root=$selector_root overlay=$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 ${slot}, ${pkgbase} kernel'
 | 
						|
						  set search --no-floppy --fs-uuid --set=root ${selector_boot#UUID=}
 | 
						|
						  echo 'Loading ${pkgbase} kernel...'
 | 
						|
						  linux /vmlinuz-${pkgbase} root=$selector_root overlay=$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_${slot}.cfg"
 | 
						|
			;;
 | 
						|
	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 "$@"
 |