284 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			8.3 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)
 | |
| #  - 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)
 | |
| #
 | |
| # 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)
 | |
| #  - lvcreate       (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
 | |
| 
 | |
| 	v vgremove --yes vg_umorpha || true
 | |
| 
 | |
| 	########################################################################
 | |
| 
 | |
| 	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+=("v umount ${tmpdir@Q}/mnt/boot")
 | |
| 	cleanup+=("v umount ${tmpdir@Q}/mnt")
 | |
| 	cleanup+=("rmdir -- ${tmpdir@Q}/mnt")
 | |
| 	cleanup+=("v umount ${tmpdir@Q}/overlay")
 | |
| 	cleanup+=("rmdir -- ${tmpdir@Q}/overlay")
 | |
| 	cleanup+=("v umount ${tmpdir@Q}/root")
 | |
| 	cleanup+=("rmdir -- ${tmpdir@Q}/root")
 | |
| 
 | |
| 	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 "$@"
 |