From b9da09402a308508d0e0574187398f928c3319ae Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 26 Mar 2023 17:26:02 +0200 Subject: [PATCH 01/84] fix(os): Identify disk by partition UUID (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index e1e7177..53c640e 100644 --- a/setup.sh +++ b/setup.sh @@ -105,7 +105,7 @@ function we_have_exactly_one_part () { function get_drive_id () { local drive_id_list drive_id_single - drive_id_list="$(find -L /dev/disk/by-id -samefile "${1:?}" | sort)" + drive_id_list="$(find -L /dev/disk/by-partuuid -samefile "${1:?}" | sort)" drive_id_single="$(head -n1 <<<"${drive_id_list}")" if [[ "$(wc -l <<<"${drive_id_single}")" -eq '1' ]] && [[ "$(wc -c <<<"${drive_id_single}")" -gt '1' ]]; then printf -- '%s' "${drive_id_single}" -- 2.47.2 From 005fe43352edbb593327895c8fb7b2230f5ffb45 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 26 Mar 2023 19:03:20 +0200 Subject: [PATCH 02/84] refactor(os): We look for partition IDs in /dev/disk/by-partuuid (#3) --- setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 53c640e..7884d25 100644 --- a/setup.sh +++ b/setup.sh @@ -111,7 +111,7 @@ function get_drive_id () { printf -- '%s' "${drive_id_single}" return 0 fi - >2 printf -- '%s\n' 'Not exactly one '"'${1:?}'"' partition entry in /dev/disk/by-id, exiting ...' + >2 printf -- '%s\n' 'No '"'${1:?}'"' partition entry in /dev/disk/by-partuuid, exiting ...' exit 77 } @@ -151,7 +151,7 @@ function set_zpool_password () { } function import_pool () { - zpool import -d '/dev/disk/by-id' -R '/mnt' "${zpool_name}" -N -f + zpool import -d '/dev/disk/by-partuuid' -R '/mnt' "${zpool_name}" -N -f zfs load-key "${zpool_name}" } -- 2.47.2 From af9deec753dc2c6ecc36d9acaa899575b7754a38 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 26 Mar 2023 19:11:50 +0200 Subject: [PATCH 03/84] docs(os): EFI partition must be mountable (#3) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 94a1506..ba1f52e 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ We expect minimal prep on your end. Please make sure that before execution the f - Arch Linux live CD ISO image sees exactly one partition with partition type code `BF00` ("Solaris root") - Arch Linux live CD ISO image sees exactly one partition with partition type code `EF00` ("EFI system partition") +- The `EF00` EFI partition is mountable, in practical terms this usually only means it has a file system. - No ZFS zpool exists The script will create a single ZFS zpool `zpool` on the `BF00` partition with dataset child `zpool/root` which itself has one child `zpool/root/archlinux`, that's where Arch Linux gets installed. Parallel to `zpool/root` it'll create `zpool/data` with a `zpool/data/home` child dataset that gets mounted at `/home`. -- 2.47.2 From 7384dd769be42e58c59915fe52da9b6ee430a885 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 26 Mar 2023 21:14:45 +0200 Subject: [PATCH 04/84] docs(os): Explain sgdisk disk setup (#3) --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index ba1f52e..0c77827 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,34 @@ We expect minimal prep on your end. Please make sure that before execution the f - The `EF00` EFI partition is mountable, in practical terms this usually only means it has a file system. - No ZFS zpool exists +### How to prep + +On a blank example disk `/dev/sda` you can fulfill the requirements (One `EF00` partition with a file system plus one `BF00` partition) for example like so: +``` +sgdisk --new '1::+100M' --new '2' --typecode '1:EF00' --typecode '2:BF00' /dev/sda +mkfs.vfat /dev/sda1 +``` +> `--new '1::+100M'`: Create partition number `1`. The field separator `:` separates the partition number from start sector. In this case start sector is unspecified so start sector sits at whatever the system's default is for this operation. On a blank disk on an Arch Linux live CD ISO image this will default to sector `2048`. Partition ends at whatever the beginning is `+100M` meaning plus 100 Mebibytes. +> +> `--new '2'`: Create partition number `2`. Both field number 2, the start sector, and field number 3, the end sector, are unspecified, there's no field separator `:`. Field number 2 will be the first free sector - in this case right after partition 1 - and field number 3 will be end of disk. Thus partition `2` will fill the remaining free disk space. +> +> `--typecode '1:EF00'`: Partition 1 gets partition type code `EF00`, an EFI system partition. +> +> `--typecode '2:BF00'`: Partition 2 gets partition type code `BF00`, an Solaris root partition. + +The result will be something like this at which point you can start the `setup.sh` script, see [How to run this?](#how-to-run-this) below for more details. +``` +# lsblk --paths +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS +/dev/loop0 7:0 0 688.5M 1 loop /run/archiso/airootfs +/dev/sr0 11:0 1 810.3M 0 rom /run/archiso/bootmnt +/dev/sda 202:0 0 10G 0 disk +├─/dev/sda1 202:1 0 100M 0 part +└─/dev/sda2 202:2 0 9.9G 0 part +``` + +## ZFS dataset layout + The script will create a single ZFS zpool `zpool` on the `BF00` partition with dataset child `zpool/root` which itself has one child `zpool/root/archlinux`, that's where Arch Linux gets installed. Parallel to `zpool/root` it'll create `zpool/data` with a `zpool/data/home` child dataset that gets mounted at `/home`. The script will use the `EF00` partition to install a ZFSBootMenu EFI executable if `efibootmgr` says that no such `ZFSBootMenu` entry exists. If ZFSBootMenu gets added to the EFI partition it'll become primary boot option. -- 2.47.2 From 7f2b16c6a4671b69db048a5a815e8ea90682f258 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 00:45:43 +0200 Subject: [PATCH 05/84] fix(os): Stop pacman from doing it's CheckSpace on ZFS (#3) --- setup.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/setup.sh b/setup.sh index 7884d25..b78ae0a 100644 --- a/setup.sh +++ b/setup.sh @@ -237,8 +237,20 @@ function pacman_dl_parallel () { sed -ri -e 's'$'\x1''^.*?(ParallelDownloads)[^\r\n\f]*'$'\x1''\1 = 5'$'\x1''g' '/etc/pacman.conf' } +function pacman_dont_check_space () { + # See pacman bug comment + # https://bugs.archlinux.org/task/45070#comment142712 + # + # When we pacstrap onto ZFS pacman incorrectly calculates and + # overestimates required disk space. We instead assume an installation + # gets done with at least a 10 GiB drive which is plenty. Skip pacman's + # size check. + sed -ri -e 's'$'\x1''^.*?(CheckSpace)([^\r\n\f]*)'$'\x1''#\1\2'$'\x1''g' '/etc/pacman.conf' +} + function install_archlinux () { pacman_dl_parallel + pacman_dont_check_space pacstrap /mnt \ base \ base-devel \ -- 2.47.2 From ba181c5fced856b7f432f33a53a78449b15a7d0f Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 00:46:16 +0200 Subject: [PATCH 06/84] feat(zfs): Allow toggle for compression and encryption (#3) --- setup.sh | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/setup.sh b/setup.sh index b78ae0a..5dc71d8 100644 --- a/setup.sh +++ b/setup.sh @@ -152,21 +152,32 @@ function set_zpool_password () { function import_pool () { zpool import -d '/dev/disk/by-partuuid' -R '/mnt' "${zpool_name}" -N -f - zfs load-key "${zpool_name}" + [[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && zfs load-key "${zpool_name}" } function create_pool () { # Create a temporary pool that is not cached + # + # Add zfsprops 'compression' unless environment variable + # ARCHZBM_ZFSPROPS_NO_COMPRESSION is set to any value. + # + # Add zfsprops 'encryption' along with 'keyformat' and a 'keylocation' + # unless environment variable ARCHZBM_ZFSPROPS_NO_ENCRYPTION is set to + # any value. zpool create -f \ -o 'ashift=12' \ -o 'autotrim=on' \ -O 'acltype=posix' \ - -O 'compression=on' \ + $([[ ! "${ARCHZBM_ZFSPROPS_NO_COMPRESSION}" ]] && \ + printf -- '%s ' \ + '-O compression=on') \ -O 'relatime=on' \ -O 'xattr=sa' \ - -O 'encryption=on' \ - -O 'keyformat=passphrase' \ - -O 'keylocation=file:///etc/zfs/'"${zpool_name}"'.key' \ + $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && \ + printf -- '%s ' \ + '-O encryption=on' \ + '-O keyformat=passphrase' \ + '-O keylocation=file:///etc/zfs/'"${zpool_name}"'.key') \ -O 'normalization=formD' \ -O 'mountpoint=none' \ -O 'canmount=off' \ @@ -202,7 +213,7 @@ function setup_zpool () { zpool_drive="$(select_part 'zfs')" drive_by_id="$(get_drive_id "${zpool_drive}")" - set_zpool_password + [[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && set_zpool_password if no_zpool_exists; then create_pool "${drive_by_id}" create_root_dataset @@ -305,14 +316,17 @@ function set_locale () { } function add_zfs_hook_to_initramfs () { - # Add zfs hook, remove fsck hook from initramfs. Also add plain text key - # file into initramfs since it's living inside an encrypted pool anyway. + # Add zfs hook, remove fsck hook from initramfs. sed -ri \ - -e 's'$'\x1''^(FILES=)[^\r\n\f]*'$'\x1''\1(/etc/zfs/'"${zpool_name}"'.key)'$'\x1''g' \ -e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \ -e 's'$'\x1''((\()(fsck)(\)))'$'\x1''\2\4'$'\x1''g' \ -e 's'$'\x1''(([[:space:]]+)(fsck)|(fsck)([[:space:]]+))'$'\x1'''$'\x1''g' \ '/mnt/etc/mkinitcpio.conf' + # Also unless encryption's unwanted add plain text key file into + # initramfs since it's living inside an encrypted pool anyway. + [[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && sed -ri \ + -e 's'$'\x1''^(FILES=)[^\r\n\f]*'$'\x1''\1(/etc/zfs/'"${zpool_name}"'.key)'$'\x1''g' \ + '/mnt/etc/mkinitcpio.conf' } function set_initramfs_build_list () { @@ -329,7 +343,7 @@ function set_initramfs_build_list () { } function add_zfs_files_to_new_os () { - for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' '/etc/zfs/'"${zpool_name}"'.key'; do + for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do rsync -av --itemize-changes {'','/mnt'}"${zfs_file}" done } -- 2.47.2 From ef029186fe79ad4ef4017b30ea65aff5367d16e2 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 02:25:23 +0200 Subject: [PATCH 07/84] docs(os): Explain static systemd network config (#3) --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 0c77827..5598cb5 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,29 @@ After installation you're going to want to at least touch these points in your n - ZFS: The password for all datasets underneath `zpool` is `password`. - Local `root` account: The local `root` account's password is `password`. - Arch User Repository (AUR) helper: We installed [paru](https://github.com/Morganamilo/paru) as our AUR helper, we installed from GitHub via `makepkg -si`. +- In `/etc/systemd/network/50-wired.network` instead of a DHCP-based network config you can get a static one. The DHCP-based looks for reference looks like: + ``` + ... + + [Network] + DHCP=ipv4 + IPForward=yes + Domains=~. + + [DHCP] + UseDNS=yes + RouteMetric=10 + ``` + Dynamic one does away with the `[DHCP]` section: + ``` + ... + + [Network] + Address=10.10.10.2/24 + Gateway=10.10.10.1 + DNS=10.10.10.1 + IPForward=yes + ``` # Password change -- 2.47.2 From 2f209db4269590c42d5823fc599aa6dea6aa111d Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 02:25:51 +0200 Subject: [PATCH 08/84] refactor(os): Check efibootmgr output quitely (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 5dc71d8..5a1ecb2 100644 --- a/setup.sh +++ b/setup.sh @@ -612,7 +612,7 @@ function get_disks_with_one_efipart () { } function add_zbm_to_efi () { - if ! efibootmgr | grep -Pi -- 'ZFSBootMenu'; then + if ! efibootmgr | grep -Piq -- 'ZFSBootMenu'; then local efi_disks_list efi_disks_list="$(get_disks_with_one_efipart)" if grep -Piq -- '^'"${efi_drive}"'$' <<<"${efi_disks_list}"; then -- 2.47.2 From 16c746e9d42857091b9a9d526044ff7fbd53cb25 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 02:40:27 +0200 Subject: [PATCH 09/84] feature(zfs): Optionally don't compress and/or don't encrypt (#3) --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5598cb5..67af7a1 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,26 @@ The script will use the `EF00` partition to install a ZFSBootMenu EFI executable ``` During execution the script will call itself when it changes into its `chroot`, that's why we `export SCRIPT_URL`. Feel free to update `"${SCRIPT_URL}"` with whatever branch or revision you want to use from [quico.space/quico-os-setup/arch-zbm](https://quico.space/quico-os-setup/arch-zbm). Typically `.../branch/main/setup.sh` as shown above is what you want. +### Options + +#### Compression + +By default we create a zpool with ZFS properties `compression=on`. If the `lz4_compress` pool feature is active this will by default enable `compression=lz4`. See `man 7 zfsprops` for example in ZFS 2.19 for details. See `zpool get feature@lz4_compress ` to check this feature's status on your ``. + +To get zpool with uncompressed datasets export the shell variable `ARCHZBM_ZFSPROPS_NO_COMPRESSION` with any value prior to running this script. Literally any value works as long as you're not setting this to an empty string: +``` +export ARCHZBM_ZFSPROPS_NO_COMPRESSION=yesplease +``` + +#### Encryption + +By default we encrypt the zpool with ZFS properties `encryption=on`. In ZFS 2.1.9 this defaults to `encryption=aes-256-gcm`. + +To get an unencrypted zpool export the shell variable `ARCHZBM_ZFSPROPS_NO_ENCRYPTION` with any value prior to running this script: +``` +export ARCHZBM_ZFSPROPS_NO_ENCRYPTION=yup +``` + ## Steps The scripts takes the following installation steps. @@ -105,7 +125,7 @@ After installation you're going to want to at least touch these points in your n Dynamic one does away with the `[DHCP]` section: ``` ... - + [Network] Address=10.10.10.2/24 Gateway=10.10.10.1 -- 2.47.2 From 5f8f407e95993ab7de7abef567c670fdb16282f7 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 02:42:49 +0200 Subject: [PATCH 10/84] docs(os): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 67af7a1..21bcffa 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ mkfs.vfat /dev/sda1 > > `--typecode '1:EF00'`: Partition 1 gets partition type code `EF00`, an EFI system partition. > -> `--typecode '2:BF00'`: Partition 2 gets partition type code `BF00`, an Solaris root partition. +> `--typecode '2:BF00'`: Partition 2 gets partition type code `BF00`, a Solaris root partition. The result will be something like this at which point you can start the `setup.sh` script, see [How to run this?](#how-to-run-this) below for more details. ``` -- 2.47.2 From 6cecb438a77c4c2a198baa9812ca4c419368425d Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 02:44:46 +0200 Subject: [PATCH 11/84] docs(os): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21bcffa..f221c3a 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ The script will use the `EF00` partition to install a ZFSBootMenu EFI executable #### Compression -By default we create a zpool with ZFS properties `compression=on`. If the `lz4_compress` pool feature is active this will by default enable `compression=lz4`. See `man 7 zfsprops` for example in ZFS 2.19 for details. See `zpool get feature@lz4_compress ` to check this feature's status on your ``. +By default we create a zpool with ZFS properties `compression=on`. If the `lz4_compress` pool feature is active this will by default enable `compression=lz4`. See `man 7 zfsprops` for example in ZFS 2.1.9 for details. See `zpool get feature@lz4_compress ` to check this feature's status on your ``. To get zpool with uncompressed datasets export the shell variable `ARCHZBM_ZFSPROPS_NO_COMPRESSION` with any value prior to running this script. Literally any value works as long as you're not setting this to an empty string: ``` -- 2.47.2 From 4973217ff58852e8947049e6a2994c27ff8ecaea Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 02:46:13 +0200 Subject: [PATCH 12/84] docs(os): Typo (#3) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f221c3a..d516a97 100644 --- a/README.md +++ b/README.md @@ -57,18 +57,18 @@ The script will use the `EF00` partition to install a ZFSBootMenu EFI executable #### Compression -By default we create a zpool with ZFS properties `compression=on`. If the `lz4_compress` pool feature is active this will by default enable `compression=lz4`. See `man 7 zfsprops` for example in ZFS 2.1.9 for details. See `zpool get feature@lz4_compress ` to check this feature's status on your ``. +By default we create a zpool with ZFS property `compression=on`. If the `lz4_compress` pool feature is active this will by default enable `compression=lz4`. See `man 7 zfsprops` for example in ZFS 2.1.9 for details. See `zpool get feature@lz4_compress ` to check this feature's status on your ``. -To get zpool with uncompressed datasets export the shell variable `ARCHZBM_ZFSPROPS_NO_COMPRESSION` with any value prior to running this script. Literally any value works as long as you're not setting this to an empty string: +To get a zpool with uncompressed datasets export the shell variable `ARCHZBM_ZFSPROPS_NO_COMPRESSION` with any value prior to running this script. Literally any value works as long as you're not setting this to an empty string: ``` export ARCHZBM_ZFSPROPS_NO_COMPRESSION=yesplease ``` #### Encryption -By default we encrypt the zpool with ZFS properties `encryption=on`. In ZFS 2.1.9 this defaults to `encryption=aes-256-gcm`. +By default we encrypt the zpool with ZFS property `encryption=on`. In ZFS 2.1.9 this defaults to `encryption=aes-256-gcm`. -To get an unencrypted zpool export the shell variable `ARCHZBM_ZFSPROPS_NO_ENCRYPTION` with any value prior to running this script: +To get a zpool with unencrypted datasets export the shell variable `ARCHZBM_ZFSPROPS_NO_ENCRYPTION` with any value prior to running this script: ``` export ARCHZBM_ZFSPROPS_NO_ENCRYPTION=yup ``` -- 2.47.2 From adde942cff623b9d32c0987ceff74c0987ceb186 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 02:47:30 +0200 Subject: [PATCH 13/84] docs(os): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d516a97..5a57a1a 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ After installation you're going to want to at least touch these points in your n - ZFS: The password for all datasets underneath `zpool` is `password`. - Local `root` account: The local `root` account's password is `password`. - Arch User Repository (AUR) helper: We installed [paru](https://github.com/Morganamilo/paru) as our AUR helper, we installed from GitHub via `makepkg -si`. -- In `/etc/systemd/network/50-wired.network` instead of a DHCP-based network config you can get a static one. The DHCP-based looks for reference looks like: +- In `/etc/systemd/network/50-wired.network` instead of a DHCP-based network config you can get a static one. The DHCP-based one for reference looks like: ``` ... -- 2.47.2 From 9af9572f3633f25e5eb8f14d6c84a8b7b40b17b4 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 16:11:58 +0200 Subject: [PATCH 14/84] docs(os): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a57a1a..c8bf19e 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ After installation you're going to want to at least touch these points in your n UseDNS=yes RouteMetric=10 ``` - Dynamic one does away with the `[DHCP]` section: + A static config does away with the `[DHCP]` section: ``` ... -- 2.47.2 From ecc33655db461c619c9ce67808ad06f5c409a843 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 22:53:38 +0200 Subject: [PATCH 15/84] docs(ZFS): Explain adding a new BE-independent dataset (#3) --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index c8bf19e..bb4930c 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,8 @@ zpool status zpool # ZFS setup explained +## Overview + The ZFS pool and dataset setup that makes this tick, explained in plain English. 1. Create zpool with options: @@ -310,6 +312,41 @@ The ZFS pool and dataset setup that makes this tick, explained in plain English. The complete ZFS structure now exists and is mounted at `/mnt` ready for any `pacstrap`, [debootstrap](https://wiki.debian.org/Debootstrap), `dnf --installroot` or other bootstrapping action. +## Adding another boot environment-independent dataset + +Assume that in addition to your `/home` data which lives on `zpool/data/home` you want another dataset that is exempt from Arch Linux snapshots. + +Consider an example `/opt/git` directory where a bunch of Git repos are checked out on which you work. You don't want them to be snapshotted - and rolled back - when something goes sideways: they are decoupled from everything else that goes on on your machine so you can easily and safely have a static `/opt/git` directory available in all boot environments. + +Move your current `/opt/git` data out of the way for a moment: +``` +mv '/opt/git'{,'.bak'} +``` +Create datasets +``` +zfs create -o canmount=off zpool/data/opt +zfs create zpool/data/opt/git +``` +Remember that the `zpool/data` dataset already exists and has that it has both `mountpoint=/` and `canmount=off` set. It is not and cannot be mounted itself, it instead conveniently anchors datasets at `/`. Since the `canmount` dataset property cannot be inherited and defaults to `canmount=on` we have to manually specify `-o canmount=off`. Our new `zpool/data/opt` should not automatically mount into `/opt`. + +We then create the child dataset `zpool/data/opt/git`, it defaults to `canmount=on` thus immediately shows up at `/opt/git`. + +Move data back into place and clean up temp directory +``` +rsync -av --remove-source-files '/opt/git'{'.bak',} +find '/opt/git.bak' -type d -empty -delete +``` + +An example `zpool/data` dataset may now look like so: +``` +# zfs list -r -oname,mountpoint,canmount zpool/data +NAME MOUNTPOINT CANMOUNT +zpool/data / off +zpool/data/home /home on +zpool/data/opt /opt off +zpool/data/opt/git /opt/git on +``` + # Development ## Conventional commits -- 2.47.2 From 8f131e3aafa0a7b0a6ad70e0a51bd894343278b1 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 22:57:17 +0200 Subject: [PATCH 16/84] docs(os): Typo (#3) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bb4930c..4cdd3a4 100644 --- a/README.md +++ b/README.md @@ -327,13 +327,13 @@ Create datasets zfs create -o canmount=off zpool/data/opt zfs create zpool/data/opt/git ``` -Remember that the `zpool/data` dataset already exists and has that it has both `mountpoint=/` and `canmount=off` set. It is not and cannot be mounted itself, it instead conveniently anchors datasets at `/`. Since the `canmount` dataset property cannot be inherited and defaults to `canmount=on` we have to manually specify `-o canmount=off`. Our new `zpool/data/opt` should not automatically mount into `/opt`. +Remember that the `zpool/data` dataset already exists and that it has both `mountpoint=/` and `canmount=off` set. It is not and cannot be mounted itself, it instead conveniently anchors datasets at `/`. Since the `canmount` dataset property cannot be inherited and defaults to `canmount=on` we have to manually specify `-o canmount=off`. Our new `zpool/data/opt` should not automatically mount into `/opt`. We then create the child dataset `zpool/data/opt/git`, it defaults to `canmount=on` thus immediately shows up at `/opt/git`. Move data back into place and clean up temp directory ``` -rsync -av --remove-source-files '/opt/git'{'.bak',} +rsync -av --remove-source-files '/opt/git'{'.bak',}'/' find '/opt/git.bak' -type d -empty -delete ``` -- 2.47.2 From 0cd149f8cb844ea3456445a9f618500764860eff Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 23:00:19 +0200 Subject: [PATCH 17/84] docs(os): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4cdd3a4..e2ecf79 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ export ARCHZBM_ZFSPROPS_NO_ENCRYPTION=yup ## Steps -The scripts takes the following installation steps. +The script takes the following installation steps. 1. Install ZFS tools and kernel module with [github.com/eoli3n/archiso-zfs](https://github.com/eoli3n/archiso-zfs) 1. Create one encrypted ZFS zpool on top of `BF00` partition, password `password` -- 2.47.2 From 412eb93c60823badff7625d24e1b9af1c6d4dcdd Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 23:10:47 +0200 Subject: [PATCH 18/84] docs(os): Typo (#3) --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e2ecf79..90e1128 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,8 @@ export ARCHZBM_ZFSPROPS_NO_ENCRYPTION=yup The script takes the following installation steps. 1. Install ZFS tools and kernel module with [github.com/eoli3n/archiso-zfs](https://github.com/eoli3n/archiso-zfs) -1. Create one encrypted ZFS zpool on top of `BF00` partition, password `password` +1. Create one ZFS zpool on top of `BF00` partition, encrypted and compressed datasets, password `password` + 1. _See paragraphs [Compression](#compression)/[Encryption](#encryption) to optionally disable properties_ 1. Create dataset for Arch Linux and `/home` 1. Install Arch Linux into pool 1. Add ZFSBootMenu to `EF00` partition if it doesn't exist already @@ -216,7 +217,7 @@ In order to generate a new master key after you've changed your user key as ment - With `-v` we get verbose progress output - Argument `-u` makes sure the dataset does not get mounted after transfer. ZFS would mount it into `/` which wouldn't be helpful since we're currently using that filesystem ourselves. - We set encryption properties `keyformat`, `keylocation` and most importantly `encryption`. The latter will turn our transferred dataset into its own `encryptionroot` which in turn generates a new master key. The auto-generated new master key gets wrapped with our updated passphrase in `keylocation`. This basically reencrypts all data in this dataset during transfer. - - We set `mountpoint` and `canmount` as well as a `org.zfsbootmenu:commandline` as we would for any new system dataset. + - We set `mountpoint` and `canmount` as well as an `org.zfsbootmenu:commandline` as we would for any new system dataset. 1. Change zpool's `bootfs` property to new system dataset ``` zpool set bootfs=zpool/root/archlinux-frn zpool -- 2.47.2 From 535073a3c2e1516c91cb0094cb57a9b6512fc9bd Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 23:13:00 +0200 Subject: [PATCH 19/84] docs(os): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 90e1128..d52edff 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ The ZFS pool and dataset setup that makes this tick, explained in plain English. 1. `-O keyformat=passphrase`: Controls what format the user's encryption key will be provided as. Passphrases must be between 8 and 512 bytes long. 1. At this time the newly created zpool is not mounted anywhere. Next we create the "root" dataset, that's an arbitary term for the parent dataset of all boot environments. Boot environments in your case may be for example different operating systems all of which live on separate datasets underneath the root. 1. `-o mountpoint=none`: Same as above, the root dataset has - just like the pool - no mountpoint configured. - 1. `zfs set org.zfsbootmenu:commandline=...`: Set a common kernel command line for all boot environment such as `"ro quiet"`. + 1. `zfs set org.zfsbootmenu:commandline=...`: Set a common kernel command line for all boot environments such as `"ro quiet"`. 1. Neither the root dataset nor the pool are mounted at this time. We now create one boot environment dataset where we want to install Arch Linux. 1. `-o mountpoint=/`: Our Arch Linux dataset will be mounted at `/`. 1. `-o canmount=noauto`: When set to `noauto`, a dataset can only be mounted and unmounted explicitly. The dataset is not mounted automatically when the dataset is created or imported, nor is it mounted by the `zfs mount -a` command or unmounted by the `zfs unmount -a` command. -- 2.47.2 From 85e2640471aa5a341ab488f7bcf0183a547bd424 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 23:15:46 +0200 Subject: [PATCH 20/84] docs(os): We scan for a zpool in /dev/disk/by-partuuid now, (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d52edff..c060ff6 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,7 @@ The ZFS pool and dataset setup that makes this tick, explained in plain English. 1. For a `zpool/data/home` child dataset: 1. We do not specify any properties. Since `canmount` cannot be inherited the parent's `canmount=off` does not apply, it instead defaults to `canmount=on`. The parent's `mountpoint=/` property on the other hand is inherited so for a `home` child dataset it conveniently equals `mountpoint=/home`. 1. In effect this `zpool/data/home` dataset is subject to `zfs mount -a` and will happily automount into `/home`. -1. We export the zpool once, we then reimport it by scanning only inside `/dev/disk/by-id`, again setting `-R /mnt` as we did during pool creation a moment ago and we do not mount any file systems. +1. We export the zpool once, we then reimport it by scanning only inside `/dev/disk/by-partuuid`, again setting `-R /mnt` as we did during pool creation a moment ago and we do not mount any file systems. 1. We `zfs load-key ` which will load the key from `keylocation` after which the `keystatus` property for `` and all child datasets will change from `unavailable` to `available`. 1. We mount our Arch Linux boot environment dataset. It automatically get prepended with `-R /mnt` since that's how we imported the pool. 1. We `zfs mount -a` which automounts `zpool/data/home` into `/home`, which again gets auto-prepended by `/mnt`. -- 2.47.2 From f0c75b735b47da87097ee48e872b51e9c9559fc4 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 27 Mar 2023 23:19:58 +0200 Subject: [PATCH 21/84] docs(os): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c060ff6..1ce0a8c 100644 --- a/README.md +++ b/README.md @@ -306,7 +306,7 @@ The ZFS pool and dataset setup that makes this tick, explained in plain English. 1. In effect this `zpool/data/home` dataset is subject to `zfs mount -a` and will happily automount into `/home`. 1. We export the zpool once, we then reimport it by scanning only inside `/dev/disk/by-partuuid`, again setting `-R /mnt` as we did during pool creation a moment ago and we do not mount any file systems. 1. We `zfs load-key ` which will load the key from `keylocation` after which the `keystatus` property for `` and all child datasets will change from `unavailable` to `available`. -1. We mount our Arch Linux boot environment dataset. It automatically get prepended with `-R /mnt` since that's how we imported the pool. +1. We mount our Arch Linux boot environment dataset. It automatically gets prefixed with `-R /mnt` since that's how we imported the pool. 1. We `zfs mount -a` which automounts `zpool/data/home` into `/home`, which again gets auto-prepended by `/mnt`. 1. We lastly mount our EFI partition into `/mnt/efi`. 1. We instruct ZFS to save its pool configuration via `zpool set cachefile=/etc/zfs/zpool.cache zpool`. -- 2.47.2 From 1f70342aad9813b0a70be3f56c3a97daa2a9d8ac Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 29 Apr 2023 17:11:55 +0200 Subject: [PATCH 22/84] fix(os): Only diff between DNS and static IP, keep the rest same (#3) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1ce0a8c..b290eb3 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ After installation you're going to want to at least touch these points in your n Gateway=10.10.10.1 DNS=10.10.10.1 IPForward=yes + Domains=~. ``` # Password change -- 2.47.2 From ec7931cb4caefbb02c21f2d510d0ba1e14a3f66f Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Tue, 16 May 2023 14:11:14 +0200 Subject: [PATCH 23/84] docs(zfs): Warn about nested datasets creation and auto-mounting (#3) --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/README.md b/README.md index b290eb3..df57219 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,55 @@ zpool/data/opt /opt off zpool/data/opt/git /opt/git on ``` +## Nested environment-independent datasets + +### Caution + +If you want a dedicated dataset for a directory that lives deeper in your file system tree than just `/opt/git`, for example like `/var/lib/docker` make sure to not recursively create this structure in a single `zfs create` command. + +In [Adding another boot environment-independent dataset](#adding-another-boot-environment-independent-dataset) above you can safely do: +``` +zfs create -o canmount=off zpool/data/opt +``` +Here `zpool/data` already exists, you're only creating one child dataset `opt` and you're setting `-o canmount=off` so that it never mounts into your `/opt` directory. + +Now consider the same setup for `/var/lib/docker`. If you follow the exact same approach: +``` +zfs create -o canmount=off zpool/data/var/lib +``` +Docker will correctly report: +``` +cannot create 'zpool/data/var/lib': parent does not exist +``` +You might want to just create the parent then with `-p` argument: +``` +zfs create -p -o canmount=off zpool/data/var/lib + ~~ +``` +Note, however, that `-o canmount=off` only applies to `lib` dataset and that `zpool/data/var` has just been auto-mounted into `/var`: +``` +# zfs list -r -oname,mountpoint,canmount,mounted zpool/data +NAME MOUNTPOINT CANMOUNT MOUNTED +zpool/data / off no +zpool/data/home /home on yes +zpool/data/opt /opt off no +zpool/data/opt/git /opt/git on yes +zpool/data/var /var on yes <--- +zpool/data/var/lib /var/lib off no +``` + +### Advice + +Instead create nested parents in multiple steps where you set each one to `-o canmount=off`: +``` +zfs create -o canmount=off zpool/data/var +zfs create -o canmount=off zpool/data/var/lib +``` +Lastly create the dataset you want mounted: +``` +zfs create zpool/data/var/lib/docker +``` + # Development ## Conventional commits -- 2.47.2 From 310b180580301fe60b2438b45010548251c14fec Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Tue, 16 May 2023 14:12:56 +0200 Subject: [PATCH 24/84] docs(zfs): Display mounted state in ZFS example (#3) --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index df57219..c5de3be 100644 --- a/README.md +++ b/README.md @@ -341,12 +341,12 @@ find '/opt/git.bak' -type d -empty -delete An example `zpool/data` dataset may now look like so: ``` -# zfs list -r -oname,mountpoint,canmount zpool/data -NAME MOUNTPOINT CANMOUNT -zpool/data / off -zpool/data/home /home on -zpool/data/opt /opt off -zpool/data/opt/git /opt/git on +# zfs list -r -oname,mountpoint,canmount,mounted zpool/data +NAME MOUNTPOINT CANMOUNT MOUNTED +zpool/data / off no +zpool/data/home /home on yes +zpool/data/opt /opt off no +zpool/data/opt/git /opt/git on yes ``` ## Nested environment-independent datasets -- 2.47.2 From 63974a2dff95383237f0799ad6de59a9fcbd2a07 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Tue, 30 May 2023 22:56:18 +0200 Subject: [PATCH 25/84] docs(os): Explain NetworkManager interaction (#3) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c5de3be..7c8840c 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,12 @@ After installation you're going to want to at least touch these points in your n IPForward=yes Domains=~. ``` +- In case you later want a graphical interface and specifically NetworkManager (via package `networkmanager`) consider telling it to keep its hands off of some of your network interfaces. The bullet point above adds a `systemd`-style config file that `systemd-networkd.service` will read and use. Should you ever install NetworkManager it will by default assume that it must manage all interfaces. It'll use its own DHCP client to try and get IP addresses for _managed interfaces_ in which case you'll end up with whatever addressing scheme you configured in a `.network` unit file plus NetworkManager's additional address. Create `/etc/NetworkManager/conf.d/99-unmanaged-devices.conf` for example to declare some interfaces as off-limits or _unmanaged_: + ``` + [keyfile] + unmanaged-devices=mac:52:54:00:74:79:56;type:ethernet + ``` + Check out [ArchWiki article "NetworkManager" section "Ignore specific devices"](https://wiki.archlinux.org/title/NetworkManager#Ignore_specific_devices) for more info. # Password change -- 2.47.2 From 29a5ede89964cdd539a9421bbf7e7ffb412b6d07 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 15:15:39 +0200 Subject: [PATCH 26/84] refactor(meta): Move we_are_changerooted function to top (#3) --- setup.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.sh b/setup.sh index 5a1ecb2..d599e74 100644 --- a/setup.sh +++ b/setup.sh @@ -13,10 +13,6 @@ trap '[ "$?" -ne 77 ] || exit 77' ERR declare zpool_drive efi_drive -function set_ntp () { - timedatectl set-ntp true -} - function we_are_changerooted () { if [ "$(stat -c '%d:%i' '/')" != "$(stat -c '%d:%i' '/proc/1/root/.')" ]; then return 0 @@ -25,6 +21,10 @@ function we_are_changerooted () { fi } +function set_ntp () { + timedatectl set-ntp true +} + function update_pacman_db () { printf -- '%s\n' 'Refreshing mirror list ...' systemctl start reflector -- 2.47.2 From 2876f55e82963fbb932c2e30b311f6bc9bf4b7e7 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 15:24:39 +0200 Subject: [PATCH 27/84] refactor(meta): Add function numbering (#3) --- setup.sh | 78 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/setup.sh b/setup.sh index d599e74..0d40a94 100644 --- a/setup.sh +++ b/setup.sh @@ -22,10 +22,12 @@ function we_are_changerooted () { } function set_ntp () { + #1.1 timedatectl set-ntp true } function update_pacman_db () { + #1.2 printf -- '%s\n' 'Refreshing mirror list ...' systemctl start reflector # In an ISO and for the minimal number of packages we need we do not @@ -34,11 +36,13 @@ function update_pacman_db () { } function install_pkgs () { + #1.3 printf -- '%s\n' 'Installing packages ...' pacman -S --needed --noconfirm "${@}" } function install_zfs () { + #1.4 declare reset_colors='\033[0m' curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash printf -- "${reset_colors}" @@ -209,6 +213,7 @@ function export_pool () { } function setup_zpool () { + #1.4 local drive_by_id zpool_drive="$(select_part 'zfs')" drive_by_id="$(get_drive_id "${zpool_drive}")" @@ -228,6 +233,7 @@ function setup_zpool () { } function mount_system () { + #1.5 zfs mount "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" zfs mount -a @@ -240,6 +246,7 @@ function mount_system () { } function copy_zpool_cache () { + #1.6 mkdir -p '/mnt/etc/zfs' zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}" } @@ -260,6 +267,7 @@ function pacman_dont_check_space () { } function install_archlinux () { + #1.7 pacman_dl_parallel pacman_dont_check_space pacstrap /mnt \ @@ -286,6 +294,7 @@ function install_archlinux () { } function gen_fstab () { + #1.8 genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab' } @@ -298,6 +307,7 @@ EOF } function set_hostname () { + #1.9 declare new_hostname install_pkgs 'pwgen' new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)" @@ -306,6 +316,7 @@ function set_hostname () { } function set_locale () { + #1.10 printf -- '%s\n' \ 'KEYMAP=de-latin1' \ 'FONT=Lat2-Terminus16' \ @@ -316,6 +327,7 @@ function set_locale () { } function add_zfs_hook_to_initramfs () { + #1.11 # Add zfs hook, remove fsck hook from initramfs. sed -ri \ -e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \ @@ -330,6 +342,7 @@ function add_zfs_hook_to_initramfs () { } function set_initramfs_build_list () { + #1.12 # No need to build fallback initramfs, our new fallback is ZFS snapshots sed -ri \ -e '/^#/d' \ @@ -343,12 +356,14 @@ function set_initramfs_build_list () { } function add_zfs_files_to_new_os () { + #1.13 for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do rsync -av --itemize-changes {'','/mnt'}"${zfs_file}" done } function enter_chroot () { + #1.14 arch-chroot /mnt /bin/bash -xe < '/mnt/etc/systemd/network/50-wired.network' <<"EOF" [Match] Name=en* @@ -543,6 +560,7 @@ EOF } function configure_dns () { + #2.3 rm '/mnt/etc/resolv.conf' ln -s '/run/systemd/resolve/stub-resolv.conf' '/mnt/etc/resolv.conf' @@ -553,14 +571,17 @@ function configure_dns () { } function configure_reflector () { + #2.4 systemctl enable 'reflector' --root='/mnt' } function configure_zfs () { + #2.5 systemctl enable 'zfs-import-cache' 'zfs-mount' 'zfs-import.target' 'zfs.target' --root='/mnt' } function configure_zfs_mount_gen () { + #2.6 mkdir -p '/mnt/etc/zfs/zfs-list.cache' touch '/mnt/etc/zfs/zfs-list.cache/'"${zpool_name}" zfs list -H -o name,mountpoint,canmount,atime,relatime,devices,exec,readonly,setuid,nbmand | sed 's/\/mnt//' > '/mnt/etc/zfs/zfs-list.cache/'"${zpool_name}" @@ -568,6 +589,7 @@ function configure_zfs_mount_gen () { } function configure_zfsbootmenu () { + #2.7 curl -s 'https://raw.githubusercontent.com/zbm-dev/zfsbootmenu/master/etc/zfsbootmenu/mkinitcpio.conf' | sed -r -e '/^#/d' -e '/^$/d' > '/mnt/etc/zfsbootmenu/mkinitcpio.conf' cat > '/mnt/etc/zfsbootmenu/config.yaml' < Date: Fri, 20 Oct 2023 15:26:22 +0200 Subject: [PATCH 28/84] refactor(meta): Trim trailing whitespace (#3) --- setup.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index 0d40a94..4854d83 100644 --- a/setup.sh +++ b/setup.sh @@ -161,10 +161,10 @@ function import_pool () { function create_pool () { # Create a temporary pool that is not cached - # + # # Add zfsprops 'compression' unless environment variable # ARCHZBM_ZFSPROPS_NO_COMPRESSION is set to any value. - # + # # Add zfsprops 'encryption' along with 'keyformat' and a 'keylocation' # unless environment variable ARCHZBM_ZFSPROPS_NO_ENCRYPTION is set to # any value. @@ -258,7 +258,7 @@ function pacman_dl_parallel () { function pacman_dont_check_space () { # See pacman bug comment # https://bugs.archlinux.org/task/45070#comment142712 - # + # # When we pacstrap onto ZFS pacman incorrectly calculates and # overestimates required disk space. We instead assume an installation # gets done with at least a 10 GiB drive which is plenty. Skip pacman's -- 2.47.2 From 93932a522ec61c1a8735c59c4f7fc14b16cd71ae Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 15:29:40 +0200 Subject: [PATCH 29/84] docs(meta): Default to 512 MiB EFS instead of 100 MiB (#3) Testing shows 100 MiB is a bit tight with a backup UEFI image and future growth. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7c8840c..a2518b6 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ We expect minimal prep on your end. Please make sure that before execution the f On a blank example disk `/dev/sda` you can fulfill the requirements (One `EF00` partition with a file system plus one `BF00` partition) for example like so: ``` -sgdisk --new '1::+100M' --new '2' --typecode '1:EF00' --typecode '2:BF00' /dev/sda +sgdisk --new '1::+512M' --new '2' --typecode '1:EF00' --typecode '2:BF00' /dev/sda mkfs.vfat /dev/sda1 ``` -> `--new '1::+100M'`: Create partition number `1`. The field separator `:` separates the partition number from start sector. In this case start sector is unspecified so start sector sits at whatever the system's default is for this operation. On a blank disk on an Arch Linux live CD ISO image this will default to sector `2048`. Partition ends at whatever the beginning is `+100M` meaning plus 100 Mebibytes. +> `--new '1::+512M'`: Create partition number `1`. The field separator `:` separates the partition number from start sector. In this case start sector is unspecified so start sector sits at whatever the system's default is for this operation. On a blank disk on an Arch Linux live CD ISO image this will default to sector `2048`. Partition ends at whatever the beginning is `+512M` meaning plus 512 Mebibytes. > > `--new '2'`: Create partition number `2`. Both field number 2, the start sector, and field number 3, the end sector, are unspecified, there's no field separator `:`. Field number 2 will be the first free sector - in this case right after partition 1 - and field number 3 will be end of disk. Thus partition `2` will fill the remaining free disk space. > @@ -33,7 +33,7 @@ NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS /dev/loop0 7:0 0 688.5M 1 loop /run/archiso/airootfs /dev/sr0 11:0 1 810.3M 0 rom /run/archiso/bootmnt /dev/sda 202:0 0 10G 0 disk -├─/dev/sda1 202:1 0 100M 0 part +├─/dev/sda1 202:1 0 512M 0 part └─/dev/sda2 202:2 0 9.9G 0 part ``` -- 2.47.2 From b9d9548929d0754c37901463cb6ef0dcaa4d175e Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 15:30:01 +0200 Subject: [PATCH 30/84] docs(meta): Typo (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2518b6..d43d755 100644 --- a/README.md +++ b/README.md @@ -426,7 +426,7 @@ The following _scopes_ are known for this project. A Conventional Commits commit - `iso`: Changing Arch Linux ISO CD - `zbm`: Adjusting ZFSBootMenu's behavior - `zfs`: A change to how ZFS interacts with the system, either a pool or a dataset -- `os`: Getting an perating system set up to correctly work in a ZFS boot environment +- `os`: Getting an operating system set up to correctly work in a ZFS boot environment - `meta`: Affects the project's repo layout, readme content, file names etc. # Credits -- 2.47.2 From 1ac2353d64806aafb5a335f9ae79b25c0e9b1f58 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 15:35:17 +0200 Subject: [PATCH 31/84] refactor(os): Default pacman to 20 parallel downloads (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 4854d83..403125c 100644 --- a/setup.sh +++ b/setup.sh @@ -252,7 +252,7 @@ function copy_zpool_cache () { } function pacman_dl_parallel () { - sed -ri -e 's'$'\x1''^.*?(ParallelDownloads)[^\r\n\f]*'$'\x1''\1 = 5'$'\x1''g' '/etc/pacman.conf' + sed -ri -e 's'$'\x1''^.*?(ParallelDownloads)[^\r\n\f]*'$'\x1''\1 = 20'$'\x1''g' '/etc/pacman.conf' } function pacman_dont_check_space () { -- 2.47.2 From 5cb1e6b1f298a060a7ee3fee7831f5666f1cf347 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 15:37:56 +0200 Subject: [PATCH 32/84] refactor(os): Remind ourselves /etc/pacman.conf is ephemeral (#3) --- setup.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.sh b/setup.sh index 403125c..262c33b 100644 --- a/setup.sh +++ b/setup.sh @@ -252,6 +252,8 @@ function copy_zpool_cache () { } function pacman_dl_parallel () { + # We're setting this in Arch Linux ISO CD while we install proper Arch. + # No need to revert this later as it is ephemeral anyway. sed -ri -e 's'$'\x1''^.*?(ParallelDownloads)[^\r\n\f]*'$'\x1''\1 = 20'$'\x1''g' '/etc/pacman.conf' } @@ -263,6 +265,9 @@ function pacman_dont_check_space () { # overestimates required disk space. We instead assume an installation # gets done with at least a 10 GiB drive which is plenty. Skip pacman's # size check. + # + # We're setting this in Arch Linux ISO CD while we install proper Arch. + # No need to revert this later as it is ephemeral anyway. sed -ri -e 's'$'\x1''^.*?(CheckSpace)([^\r\n\f]*)'$'\x1''#\1\2'$'\x1''g' '/etc/pacman.conf' } -- 2.47.2 From 66eb02ff7d869db681160c3abb32a9deaf045f31 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 15:41:17 +0200 Subject: [PATCH 33/84] refactor(meta): Add function numbering (#3) --- setup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 262c33b..c4fffe4 100644 --- a/setup.sh +++ b/setup.sh @@ -510,6 +510,7 @@ EOF } function install_os_in_chroot () { + #1.16 ### Reinit keyring # As keyring is initialized at boot, and copied to the install dir with pacstrap, and ntp is running # Time changed after keyring initialization, it leads to malfunction @@ -678,7 +679,7 @@ function finalize_os_setup () { function main () { if we_are_changerooted; then - install_os_in_chroot + install_os_in_chroot #1.16 else set_ntp #1.1 update_pacman_db #1.2 -- 2.47.2 From 148f9306360c260433459c9cea537101d9ba3fd2 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 16:30:29 +0200 Subject: [PATCH 34/84] refactor(os): Allow AUR helper to replace itself (#3) --- README.md | 2 +- setup.sh | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d43d755..8fe71e4 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ After installation you're going to want to at least touch these points in your n - Passwords - ZFS: The password for all datasets underneath `zpool` is `password`. - Local `root` account: The local `root` account's password is `password`. -- Arch User Repository (AUR) helper: We installed [paru](https://github.com/Morganamilo/paru) as our AUR helper, we installed from GitHub via `makepkg -si`. +- Arch User Repository (AUR) helper: We installed [paru](https://github.com/Morganamilo/paru) as our AUR helper, we installed from GitHub via `makepkg -si` then replaced itself with its [paru-bin](https://aur.archlinux.org/packages/paru-bin) version from AUR. - In `/etc/systemd/network/50-wired.network` instead of a DHCP-based network config you can get a static one. The DHCP-based one for reference looks like: ``` ... diff --git a/setup.sh b/setup.sh index c4fffe4..74ae35c 100644 --- a/setup.sh +++ b/setup.sh @@ -460,7 +460,46 @@ function get_aur_helper () { } function paru_install () { - sudo --user build paru -S --noconfirm "${@}" + declare -a paru_install_packages + [[ "${1}" ]] && while :; do + case "${1}" in + -[[:alnum:]]*) + printf -- '%s\n' \ + 'Short-form argument '"'${1}'"' not supported for function '"'${FUNCNAME[0]}()'"'. Only known accepted argument' \ + 'is '"'"'--replace-conflicting'"'"' without a value given. Exiting ...' + exit 77 + ;; + --replace-conflicting) + pacman_force_yes='true' + shift + continue + ;; + --*) + printf -- '%s\n' \ + 'Long-form argument '"'${1}'"' not supported for function '"'${FUNCNAME[0]}()'"'. Only known accepted argument' \ + 'is '"'"'--replace-conflicting'"'"' without a value given. Exiting ...' + exit 77 + ;; + '') + # All arguments processed + break + ;; + *) + paru_install_packages+=("${1}") + shift + ;; + esac + done || { + printf -- '%s\n' \ + 'No argument '"'${1}'"' given for function '"'${FUNCNAME[0]}'"'. Exiting ...' + exit 77 + } + if [[ "${pacman_force_yes}" ]]; then + yes 'y' | sudo --user build paru -S "${paru_install_packages[@]}" + unset -v pacman_force_yes + else + sudo --user build paru -S --noconfirm "${paru_install_packages[@]}" + fi } function keep_initiramfs_root_only_rw () { @@ -525,6 +564,7 @@ function install_os_in_chroot () { unleash_makepkg add_motd_getting_started_msg get_aur_helper + paru_install --replace-conflicting 'paru-bin' paru_install 'zfs-dkms' 'zfs-utils' hwclock --systohc locale-gen -- 2.47.2 From e9602491df010329c51c6af27aeb06dd38487649 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 17:43:46 +0200 Subject: [PATCH 35/84] feat(os): Install base-devel and git before we chroot (#3) --- setup.sh | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/setup.sh b/setup.sh index 74ae35c..a65180c 100644 --- a/setup.sh +++ b/setup.sh @@ -705,39 +705,39 @@ function umount_all () { function finalize_os_setup () { #1.15 - set_root_pw #2.1 - configure_networking #2.2 - configure_dns #2.3 - configure_reflector #2.4 - configure_zfs #2.5 - configure_zfs_mount_gen #2.6 - configure_zfsbootmenu #2.7 - gen_zfsbootmenu #2.8 - add_zbm_to_efi #2.9 - umount_all #2.10 + set_root_pw #2.1 + configure_networking #2.2 + configure_dns #2.3 + configure_reflector #2.4 + configure_zfs #2.5 + configure_zfs_mount_gen #2.6 + configure_zfsbootmenu #2.7 + gen_zfsbootmenu #2.8 + add_zbm_to_efi #2.9 + umount_all #2.10 } function main () { if we_are_changerooted; then - install_os_in_chroot #1.16 + install_os_in_chroot #1.16 else - set_ntp #1.1 - update_pacman_db #1.2 - install_pkgs 'jq' #1.3 - install_zfs #1.4 - setup_zpool #1.4 - mount_system #1.5 - copy_zpool_cache #1.6 - install_archlinux #1.7 - gen_fstab #1.8 - set_hostname #1.9 - set_locale #1.10 - add_zfs_hook_to_initramfs #1.11 - set_initramfs_build_list #1.12 - add_zfs_files_to_new_os #1.13 - enter_chroot #1.14 + set_ntp #1.1 + update_pacman_db #1.2 + install_pkgs 'base-devel' 'git' 'jq' #1.3 + install_zfs #1.4 + setup_zpool #1.4 + mount_system #1.5 + copy_zpool_cache #1.6 + install_archlinux #1.7 + gen_fstab #1.8 + set_hostname #1.9 + set_locale #1.10 + add_zfs_hook_to_initramfs #1.11 + set_initramfs_build_list #1.12 + add_zfs_files_to_new_os #1.13 + enter_chroot #1.14 # We're done in chroot - finalize_os_setup #1.15 + finalize_os_setup #1.15 fi } -- 2.47.2 From b63164f2adb74159b28be01891f1c191db73f609 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 18:30:58 +0200 Subject: [PATCH 36/84] feat(os): Give ourselves rsync in chroot (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index a65180c..6d4d9f2 100644 --- a/setup.sh +++ b/setup.sh @@ -565,7 +565,7 @@ function install_os_in_chroot () { add_motd_getting_started_msg get_aur_helper paru_install --replace-conflicting 'paru-bin' - paru_install 'zfs-dkms' 'zfs-utils' + paru_install 'zfs-dkms' 'zfs-utils' 'rsync' hwclock --systohc locale-gen source /etc/locale.conf -- 2.47.2 From 503ab0b58bc5b9c692107f83d08cef0b197a540a Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 18:48:50 +0200 Subject: [PATCH 37/84] feat(os): Replace manually building ZBM UEFI image with AUR package (#3) --- setup.sh | 87 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/setup.sh b/setup.sh index 6d4d9f2..ecabb66 100644 --- a/setup.sh +++ b/setup.sh @@ -41,6 +41,54 @@ function install_pkgs () { pacman -S --needed --noconfirm "${@}" } +function prepare_zfsbootmenu_efi_bin_pkg () { + # Our Arch Linux will use prebuilt ZFSBootMenu UEFI image files for ease + # of use. We'd like to install them from within our chroot but the AUR + # package 'zfsbootmenu-efi-bin' that we're using currently (Friday, + # October 20, 2023) identifies its target EFI system partition (ESP) by + # doing 'lsblk' and checking the partition type name. Since within + # arch-chroot there's no '/run/udev' but only an empty '/run' tmpfs + # 'lsblk' cannot see partition type names and some other pieces of info. + # + # See also + # https://gitlab.archlinux.org/archlinux/arch-install-scripts/-/issues/24 + # + # Thus within arch-chroot the installation of 'zfsbootmenu-efi-bin' and + # even 'makepkg -s' fails. We build the package in our Arch Linux live + # CD ISO image and copy the resulting file into our chroot. + # + # We circle back to the package file when we chroot into Arch and + # install_zbm_image(). + pacman_cache_dir='/var/cache/pacman/pkg' + chroot_pacman_cache_dir='/mnt'"${pacman_cache_dir}" + git_zbm_efi_bin_dir='/tmp/zfsbootmenu-efi-bin' + sudo -u 'arch' git -C '/tmp' clone 'https://aur.archlinux.org/zfsbootmenu-efi-bin.git' + + # We briefly bind-mount our ESP into '/efi' before we build the package. + # Its PKGBUILD will then find the ESP at the correct location and write + # a package file with that internal location ('/efi'). + mkdir -p '/efi' + mount --bind '/mnt/efi' '/efi' + pushd "${git_zbm_efi_bin_dir}" + sudo -u 'arch' makepkg -s || { + printf -- '%s\n' 'Failed building zfsbootmenu-efi-bin package. Exiting ...' + exit 77 + } + popd + umount '/efi' + rmdir '/efi' + + package_file_abs="$(find "${git_zbm_efi_bin_dir}" -type f -iname '*pkg.tar.zst')" + package_file="$(basename "${package_file_abs}")" + mkdir -p "${chroot_pacman_cache_dir}" + rsync -av "${package_file_abs}" "${chroot_pacman_cache_dir}"'/'"${package_file}" || { + printf -- '%s\n' 'Failed rsyncing zfsbootmenu-efi-bin package file into chroot. Exiting ...' + exit 77 + } + export ZFSBOOTMENU_EFI_BIN_PKG_PATH="${pacman_cache_dir}"'/'"${package_file}" + rm -rf "${git_zbm_efi_bin_dir}" +} + function install_zfs () { #1.4 declare reset_colors='\033[0m' @@ -502,6 +550,15 @@ function paru_install () { fi } +function install_zbm_image () { + # This takes image files written earlier in our Arch Linux live CD ISO + # image at prepare_zfsbootmenu_efi_bin_pkg() and installs them via their + # locally built package file. When done we delete the manually built + # package file from pacman's cache dir. + pacman -U "${ZFSBOOTMENU_EFI_BIN_PKG_PATH}" --noconfirm + rm "${ZFSBOOTMENU_EFI_BIN_PKG_PATH}" +} + function keep_initiramfs_root_only_rw () { declare systemd_local_admin_override_path unit_name systemd_local_admin_override_path='/etc/systemd/system' @@ -571,15 +628,8 @@ function install_os_in_chroot () { source /etc/locale.conf mkinitcpio -P - # Install ZFSBootMenu and deps - git clone --depth=1 https://github.com/zbm-dev/zfsbootmenu/ '/tmp/zfsbootmenu' - paru_install 'cpanminus' 'kexec-tools' 'fzf' 'util-linux' - pushd '/tmp/zfsbootmenu' - make - make install - cpanm --notest --installdeps . - popd - rm -rf '/tmp/zfsbootmenu' + # Install ZFSBootMenu image + install_zbm_image } function set_root_pw () { @@ -636,24 +686,6 @@ function configure_zfs_mount_gen () { function configure_zfsbootmenu () { #2.7 - curl -s 'https://raw.githubusercontent.com/zbm-dev/zfsbootmenu/master/etc/zfsbootmenu/mkinitcpio.conf' | sed -r -e '/^#/d' -e '/^$/d' > '/mnt/etc/zfsbootmenu/mkinitcpio.conf' - cat > '/mnt/etc/zfsbootmenu/config.yaml' < Date: Fri, 20 Oct 2023 18:58:25 +0200 Subject: [PATCH 38/84] refactor(meta): Update function numbering (#3) --- setup.sh | 117 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 55 deletions(-) diff --git a/setup.sh b/setup.sh index ecabb66..bcb0c3b 100644 --- a/setup.sh +++ b/setup.sh @@ -42,6 +42,7 @@ function install_pkgs () { } function prepare_zfsbootmenu_efi_bin_pkg () { + #1.4 # Our Arch Linux will use prebuilt ZFSBootMenu UEFI image files for ease # of use. We'd like to install them from within our chroot but the AUR # package 'zfsbootmenu-efi-bin' that we're using currently (Friday, @@ -90,7 +91,7 @@ function prepare_zfsbootmenu_efi_bin_pkg () { } function install_zfs () { - #1.4 + #1.5 declare reset_colors='\033[0m' curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash printf -- "${reset_colors}" @@ -261,7 +262,7 @@ function export_pool () { } function setup_zpool () { - #1.4 + #1.6 local drive_by_id zpool_drive="$(select_part 'zfs')" drive_by_id="$(get_drive_id "${zpool_drive}")" @@ -281,7 +282,7 @@ function setup_zpool () { } function mount_system () { - #1.5 + #1.7 zfs mount "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" zfs mount -a @@ -294,12 +295,13 @@ function mount_system () { } function copy_zpool_cache () { - #1.6 + #1.8 mkdir -p '/mnt/etc/zfs' zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}" } function pacman_dl_parallel () { + #2.4 # We're setting this in Arch Linux ISO CD while we install proper Arch. # No need to revert this later as it is ephemeral anyway. sed -ri -e 's'$'\x1''^.*?(ParallelDownloads)[^\r\n\f]*'$'\x1''\1 = 20'$'\x1''g' '/etc/pacman.conf' @@ -320,7 +322,7 @@ function pacman_dont_check_space () { } function install_archlinux () { - #1.7 + #1.9 pacman_dl_parallel pacman_dont_check_space pacstrap /mnt \ @@ -347,7 +349,7 @@ function install_archlinux () { } function gen_fstab () { - #1.8 + #1.10 genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab' } @@ -360,7 +362,7 @@ EOF } function set_hostname () { - #1.9 + #1.11 declare new_hostname install_pkgs 'pwgen' new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)" @@ -369,7 +371,7 @@ function set_hostname () { } function set_locale () { - #1.10 + #1.12 printf -- '%s\n' \ 'KEYMAP=de-latin1' \ 'FONT=Lat2-Terminus16' \ @@ -380,7 +382,7 @@ function set_locale () { } function add_zfs_hook_to_initramfs () { - #1.11 + #1.13 # Add zfs hook, remove fsck hook from initramfs. sed -ri \ -e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \ @@ -395,7 +397,7 @@ function add_zfs_hook_to_initramfs () { } function set_initramfs_build_list () { - #1.12 + #1.14 # No need to build fallback initramfs, our new fallback is ZFS snapshots sed -ri \ -e '/^#/d' \ @@ -409,14 +411,14 @@ function set_initramfs_build_list () { } function add_zfs_files_to_new_os () { - #1.13 + #1.15 for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do rsync -av --itemize-changes {'','/mnt'}"${zfs_file}" done } function enter_chroot () { - #1.14 + #2.1 arch-chroot /mnt /bin/bash -xe < '/etc/sudoers.d/10-wheel-group-no-passwd-prompt' @@ -551,6 +555,7 @@ function paru_install () { } function install_zbm_image () { + #2.8 # This takes image files written earlier in our Arch Linux live CD ISO # image at prepare_zfsbootmenu_efi_bin_pkg() and installs them via their # locally built package file. When done we delete the manually built @@ -560,6 +565,7 @@ function install_zbm_image () { } function keep_initiramfs_root_only_rw () { + #2.3 declare systemd_local_admin_override_path unit_name systemd_local_admin_override_path='/etc/systemd/system' unit_name='chmod-initramfs' @@ -591,6 +597,7 @@ EOF } function add_motd_getting_started_msg () { + #2.6 cat > '/etc/motd' <<"EOF" #################### @@ -606,7 +613,7 @@ EOF } function install_os_in_chroot () { - #1.16 + #2.2 ### Reinit keyring # As keyring is initialized at boot, and copied to the install dir with pacstrap, and ntp is running # Time changed after keyring initialization, it leads to malfunction @@ -616,11 +623,11 @@ function install_os_in_chroot () { pacman-key --populate archlinux pacman -S archlinux-keyring --noconfirm - keep_initiramfs_root_only_rw - pacman_dl_parallel - unleash_makepkg - add_motd_getting_started_msg - get_aur_helper + keep_initiramfs_root_only_rw #2.3 + pacman_dl_parallel #2.4 + unleash_makepkg #2.5 + add_motd_getting_started_msg #2.6 + get_aur_helper #2.7 paru_install --replace-conflicting 'paru-bin' paru_install 'zfs-dkms' 'zfs-utils' 'rsync' hwclock --systohc @@ -629,16 +636,16 @@ function install_os_in_chroot () { mkinitcpio -P # Install ZFSBootMenu image - install_zbm_image + install_zbm_image #2.8 } function set_root_pw () { - #2.1 + #3.2 printf -- '%s\n' 'root:password' | chpasswd --root '/mnt' } function configure_networking () { - #2.2 + #3.3 cat > '/mnt/etc/systemd/network/50-wired.network' <<"EOF" [Match] Name=en* @@ -656,7 +663,7 @@ EOF } function configure_dns () { - #2.3 + #3.4 rm '/mnt/etc/resolv.conf' ln -s '/run/systemd/resolve/stub-resolv.conf' '/mnt/etc/resolv.conf' @@ -667,17 +674,17 @@ function configure_dns () { } function configure_reflector () { - #2.4 + #3.5 systemctl enable 'reflector' --root='/mnt' } function configure_zfs () { - #2.5 + #3.6 systemctl enable 'zfs-import-cache' 'zfs-mount' 'zfs-import.target' 'zfs.target' --root='/mnt' } function configure_zfs_mount_gen () { - #2.6 + #3.7 mkdir -p '/mnt/etc/zfs/zfs-list.cache' touch '/mnt/etc/zfs/zfs-list.cache/'"${zpool_name}" zfs list -H -o name,mountpoint,canmount,atime,relatime,devices,exec,readonly,setuid,nbmand | sed 's/\/mnt//' > '/mnt/etc/zfs/zfs-list.cache/'"${zpool_name}" @@ -685,12 +692,12 @@ function configure_zfs_mount_gen () { } function configure_zfsbootmenu () { - #2.7 + #3.8 zfs set org.zfsbootmenu:commandline='rw nowatchdog rd.vconsole.keymap=de-latin1' "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" } function gen_zfsbootmenu () { - #2.8 + #3.9 arch-chroot /mnt /bin/bash -xe <<"EOF" source /etc/locale.conf mkdir -p '/efi/EFI/ZBM' @@ -713,7 +720,7 @@ function get_disks_with_one_efipart () { } function add_zbm_to_efi () { - #2.9 + #3.10 if ! efibootmgr | grep -Piq -- 'ZFSBootMenu'; then local efi_disks_list efi_disks_list="$(get_disks_with_one_efipart)" @@ -729,48 +736,48 @@ function add_zbm_to_efi () { } function umount_all () { - #2.10 + #3.11 umount '/mnt/efi' zfs umount -a zpool export "${zpool_name}" } function finalize_os_setup () { - #1.15 - set_root_pw #2.1 - configure_networking #2.2 - configure_dns #2.3 - configure_reflector #2.4 - configure_zfs #2.5 - configure_zfs_mount_gen #2.6 - configure_zfsbootmenu #2.7 - gen_zfsbootmenu #2.8 - add_zbm_to_efi #2.9 - umount_all #2.10 + #3.1 + set_root_pw #3.2 + configure_networking #3.3 + configure_dns #3.4 + configure_reflector #3.5 + configure_zfs #3.6 + configure_zfs_mount_gen #3.7 + configure_zfsbootmenu #3.8 + gen_zfsbootmenu #3.9 + add_zbm_to_efi #3.10 + umount_all #3.11 } function main () { if we_are_changerooted; then - install_os_in_chroot #1.16 + install_os_in_chroot #2.2 else set_ntp #1.1 update_pacman_db #1.2 install_pkgs 'base-devel' 'git' 'jq' #1.3 - prepare_zfsbootmenu_efi_bin_pkg - install_zfs #1.4 - setup_zpool #1.4 - mount_system #1.5 - copy_zpool_cache #1.6 - install_archlinux #1.7 - gen_fstab #1.8 - set_hostname #1.9 - set_locale #1.10 - add_zfs_hook_to_initramfs #1.11 - set_initramfs_build_list #1.12 - add_zfs_files_to_new_os #1.13 - enter_chroot #1.14 + prepare_zfsbootmenu_efi_bin_pkg #1.4 + install_zfs #1.5 + setup_zpool #1.6 + mount_system #1.7 + copy_zpool_cache #1.8 + install_archlinux #1.9 + gen_fstab #1.10 + set_hostname #1.11 + set_locale #1.12 + add_zfs_hook_to_initramfs #1.13 + set_initramfs_build_list #1.14 + add_zfs_files_to_new_os #1.15 + enter_chroot #2.1 # We're done in chroot - finalize_os_setup #1.15 + finalize_os_setup #3.1 fi } -- 2.47.2 From 7a07b18156e24f61ad12d8fd74c6c8dd65519d02 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 19:01:59 +0200 Subject: [PATCH 39/84] fix(os): Write root password with specific --crypt-method (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index bcb0c3b..5f8e9fb 100644 --- a/setup.sh +++ b/setup.sh @@ -641,7 +641,7 @@ function install_os_in_chroot () { function set_root_pw () { #3.2 - printf -- '%s\n' 'root:password' | chpasswd --root '/mnt' + printf -- '%s\n' 'root:password' | chpasswd --crypt-method 'SHA512' --root '/mnt' } function configure_networking () { -- 2.47.2 From 4cebd834de27d9a7fc5d34fc66db973910134f5c Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 19:03:40 +0200 Subject: [PATCH 40/84] fix(os): Enable reflector.timer unit (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 5f8e9fb..11cb49a 100644 --- a/setup.sh +++ b/setup.sh @@ -675,7 +675,7 @@ function configure_dns () { function configure_reflector () { #3.5 - systemctl enable 'reflector' --root='/mnt' + systemctl enable 'reflector.service' 'reflector.timer' --root='/mnt' } function configure_zfs () { -- 2.47.2 From 9550eceaab95d8ed53991871218fcfe264adf4f3 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 19:04:55 +0200 Subject: [PATCH 41/84] feat(os): Replace manually building ZBM UEFI image with AUR package (#3) --- setup.sh | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/setup.sh b/setup.sh index 11cb49a..125ebd0 100644 --- a/setup.sh +++ b/setup.sh @@ -696,16 +696,6 @@ function configure_zfsbootmenu () { zfs set org.zfsbootmenu:commandline='rw nowatchdog rd.vconsole.keymap=de-latin1' "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" } -function gen_zfsbootmenu () { - #3.9 - arch-chroot /mnt /bin/bash -xe <<"EOF" -source /etc/locale.conf -mkdir -p '/efi/EFI/ZBM' -find /efi/EFI/ZBM -type f -delete -generate-zbm -EOF -} - function get_disks_with_one_efipart () { local disks_with_one_efipart # Find disks that have exactly one EFI partition and where that EFI @@ -720,7 +710,7 @@ function get_disks_with_one_efipart () { } function add_zbm_to_efi () { - #3.10 + #3.9 if ! efibootmgr | grep -Piq -- 'ZFSBootMenu'; then local efi_disks_list efi_disks_list="$(get_disks_with_one_efipart)" @@ -736,7 +726,7 @@ function add_zbm_to_efi () { } function umount_all () { - #3.11 + #3.10 umount '/mnt/efi' zfs umount -a zpool export "${zpool_name}" @@ -751,8 +741,7 @@ function finalize_os_setup () { configure_zfs #3.6 configure_zfs_mount_gen #3.7 configure_zfsbootmenu #3.8 - gen_zfsbootmenu #3.9 - add_zbm_to_efi #3.10 + add_zbm_to_efi #3.9 umount_all #3.11 } -- 2.47.2 From c5e0216041dd0bb068518fe775dfe8b03a4d1087 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 19:19:35 +0200 Subject: [PATCH 42/84] fix(os): Increase CoW space before we start (#3) --- setup.sh | 62 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/setup.sh b/setup.sh index 125ebd0..407fc5f 100644 --- a/setup.sh +++ b/setup.sh @@ -26,8 +26,13 @@ function set_ntp () { timedatectl set-ntp true } -function update_pacman_db () { +function resize_cow_space () { #1.2 + mount -o remount,size='50%' /run/archiso/cowspace +} + +function update_pacman_db () { + #1.3 printf -- '%s\n' 'Refreshing mirror list ...' systemctl start reflector # In an ISO and for the minimal number of packages we need we do not @@ -36,13 +41,13 @@ function update_pacman_db () { } function install_pkgs () { - #1.3 + #1.4 printf -- '%s\n' 'Installing packages ...' pacman -S --needed --noconfirm "${@}" } function prepare_zfsbootmenu_efi_bin_pkg () { - #1.4 + #1.5 # Our Arch Linux will use prebuilt ZFSBootMenu UEFI image files for ease # of use. We'd like to install them from within our chroot but the AUR # package 'zfsbootmenu-efi-bin' that we're using currently (Friday, @@ -91,7 +96,7 @@ function prepare_zfsbootmenu_efi_bin_pkg () { } function install_zfs () { - #1.5 + #1.6 declare reset_colors='\033[0m' curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash printf -- "${reset_colors}" @@ -262,7 +267,7 @@ function export_pool () { } function setup_zpool () { - #1.6 + #1.7 local drive_by_id zpool_drive="$(select_part 'zfs')" drive_by_id="$(get_drive_id "${zpool_drive}")" @@ -282,7 +287,7 @@ function setup_zpool () { } function mount_system () { - #1.7 + #1.8 zfs mount "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" zfs mount -a @@ -295,7 +300,7 @@ function mount_system () { } function copy_zpool_cache () { - #1.8 + #1.9 mkdir -p '/mnt/etc/zfs' zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}" } @@ -322,7 +327,7 @@ function pacman_dont_check_space () { } function install_archlinux () { - #1.9 + #1.10 pacman_dl_parallel pacman_dont_check_space pacstrap /mnt \ @@ -349,7 +354,7 @@ function install_archlinux () { } function gen_fstab () { - #1.10 + #1.11 genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab' } @@ -362,7 +367,7 @@ EOF } function set_hostname () { - #1.11 + #1.12 declare new_hostname install_pkgs 'pwgen' new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)" @@ -371,7 +376,7 @@ function set_hostname () { } function set_locale () { - #1.12 + #1.13 printf -- '%s\n' \ 'KEYMAP=de-latin1' \ 'FONT=Lat2-Terminus16' \ @@ -382,7 +387,7 @@ function set_locale () { } function add_zfs_hook_to_initramfs () { - #1.13 + #1.14 # Add zfs hook, remove fsck hook from initramfs. sed -ri \ -e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \ @@ -397,7 +402,7 @@ function add_zfs_hook_to_initramfs () { } function set_initramfs_build_list () { - #1.14 + #1.15 # No need to build fallback initramfs, our new fallback is ZFS snapshots sed -ri \ -e '/^#/d' \ @@ -411,7 +416,7 @@ function set_initramfs_build_list () { } function add_zfs_files_to_new_os () { - #1.15 + #1.16 for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do rsync -av --itemize-changes {'','/mnt'}"${zfs_file}" done @@ -750,20 +755,21 @@ function main () { install_os_in_chroot #2.2 else set_ntp #1.1 - update_pacman_db #1.2 - install_pkgs 'base-devel' 'git' 'jq' #1.3 - prepare_zfsbootmenu_efi_bin_pkg #1.4 - install_zfs #1.5 - setup_zpool #1.6 - mount_system #1.7 - copy_zpool_cache #1.8 - install_archlinux #1.9 - gen_fstab #1.10 - set_hostname #1.11 - set_locale #1.12 - add_zfs_hook_to_initramfs #1.13 - set_initramfs_build_list #1.14 - add_zfs_files_to_new_os #1.15 + resize_cow_space #1.2 + update_pacman_db #1.3 + install_pkgs 'base-devel' 'git' 'jq' #1.4 + prepare_zfsbootmenu_efi_bin_pkg #1.5 + install_zfs #1.6 + setup_zpool #1.7 + mount_system #1.8 + copy_zpool_cache #1.9 + install_archlinux #1.10 + gen_fstab #1.11 + set_hostname #1.12 + set_locale #1.13 + add_zfs_hook_to_initramfs #1.14 + set_initramfs_build_list #1.15 + add_zfs_files_to_new_os #1.16 enter_chroot #2.1 # We're done in chroot finalize_os_setup #3.1 -- 2.47.2 From 362abe39fc4275ada3129bbf3f973e5f8857dc3a Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 19:21:41 +0200 Subject: [PATCH 43/84] fix(os): Install ZFS as a dependency before building zfsbootmenu-efi-bin package (#3) --- setup.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/setup.sh b/setup.sh index 407fc5f..89e0249 100644 --- a/setup.sh +++ b/setup.sh @@ -46,8 +46,15 @@ function install_pkgs () { pacman -S --needed --noconfirm "${@}" } -function prepare_zfsbootmenu_efi_bin_pkg () { +function install_zfs () { #1.5 + declare reset_colors='\033[0m' + curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash + printf -- "${reset_colors}" +} + +function prepare_zfsbootmenu_efi_bin_pkg () { + #1.6 # Our Arch Linux will use prebuilt ZFSBootMenu UEFI image files for ease # of use. We'd like to install them from within our chroot but the AUR # package 'zfsbootmenu-efi-bin' that we're using currently (Friday, @@ -95,13 +102,6 @@ function prepare_zfsbootmenu_efi_bin_pkg () { rm -rf "${git_zbm_efi_bin_dir}" } -function install_zfs () { - #1.6 - declare reset_colors='\033[0m' - curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash - printf -- "${reset_colors}" -} - function get_partitions () { declare partitions_json partitions_json="$(lsblk --output PATH,PARTTYPE --json --tree)" || return 1 @@ -758,8 +758,8 @@ function main () { resize_cow_space #1.2 update_pacman_db #1.3 install_pkgs 'base-devel' 'git' 'jq' #1.4 - prepare_zfsbootmenu_efi_bin_pkg #1.5 - install_zfs #1.6 + install_zfs #1.5 + prepare_zfsbootmenu_efi_bin_pkg #1.6 setup_zpool #1.7 mount_system #1.8 copy_zpool_cache #1.9 -- 2.47.2 From 8ad2694dd4583a6524bfdc34c345bdc23df34435 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 19:26:05 +0200 Subject: [PATCH 44/84] fix(os): Mount chroot before building zfsbootmenu-efi-bin package (#3) --- setup.sh | 108 +++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/setup.sh b/setup.sh index 89e0249..5a5dce5 100644 --- a/setup.sh +++ b/setup.sh @@ -53,55 +53,6 @@ function install_zfs () { printf -- "${reset_colors}" } -function prepare_zfsbootmenu_efi_bin_pkg () { - #1.6 - # Our Arch Linux will use prebuilt ZFSBootMenu UEFI image files for ease - # of use. We'd like to install them from within our chroot but the AUR - # package 'zfsbootmenu-efi-bin' that we're using currently (Friday, - # October 20, 2023) identifies its target EFI system partition (ESP) by - # doing 'lsblk' and checking the partition type name. Since within - # arch-chroot there's no '/run/udev' but only an empty '/run' tmpfs - # 'lsblk' cannot see partition type names and some other pieces of info. - # - # See also - # https://gitlab.archlinux.org/archlinux/arch-install-scripts/-/issues/24 - # - # Thus within arch-chroot the installation of 'zfsbootmenu-efi-bin' and - # even 'makepkg -s' fails. We build the package in our Arch Linux live - # CD ISO image and copy the resulting file into our chroot. - # - # We circle back to the package file when we chroot into Arch and - # install_zbm_image(). - pacman_cache_dir='/var/cache/pacman/pkg' - chroot_pacman_cache_dir='/mnt'"${pacman_cache_dir}" - git_zbm_efi_bin_dir='/tmp/zfsbootmenu-efi-bin' - sudo -u 'arch' git -C '/tmp' clone 'https://aur.archlinux.org/zfsbootmenu-efi-bin.git' - - # We briefly bind-mount our ESP into '/efi' before we build the package. - # Its PKGBUILD will then find the ESP at the correct location and write - # a package file with that internal location ('/efi'). - mkdir -p '/efi' - mount --bind '/mnt/efi' '/efi' - pushd "${git_zbm_efi_bin_dir}" - sudo -u 'arch' makepkg -s || { - printf -- '%s\n' 'Failed building zfsbootmenu-efi-bin package. Exiting ...' - exit 77 - } - popd - umount '/efi' - rmdir '/efi' - - package_file_abs="$(find "${git_zbm_efi_bin_dir}" -type f -iname '*pkg.tar.zst')" - package_file="$(basename "${package_file_abs}")" - mkdir -p "${chroot_pacman_cache_dir}" - rsync -av "${package_file_abs}" "${chroot_pacman_cache_dir}"'/'"${package_file}" || { - printf -- '%s\n' 'Failed rsyncing zfsbootmenu-efi-bin package file into chroot. Exiting ...' - exit 77 - } - export ZFSBOOTMENU_EFI_BIN_PKG_PATH="${pacman_cache_dir}"'/'"${package_file}" - rm -rf "${git_zbm_efi_bin_dir}" -} - function get_partitions () { declare partitions_json partitions_json="$(lsblk --output PATH,PARTTYPE --json --tree)" || return 1 @@ -267,7 +218,7 @@ function export_pool () { } function setup_zpool () { - #1.7 + #1.6 local drive_by_id zpool_drive="$(select_part 'zfs')" drive_by_id="$(get_drive_id "${zpool_drive}")" @@ -287,7 +238,7 @@ function setup_zpool () { } function mount_system () { - #1.8 + #1.7 zfs mount "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" zfs mount -a @@ -299,6 +250,55 @@ function mount_system () { mount "${efi_part}" '/mnt/efi' } +function prepare_zfsbootmenu_efi_bin_pkg () { + #1.8 + # Our Arch Linux will use prebuilt ZFSBootMenu UEFI image files for ease + # of use. We'd like to install them from within our chroot but the AUR + # package 'zfsbootmenu-efi-bin' that we're using currently (Friday, + # October 20, 2023) identifies its target EFI system partition (ESP) by + # doing 'lsblk' and checking the partition type name. Since within + # arch-chroot there's no '/run/udev' but only an empty '/run' tmpfs + # 'lsblk' cannot see partition type names and some other pieces of info. + # + # See also + # https://gitlab.archlinux.org/archlinux/arch-install-scripts/-/issues/24 + # + # Thus within arch-chroot the installation of 'zfsbootmenu-efi-bin' and + # even 'makepkg -s' fails. We build the package in our Arch Linux live + # CD ISO image and copy the resulting file into our chroot. + # + # We circle back to the package file when we chroot into Arch and + # install_zbm_image(). + pacman_cache_dir='/var/cache/pacman/pkg' + chroot_pacman_cache_dir='/mnt'"${pacman_cache_dir}" + git_zbm_efi_bin_dir='/tmp/zfsbootmenu-efi-bin' + sudo -u 'arch' git -C '/tmp' clone 'https://aur.archlinux.org/zfsbootmenu-efi-bin.git' + + # We briefly bind-mount our ESP into '/efi' before we build the package. + # Its PKGBUILD will then find the ESP at the correct location and write + # a package file with that internal location ('/efi'). + mkdir -p '/efi' + mount --bind '/mnt/efi' '/efi' + pushd "${git_zbm_efi_bin_dir}" + sudo -u 'arch' makepkg -s || { + printf -- '%s\n' 'Failed building zfsbootmenu-efi-bin package. Exiting ...' + exit 77 + } + popd + umount '/efi' + rmdir '/efi' + + package_file_abs="$(find "${git_zbm_efi_bin_dir}" -type f -iname '*pkg.tar.zst')" + package_file="$(basename "${package_file_abs}")" + mkdir -p "${chroot_pacman_cache_dir}" + rsync -av "${package_file_abs}" "${chroot_pacman_cache_dir}"'/'"${package_file}" || { + printf -- '%s\n' 'Failed rsyncing zfsbootmenu-efi-bin package file into chroot. Exiting ...' + exit 77 + } + export ZFSBOOTMENU_EFI_BIN_PKG_PATH="${pacman_cache_dir}"'/'"${package_file}" + rm -rf "${git_zbm_efi_bin_dir}" +} + function copy_zpool_cache () { #1.9 mkdir -p '/mnt/etc/zfs' @@ -759,9 +759,9 @@ function main () { update_pacman_db #1.3 install_pkgs 'base-devel' 'git' 'jq' #1.4 install_zfs #1.5 - prepare_zfsbootmenu_efi_bin_pkg #1.6 - setup_zpool #1.7 - mount_system #1.8 + setup_zpool #1.6 + mount_system #1.7 + prepare_zfsbootmenu_efi_bin_pkg #1.8 copy_zpool_cache #1.9 install_archlinux #1.10 gen_fstab #1.11 -- 2.47.2 From 6c25b9211347545343f493e630220715c081869a Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 21:44:30 +0200 Subject: [PATCH 45/84] fix(iso): Force-refresh pkg list, force-upgrade and downgrade pkgs to exactly match repos (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 5a5dce5..76e3a18 100644 --- a/setup.sh +++ b/setup.sh @@ -37,7 +37,7 @@ function update_pacman_db () { systemctl start reflector # In an ISO and for the minimal number of packages we need we do not # care about partial upgrades - pacman -Sy + pacman -Syyuu --noconfirm } function install_pkgs () { -- 2.47.2 From c46c78ba92d09a4599e0e526a844e10d7fc75093 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 21:57:27 +0200 Subject: [PATCH 46/84] refactor(os): Set up locale before we do pacman work (#3) --- setup.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 76e3a18..2590918 100644 --- a/setup.sh +++ b/setup.sh @@ -628,6 +628,9 @@ function install_os_in_chroot () { pacman-key --populate archlinux pacman -S archlinux-keyring --noconfirm + locale-gen + source /etc/locale.conf + keep_initiramfs_root_only_rw #2.3 pacman_dl_parallel #2.4 unleash_makepkg #2.5 @@ -636,8 +639,6 @@ function install_os_in_chroot () { paru_install --replace-conflicting 'paru-bin' paru_install 'zfs-dkms' 'zfs-utils' 'rsync' hwclock --systohc - locale-gen - source /etc/locale.conf mkinitcpio -P # Install ZFSBootMenu image -- 2.47.2 From b34842434e8fba045409cfd9d25a2dca0f025485 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 22:17:13 +0200 Subject: [PATCH 47/84] refactor(os): Get ZFS modules installed before we need them (#3) --- setup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 2590918..b30e5c0 100644 --- a/setup.sh +++ b/setup.sh @@ -637,7 +637,8 @@ function install_os_in_chroot () { add_motd_getting_started_msg #2.6 get_aur_helper #2.7 paru_install --replace-conflicting 'paru-bin' - paru_install 'zfs-dkms' 'zfs-utils' 'rsync' + paru_install 'zfs-dkms' + paru_install 'zfs-utils' 'rsync' hwclock --systohc mkinitcpio -P -- 2.47.2 From 61be86a820298de17fa40a542afbdc5842afdaa0 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 22:34:19 +0200 Subject: [PATCH 48/84] fix(zbm): Update ESP paths to images, install both recovery and release (#3) --- setup.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index b30e5c0..2a85d78 100644 --- a/setup.sh +++ b/setup.sh @@ -725,10 +725,17 @@ function add_zbm_to_efi () { efibootmgr --disk "${efi_drive}" \ --part 1 \ --create \ - --label "ZFSBootMenu" \ - --loader "\EFI\ZBM\vmlinuz.efi" \ + --label "ZFSBootMenu recovery" \ + --loader "\EFI\zbm\zfsbootmenu-recovery-vmlinuz-x86_64.EFI" \ + --verbose + efibootmgr --disk "${efi_drive}" \ + --part 1 \ + --create \ + --label "ZFSBootMenu release" \ + --loader "\EFI\zbm\zfsbootmenu-release-vmlinuz-x86_64.EFI" \ --verbose fi + efibootmgr fi } -- 2.47.2 From 589d66d22b395013addb9f8e6307654fdfac39f8 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 22:47:05 +0200 Subject: [PATCH 49/84] fix(zfs): Make sure root dataset cannot be mounted on accident (#3) --- README.md | 1 + setup.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8fe71e4..386b262 100644 --- a/README.md +++ b/README.md @@ -297,6 +297,7 @@ The ZFS pool and dataset setup that makes this tick, explained in plain English. 1. `-O keylocation=file://...`: This property is only set for encrypted datasets which are encryption roots. Controls where the user's encryption key will be loaded from by default for commands such as `zfs load-key`. 1. `-O keyformat=passphrase`: Controls what format the user's encryption key will be provided as. Passphrases must be between 8 and 512 bytes long. 1. At this time the newly created zpool is not mounted anywhere. Next we create the "root" dataset, that's an arbitary term for the parent dataset of all boot environments. Boot environments in your case may be for example different operating systems all of which live on separate datasets underneath the root. + 1. `-o canmount=off`: Same as above, the root dataset can - just like the pool - not be mounted. 1. `-o mountpoint=none`: Same as above, the root dataset has - just like the pool - no mountpoint configured. 1. `zfs set org.zfsbootmenu:commandline=...`: Set a common kernel command line for all boot environments such as `"ro quiet"`. 1. Neither the root dataset nor the pool are mounted at this time. We now create one boot environment dataset where we want to install Arch Linux. diff --git a/setup.sh b/setup.sh index 2a85d78..f7c96df 100644 --- a/setup.sh +++ b/setup.sh @@ -196,7 +196,7 @@ function create_pool () { } function create_root_dataset () { - zfs create -o mountpoint=none "${zpool_name}"'/root' + zfs create -o mountpoint=none -o canmount=off "${zpool_name}"'/root' # zfs set org.zfsbootmenu:commandline="ro quiet" "${zpool_name}"'/root' zfs set org.zfsbootmenu:commandline="ro" "${zpool_name}"'/root' } -- 2.47.2 From e08697b7faa8a1bce69de8041d3c22dc4dc35495 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Fri, 20 Oct 2023 23:34:31 +0200 Subject: [PATCH 50/84] feat(os): Add a few /etc/motd pointers (#3) --- setup.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.sh b/setup.sh index f7c96df..9a051b5 100644 --- a/setup.sh +++ b/setup.sh @@ -611,6 +611,9 @@ GUI basics: paru -S xorg plasma-meta kde-applications-meta sddm localectl set-x11-keymap de + useradd --create-home --shell /bin/bash --user-group --groups wheel + passwd + systemctl enable --now sddm.service #################### -- 2.47.2 From 8566b414524794649bbdc3801a65293e9b116cbf Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 00:19:30 +0200 Subject: [PATCH 51/84] refactor(iso): Inform user partition's missing (#3) --- setup.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/setup.sh b/setup.sh index 9a051b5..483b1d3 100644 --- a/setup.sh +++ b/setup.sh @@ -136,6 +136,22 @@ function select_part () { parts="$(get_parts "${part_type}")" fi + if [[ ! "${parts}" ]]; then + case "${part_type}" in + efi) + part_type_human_readable='EFI system partition (ESP) with partition type code EF00' + ;; + zfs) + part_type_human_readable='ZFS zpool partition with partition type code BF00' + ;; + esac + printf -- '%s\n' \ + 'It looks as if there is no '"${part_type_human_readable}" \ + 'on any of the disks. Did you correctly partition a disk before starting?' \ + 'Check https://quico.space/quico-os-setup/arch-zbm#prep. Exiting ...' + exit 77 + fi + if we_have_exactly_one_part "${part_type}" "${parts}"; then part="${parts}" else -- 2.47.2 From 40948ddbae080eb8eaa56ef59166fbe2fa5b5c37 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 00:32:16 +0200 Subject: [PATCH 52/84] refactor(meta): Print key log output to stdout without capturing it in subshells (#3) --- setup.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/setup.sh b/setup.sh index 483b1d3..ba51668 100644 --- a/setup.sh +++ b/setup.sh @@ -1,5 +1,7 @@ #!/bin/bash +3>&1 + declare this_script_url this_script_url="${SCRIPT_URL:?}" @@ -81,7 +83,7 @@ function get_parts () { parts="$(get_partitions | jq --raw-output '.[][] | select(.children | length > 0) | select(.path=="'"${zfs_install_drive:?}"'") | .children[] | select(.parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b") | .path')" || exit 1 ;; *) - >2 printf -- '%s\n' 'Unknown partition type '"'"'"${parttype}"'"'"', exiting ...' + >&3 printf -- '%s\n' 'Unknown partition type '"'"'"${parttype}"'"'"', exiting ...' exit 77 ;; esac @@ -97,7 +99,7 @@ function we_have_exactly_one_part () { if [[ "$(wc -c <<<"${parts_list}")" -gt '1' ]]; then case "${parts_count}" in 0) - >2 printf -- '%s\n' 'No '"${parttype^^}"' partition found. Exiting ...' + >&3 printf -- '%s\n' 'No '"${parttype^^}"' partition found. Exiting ...' exit 77 ;; 1) @@ -107,7 +109,7 @@ function we_have_exactly_one_part () { return 1 ;; esac - >2 printf -- '%s\n' 'Partition list does not look valid. Cowardly exiting ...' + >&3 printf -- '%s\n' 'Partition list does not look valid. Cowardly exiting ...' exit 77 fi } @@ -120,7 +122,7 @@ function get_drive_id () { printf -- '%s' "${drive_id_single}" return 0 fi - >2 printf -- '%s\n' 'No '"'${1:?}'"' partition entry in /dev/disk/by-partuuid, exiting ...' + >&3 printf -- '%s\n' 'No '"'${1:?}'"' partition entry in /dev/disk/by-partuuid, exiting ...' exit 77 } @@ -145,7 +147,7 @@ function select_part () { part_type_human_readable='ZFS zpool partition with partition type code BF00' ;; esac - printf -- '%s\n' \ + >&3 printf -- '%s\n' \ 'It looks as if there is no '"${part_type_human_readable}" \ 'on any of the disks. Did you correctly partition a disk before starting?' \ 'Check https://quico.space/quico-os-setup/arch-zbm#prep. Exiting ...' @@ -155,7 +157,7 @@ function select_part () { if we_have_exactly_one_part "${part_type}" "${parts}"; then part="${parts}" else - 2> printf -- '%s\n' 'More than one '"${part_type^^}"' partition to pick for installation. Cowardly exiting ...' + >&3 printf -- '%s\n' 'More than one '"${part_type^^}"' partition to pick for installation. Cowardly exiting ...' exit 77 fi printf -- '%s' "${part}" -- 2.47.2 From b5c9ba4127bf5627ea17988f69c188793b0a5af8 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 00:34:13 +0200 Subject: [PATCH 53/84] refactor(meta): Print key log output to stdout without capturing it in subshells (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index ba51668..ea39ddc 100644 --- a/setup.sh +++ b/setup.sh @@ -1,6 +1,6 @@ #!/bin/bash -3>&1 +exec 3>&1 declare this_script_url this_script_url="${SCRIPT_URL:?}" -- 2.47.2 From c7e59ba0cbc387ac8b05257b553d1e70c8f509c4 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 00:56:26 +0200 Subject: [PATCH 54/84] refactor(meta): Explain fd 3 logging and add more of it (#3) --- setup.sh | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/setup.sh b/setup.sh index ea39ddc..e4d7a01 100644 --- a/setup.sh +++ b/setup.sh @@ -1,5 +1,19 @@ #!/bin/bash +# Whatever comes in on file descriptor (FD) 3 gets redirected to where file +# descriptor 1 is pointing. File descriptor 1 points to stdout so when we +# output-redirect something into FD 3 it shows up on stdout. We can use this +# to produce arbitrary logging output inside a subshell like so: +# +# function my_func () { +# some_command "${1:?}" +# >&3 echo 'A log message' +# } +# +# var="$(my_func arg_1)" +# +# Here "${var}" will only capture the output of some_command "${1:?}". It +# will not capture 'echo' which will instead show up on our stdout/FD 1. exec 3>&1 declare this_script_url @@ -250,7 +264,7 @@ function setup_zpool () { export_pool import_pool else - printf -- '%s\n' 'A zpool already exists, that is unexpected. Cowardly exiting 1 ...' + >&3 printf -- '%s\n' 'A zpool already exists, that is unexpected. Cowardly exiting 1 ...' exit 1 fi } @@ -299,7 +313,7 @@ function prepare_zfsbootmenu_efi_bin_pkg () { mount --bind '/mnt/efi' '/efi' pushd "${git_zbm_efi_bin_dir}" sudo -u 'arch' makepkg -s || { - printf -- '%s\n' 'Failed building zfsbootmenu-efi-bin package. Exiting ...' + >&3 printf -- '%s\n' 'Failed building zfsbootmenu-efi-bin package. Exiting ...' exit 77 } popd @@ -310,7 +324,7 @@ function prepare_zfsbootmenu_efi_bin_pkg () { package_file="$(basename "${package_file_abs}")" mkdir -p "${chroot_pacman_cache_dir}" rsync -av "${package_file_abs}" "${chroot_pacman_cache_dir}"'/'"${package_file}" || { - printf -- '%s\n' 'Failed rsyncing zfsbootmenu-efi-bin package file into chroot. Exiting ...' + >&3 printf -- '%s\n' 'Failed rsyncing zfsbootmenu-efi-bin package file into chroot. Exiting ...' exit 77 } export ZFSBOOTMENU_EFI_BIN_PKG_PATH="${pacman_cache_dir}"'/'"${package_file}" @@ -539,7 +553,7 @@ function paru_install () { [[ "${1}" ]] && while :; do case "${1}" in -[[:alnum:]]*) - printf -- '%s\n' \ + >&3 printf -- '%s\n' \ 'Short-form argument '"'${1}'"' not supported for function '"'${FUNCNAME[0]}()'"'. Only known accepted argument' \ 'is '"'"'--replace-conflicting'"'"' without a value given. Exiting ...' exit 77 @@ -550,7 +564,7 @@ function paru_install () { continue ;; --*) - printf -- '%s\n' \ + >&3 printf -- '%s\n' \ 'Long-form argument '"'${1}'"' not supported for function '"'${FUNCNAME[0]}()'"'. Only known accepted argument' \ 'is '"'"'--replace-conflicting'"'"' without a value given. Exiting ...' exit 77 @@ -565,7 +579,7 @@ function paru_install () { ;; esac done || { - printf -- '%s\n' \ + >&3 printf -- '%s\n' \ 'No argument '"'${1}'"' given for function '"'${FUNCNAME[0]}'"'. Exiting ...' exit 77 } -- 2.47.2 From de4f3f2066bc1a356028f284a27cf74c452f672e Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 00:57:32 +0200 Subject: [PATCH 55/84] refactor(os): Do normal pacman installs, don't prepend keyring nor ZFS installs (#3) --- setup.sh | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/setup.sh b/setup.sh index e4d7a01..a0ee3f2 100644 --- a/setup.sh +++ b/setup.sh @@ -461,54 +461,6 @@ curl --silent '${this_script_url}' | bash EOF } -function get_pkg_info () { - declare from_where local_pkg_info local_pkg_version version_search - from_where="${1}" - version_search='/Version/{print $3}' - pkg_info="$(paru -$([[ "${from_where}" == 'local' ]] && printf -- '%s' 'Q' || printf -- '%s' 'S')i "${2}" 2>&1)" - if [[ "${from_where}" == 'local' ]] && grep -Piq -- '^error: package .*? was not found' <<<"${pkg_info}"; then - return 1 - else - local_pkg_version="$(awk "${version_search}" <<<"${pkg_info}")" - fi - printf -- '%s' "${local_pkg_version}" - return 0 -} - -function paru_with_zfs_first () { - if [[ "${#}" -eq '0' ]]; then - declare -A local_pkg_info - /usr/bin/paru -Sy - if local_pkg_info['zfs-dkms']="$(get_pkg_info 'local' 'zfs-dkms')" && local_pkg_info['zfs-utils']="$(get_pkg_info 'local' 'zfs-utils')"; then - local_pkg_info['zfs-dkms']="$(get_pkg_info 'local' 'zfs-dkms')" - local_pkg_info['zfs-utils']="$(get_pkg_info 'local' 'zfs-utils')" - - declare -A remote_pkg_info - remote_pkg_info['zfs-dkms']="$(get_pkg_info 'remote' 'zfs-dkms')" - remote_pkg_info['zfs-utils']="$(get_pkg_info 'remote' 'zfs-utils')" - - /usr/bin/paru -S --needed archlinux-keyring - - if [[ "${local_pkg_info['zfs-dkms']}" == "${remote_pkg_info['zfs-dkms']}" ]] && \ - [[ "${local_pkg_info['zfs-utils']}" == "${remote_pkg_info['zfs-utils']}" ]]; then - /usr/bin/paru -Su - else - /usr/bin/paru -Sy 'zfs-dkms' 'zfs-utils' \ - --assume-installed zfs-dkms="${local_pkg_info['zfs-dkms']}" \ - --assume-installed zfs-dkms="${remote_pkg_info['zfs-dkms']}" \ - --assume-installed zfs-utils="${local_pkg_info['zfs-utils']}" \ - --assume-installed zfs-utils="${remote_pkg_info['zfs-utils']}" - /usr/bin/paru -Su - fi - else - /usr/bin/paru -S --needed archlinux-keyring - /usr/bin/paru -Su - fi - else - /usr/bin/paru "${@}" - fi -} - function create_unpriv_user () { account_name="${1:?}" full_name="${2:-${account_name}}" @@ -545,7 +497,6 @@ function get_aur_helper () { popd rm -rf 'paru' popd - alias paru='paru_with_zfs_first' } function paru_install () { -- 2.47.2 From e92a22c005115eb7a8bcf03c16662740537c6f46 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 00:57:57 +0200 Subject: [PATCH 56/84] refactor(meta): Quoting because we can (#3) --- setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index a0ee3f2..57aa8b5 100644 --- a/setup.sh +++ b/setup.sh @@ -535,10 +535,10 @@ function paru_install () { exit 77 } if [[ "${pacman_force_yes}" ]]; then - yes 'y' | sudo --user build paru -S "${paru_install_packages[@]}" + yes 'y' | sudo --user 'build' paru -S "${paru_install_packages[@]}" unset -v pacman_force_yes else - sudo --user build paru -S --noconfirm "${paru_install_packages[@]}" + sudo --user 'build' paru -S --noconfirm "${paru_install_packages[@]}" fi } -- 2.47.2 From da88ec53a6e2f5e540051327daff3f7a2e58753a Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 00:58:23 +0200 Subject: [PATCH 57/84] refactor(meta): ZFS installs in one go should now work (#3) --- setup.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 57aa8b5..acc9d95 100644 --- a/setup.sh +++ b/setup.sh @@ -623,8 +623,7 @@ function install_os_in_chroot () { add_motd_getting_started_msg #2.6 get_aur_helper #2.7 paru_install --replace-conflicting 'paru-bin' - paru_install 'zfs-dkms' - paru_install 'zfs-utils' 'rsync' + paru_install 'zfs-dkms' 'zfs-utils' 'rsync' hwclock --systohc mkinitcpio -P -- 2.47.2 From b0c50f33232e105db533c9d9e3b492e21931223d Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 01:25:22 +0200 Subject: [PATCH 58/84] refactor(os): Get ZFS modules installed before we need them (#3) --- setup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index acc9d95..57aa8b5 100644 --- a/setup.sh +++ b/setup.sh @@ -623,7 +623,8 @@ function install_os_in_chroot () { add_motd_getting_started_msg #2.6 get_aur_helper #2.7 paru_install --replace-conflicting 'paru-bin' - paru_install 'zfs-dkms' 'zfs-utils' 'rsync' + paru_install 'zfs-dkms' + paru_install 'zfs-utils' 'rsync' hwclock --systohc mkinitcpio -P -- 2.47.2 From b36d4d33c328bbc338423a9b5c31f70a0619bebb Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 01:54:28 +0200 Subject: [PATCH 59/84] refactor(os): pacman install in one go (#3) --- setup.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 57aa8b5..acc9d95 100644 --- a/setup.sh +++ b/setup.sh @@ -623,8 +623,7 @@ function install_os_in_chroot () { add_motd_getting_started_msg #2.6 get_aur_helper #2.7 paru_install --replace-conflicting 'paru-bin' - paru_install 'zfs-dkms' - paru_install 'zfs-utils' 'rsync' + paru_install 'zfs-dkms' 'zfs-utils' 'rsync' hwclock --systohc mkinitcpio -P -- 2.47.2 From abffd08c1e962717bf07a7c8b7e8ff94230bce86 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 04:48:11 +0200 Subject: [PATCH 60/84] feat(zbm): Add ZBM postconf hook to update UEFI bootnums (#3) --- zbm_set_new_uefi_boot_entries.sh | 177 +++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 zbm_set_new_uefi_boot_entries.sh diff --git a/zbm_set_new_uefi_boot_entries.sh b/zbm_set_new_uefi_boot_entries.sh new file mode 100644 index 0000000..bbf27ed --- /dev/null +++ b/zbm_set_new_uefi_boot_entries.sh @@ -0,0 +1,177 @@ +#!/bin/bash + +# Whatever comes in on file descriptor (FD) 3 gets redirected to where file +# descriptor 1 is pointing. File descriptor 1 points to stdout so when we +# output-redirect something into FD 3 it shows up on stdout. We can use this +# to produce arbitrary logging output inside a subshell like so: +# +# function my_func () { +# some_command "${1:?}" +# >&3 echo 'A log message' +# } +# +# var="$(my_func arg_1)" +# +# Here "${var}" will only capture the output of some_command "${1:?}". It +# will not capture 'echo' which will instead show up on our stdout/FD 1. +exec 3>&1 + +# https://unix.stackexchange.com/a/48550 +set -E +trap '[ "$?" -ne 77 ] || exit 77' ERR + +function get_partitions () { + declare partitions_json + partitions_json="$(lsblk --output PATH,PARTTYPE --json --tree)" || return 1 + printf -- '%s' "${partitions_json}" + return 0 +} + +function get_parts () { + local zfs_install_drive + declare parttype parts + parttype="${1:?}" + zfs_install_drive="${2:-}" + case "${parttype}" in + zfs) + parts="$(get_partitions | jq --raw-output '.[][] | select(.children | length > 0) | .children[] | select(.parttype=="6a85cf4d-1dd2-11b2-99a6-080020736631") | .path')" || exit 1 + ;; + efi) + parts="$(get_partitions | jq --raw-output '.[][] | select(.children | length > 0) | select(.path=="'"${zfs_install_drive:?}"'") | .children[] | select(.parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b") | .path')" || exit 1 + ;; + *) + >&3 printf -- '%s\n' 'Unknown partition type '"'"'"${parttype}"'"'"', exiting ...' + exit 77 + ;; + esac + printf -- '%s' "${parts}" + return 0 +} + +function we_have_exactly_one_part () { + local parttype parts_list parts_count + parttype="${1:?}" + parts_list="${2:?}" + parts_count="$(wc -l <<<"${parts_list}")" + if [[ "$(wc -c <<<"${parts_list}")" -gt '1' ]]; then + case "${parts_count}" in + 0) + >&3 printf -- '%s\n' 'No '"${parttype^^}"' partition found. Exiting ...' + exit 77 + ;; + 1) + return 0 + ;; + *) + return 1 + ;; + esac + >&3 printf -- '%s\n' 'Partition list does not look valid. Cowardly exiting ...' + exit 77 + fi +} + +function select_part () { + local parts enriched_parts enriched_parts_count part_number part_type zfs_install_drive + declare part + part_type="${1:?}" # 'efi' or 'zfs' + zfs_install_drive="${2:-}" + if [[ "${zfs_install_drive}" ]]; then + # This is intended to find correct EFI partition + parts="$(get_parts "${part_type}" "${zfs_install_drive}")" + else + parts="$(get_parts "${part_type}")" + fi + + if [[ ! "${parts}" ]]; then + case "${part_type}" in + efi) + part_type_human_readable='EFI system partition (ESP) with partition type code EF00' + ;; + zfs) + part_type_human_readable='ZFS zpool partition with partition type code BF00' + ;; + esac + >&3 printf -- '%s\n' \ + 'It looks as if there is no '"${part_type_human_readable}" \ + 'on any of the disks. Did you correctly partition a disk before starting?' \ + 'Check https://quico.space/quico-os-setup/arch-zbm#prep. Exiting ...' + exit 77 + fi + + if we_have_exactly_one_part "${part_type}" "${parts}"; then + part="${parts}" + else + >&3 printf -- '%s\n' 'More than one '"${part_type^^}"' partition to pick for installation. Cowardly exiting ...' + exit 77 + fi + printf -- '%s' "${part}" + return 0 +} + +function get_part_parent () { + local child_partition parent_partition + child_partition="${1:?}" + parent_partition="$(get_partitions | jq --raw-output '.[][] | select(.children | length > 0) | select(.children[].path=="'"${child_partition:?}"'") | .path')" + printf -- '%s' "${parent_partition}" + return 0 +} + +function get_disks_with_one_efipart () { + local disks_with_one_efipart + # Find disks that have exactly one EFI partition and where that EFI + # partition is partition number 1. We expect exactly one disk to meet + # these criteria. Anything else and we bail. + disks_with_one_efipart="$(lsblk --output PATH,PARTTYPE --json --tree | jq --raw-output '.[][] | select(.children | length > 0) | select( any (.children[]; (.path | test("^[^[:digit:]]+1")) and (.parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) and ([select(.children[].parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b")] | length == 1) ) | .path')" + if [[ "$(wc -l <<<"${disks_with_one_efipart}")" -eq '1' ]] && [[ "$(wc -c <<<"${disks_with_one_efipart}")" -gt '1' ]]; then + printf -- '%s' "${disks_with_one_efipart}" + return 0 + fi + return 1 +} + +function set_new_uefi_boot_entries () { + declare -a uefi_images + mapfile -t uefi_images < \ + <(find '/efi/EFI/ZBM' -type f -iname '*.efi' -print0 | \ + xargs -0 --no-run-if-empty --max-args '1' stat -c '%Y %n' | \ + sort -V | \ + awk '{print $2}') + zpool_drive="$(select_part 'zfs')" + zfs_parent="$(get_part_parent "${zpool_drive:?}")" + efi_drive="${zfs_parent}" + + if efibootmgr | grep -Piq -- 'ZFSBootMenu'; then + local -a old_uefi_entries + mapfile -t old_uefi_entries < \ + <(efibootmgr | \ + grep -Pio -- '(?<=^Boot)[^\*[:space:]]+(?=\*? ZFSBootMenu)') + for old_uefi_entry in "${old_uefi_entries[@]}"; do + efibootmgr --bootnum "${old_uefi_entry}" --delete-bootnum &>/dev/null && { + >&3 printf -- '%s\n' \ + 'EFI boot entry '"${old_uefi_entry}"' deleted.' + } + done + fi + + if ! efibootmgr | grep -Piq -- 'ZFSBootMenu'; then + local efi_disks_list + efi_disks_list="$(get_disks_with_one_efipart)" + if grep -Piq -- '^'"${efi_drive}"'$' <<<"${efi_disks_list}"; then + for uefi_image in "${uefi_images[@]}"; do + uefi_image_version="$(basename "${uefi_image##*-}")" + uefi_image_version="${uefi_image_version%%.EFI}" + uefi_image_inverted="${uefi_image#/mnt/efi}" + uefi_image_inverted="${uefi_image_inverted//\//\\}" + efibootmgr --disk "${efi_drive}" \ + --part 1 \ + --create \ + --label 'ZFSBootMenu '"${uefi_image_version}" \ + --loader "${uefi_image_inverted}" &>/dev/null && { + >&3 printf -- '%s\n' \ + 'EFI boot entry ZFSBootMenu '"${uefi_image_version}"' added.' + } + done + fi + fi +} -- 2.47.2 From be63ed90adc6dccf12e11ebf1b05a25d429f05c3 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 05:03:09 +0200 Subject: [PATCH 61/84] refactor(zbm): We're not building in Arch Linux live CD ISO image (#3) We don't need rsync anymore either since we won't have to shuffle UEFI images around. --- setup.sh | 51 +-------------------------------------------------- 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/setup.sh b/setup.sh index acc9d95..46c57fc 100644 --- a/setup.sh +++ b/setup.sh @@ -282,55 +282,6 @@ function mount_system () { mount "${efi_part}" '/mnt/efi' } -function prepare_zfsbootmenu_efi_bin_pkg () { - #1.8 - # Our Arch Linux will use prebuilt ZFSBootMenu UEFI image files for ease - # of use. We'd like to install them from within our chroot but the AUR - # package 'zfsbootmenu-efi-bin' that we're using currently (Friday, - # October 20, 2023) identifies its target EFI system partition (ESP) by - # doing 'lsblk' and checking the partition type name. Since within - # arch-chroot there's no '/run/udev' but only an empty '/run' tmpfs - # 'lsblk' cannot see partition type names and some other pieces of info. - # - # See also - # https://gitlab.archlinux.org/archlinux/arch-install-scripts/-/issues/24 - # - # Thus within arch-chroot the installation of 'zfsbootmenu-efi-bin' and - # even 'makepkg -s' fails. We build the package in our Arch Linux live - # CD ISO image and copy the resulting file into our chroot. - # - # We circle back to the package file when we chroot into Arch and - # install_zbm_image(). - pacman_cache_dir='/var/cache/pacman/pkg' - chroot_pacman_cache_dir='/mnt'"${pacman_cache_dir}" - git_zbm_efi_bin_dir='/tmp/zfsbootmenu-efi-bin' - sudo -u 'arch' git -C '/tmp' clone 'https://aur.archlinux.org/zfsbootmenu-efi-bin.git' - - # We briefly bind-mount our ESP into '/efi' before we build the package. - # Its PKGBUILD will then find the ESP at the correct location and write - # a package file with that internal location ('/efi'). - mkdir -p '/efi' - mount --bind '/mnt/efi' '/efi' - pushd "${git_zbm_efi_bin_dir}" - sudo -u 'arch' makepkg -s || { - >&3 printf -- '%s\n' 'Failed building zfsbootmenu-efi-bin package. Exiting ...' - exit 77 - } - popd - umount '/efi' - rmdir '/efi' - - package_file_abs="$(find "${git_zbm_efi_bin_dir}" -type f -iname '*pkg.tar.zst')" - package_file="$(basename "${package_file_abs}")" - mkdir -p "${chroot_pacman_cache_dir}" - rsync -av "${package_file_abs}" "${chroot_pacman_cache_dir}"'/'"${package_file}" || { - >&3 printf -- '%s\n' 'Failed rsyncing zfsbootmenu-efi-bin package file into chroot. Exiting ...' - exit 77 - } - export ZFSBOOTMENU_EFI_BIN_PKG_PATH="${pacman_cache_dir}"'/'"${package_file}" - rm -rf "${git_zbm_efi_bin_dir}" -} - function copy_zpool_cache () { #1.9 mkdir -p '/mnt/etc/zfs' @@ -623,7 +574,7 @@ function install_os_in_chroot () { add_motd_getting_started_msg #2.6 get_aur_helper #2.7 paru_install --replace-conflicting 'paru-bin' - paru_install 'zfs-dkms' 'zfs-utils' 'rsync' + paru_install 'zfs-dkms' 'zfs-utils' 'jq' hwclock --systohc mkinitcpio -P -- 2.47.2 From dcc3cf7d93e2cd68ad7e65ad799daa5acacf61b5 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 05:05:17 +0200 Subject: [PATCH 62/84] refactor(zbm): Streamline ZBM image creation (#3) --- setup.sh | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/setup.sh b/setup.sh index 46c57fc..b2d9da7 100644 --- a/setup.sh +++ b/setup.sh @@ -493,14 +493,29 @@ function paru_install () { fi } -function install_zbm_image () { - #2.8 - # This takes image files written earlier in our Arch Linux live CD ISO - # image at prepare_zfsbootmenu_efi_bin_pkg() and installs them via their - # locally built package file. When done we delete the manually built - # package file from pacman's cache dir. - pacman -U "${ZFSBOOTMENU_EFI_BIN_PKG_PATH}" --noconfirm - rm "${ZFSBOOTMENU_EFI_BIN_PKG_PATH}" +function configure_zfsbootmenu () { + #3.8 + #FIXME + paru_install 'zfsbootmenu' + mkdir -p '/etc/zfsbootmenu/posthooks.d' + cat > '/etc/zfsbootmenu/config.yaml' < Date: Sat, 21 Oct 2023 05:07:02 +0200 Subject: [PATCH 63/84] refactor(zbm): Add ZBM postconf hook (#3) We're adding this to our chroot after we've generated a ZBM UEFI image file /without/ this hook script. It's meant to run only in our real OS. --- setup.sh | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/setup.sh b/setup.sh index b2d9da7..db72c73 100644 --- a/setup.sh +++ b/setup.sh @@ -18,6 +18,7 @@ exec 3>&1 declare this_script_url this_script_url="${SCRIPT_URL:?}" +postconf_hook="$(dirname "${this_script_url}")"'/zbm_set_new_uefi_boot_entries.sh' declare zpool_name zfs_arch_dataset_name zpool_name='zpool' @@ -674,21 +675,10 @@ function add_zbm_to_efi () { local efi_disks_list efi_disks_list="$(get_disks_with_one_efipart)" if grep -Piq -- '^'"${efi_drive}"'$' <<<"${efi_disks_list}"; then - efibootmgr --disk "${efi_drive}" \ - --part 1 \ - --create \ - --label "ZFSBootMenu recovery" \ - --loader "\EFI\zbm\zfsbootmenu-recovery-vmlinuz-x86_64.EFI" \ - --verbose - efibootmgr --disk "${efi_drive}" \ - --part 1 \ - --create \ - --label "ZFSBootMenu release" \ - --loader "\EFI\zbm\zfsbootmenu-release-vmlinuz-x86_64.EFI" \ - --verbose - fi - efibootmgr - fi +function insert_zbm_postconf_hook () { + declare postconf_target_abs='/mnt/etc/zfsbootmenu/posthooks.d/'"$(basename "${postconf_hook}")" + curl --silent --location "${postconf_hook}" --output "${postconf_target_abs}" + chmod +x "${postconf_target_abs}" } function umount_all () { @@ -707,7 +697,7 @@ function finalize_os_setup () { configure_zfs #3.6 configure_zfs_mount_gen #3.7 configure_zfsbootmenu #3.8 - add_zbm_to_efi #3.9 + insert_zbm_postconf_hook umount_all #3.11 } -- 2.47.2 From 915ded9c1bb3901180231e55fb66d5d9e887f2a1 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 05:08:22 +0200 Subject: [PATCH 64/84] refactor(zbm): Update UEFI boot entries when images are done (#3) --- setup.sh | 60 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/setup.sh b/setup.sh index db72c73..e6149c1 100644 --- a/setup.sh +++ b/setup.sh @@ -651,30 +651,50 @@ function configure_zfs_mount_gen () { systemctl enable 'zfs-zed.service' --root='/mnt' } -function configure_zfsbootmenu () { - #3.8 - zfs set org.zfsbootmenu:commandline='rw nowatchdog rd.vconsole.keymap=de-latin1' "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" -} - -function get_disks_with_one_efipart () { - local disks_with_one_efipart - # Find disks that have exactly one EFI partition and where that EFI - # partition is partition number 1. We expect exactly one disk to meet - # these criteria. Anything else and we bail. - disks_with_one_efipart="$(lsblk --output PATH,PARTTYPE --json --tree | jq --raw-output '.[][] | select(.children | length > 0) | select( any (.children[]; (.path | test("^[^[:digit:]]+1")) and (.parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) and ([select(.children[].parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b")] | length == 1) ) | .path')" - if [[ "$(wc -l <<<"${disks_with_one_efipart}")" -eq '1' ]] && [[ "$(wc -c <<<"${disks_with_one_efipart}")" -gt '1' ]]; then - printf -- '%s' "${disks_with_one_efipart}" - return 0 - fi - return 1 -} - -function add_zbm_to_efi () { +function set_new_uefi_boot_entries () { #3.9 + declare -a uefi_images + mapfile -t uefi_images < \ + <(find '/mnt/efi/EFI/ZBM' -type f -iname '*.efi' -print0 | \ + xargs -0 --no-run-if-empty --max-args '1' stat -c '%Y %n' | \ + sort -V | \ + awk '{print $2}') + + if efibootmgr | grep -Piq -- 'ZFSBootMenu'; then + local -a old_uefi_entries + mapfile -t old_uefi_entries < \ + <(efibootmgr | \ + grep -Pio -- '(?<=^Boot)[^\*[:space:]]+(?=\*? ZFSBootMenu)') + for old_uefi_entry in "${old_uefi_entries[@]}"; do + efibootmgr --bootnum "${old_uefi_entry}" --delete-bootnum &>/dev/null && { + >&3 printf -- '%s\n' \ + 'EFI boot entry '"${old_uefi_entry}"' deleted.' + } + done + fi + if ! efibootmgr | grep -Piq -- 'ZFSBootMenu'; then local efi_disks_list efi_disks_list="$(get_disks_with_one_efipart)" if grep -Piq -- '^'"${efi_drive}"'$' <<<"${efi_disks_list}"; then + for uefi_image in "${uefi_images[@]}"; do + uefi_image_version="$(basename "${uefi_image##*-}")" + uefi_image_version="${uefi_image_version%%.EFI}" + uefi_image_inverted="${uefi_image#/mnt/efi}" + uefi_image_inverted="${uefi_image_inverted//\//\\}" + efibootmgr --disk "${efi_drive}" \ + --part 1 \ + --create \ + --label 'ZFSBootMenu '"${uefi_image_version}" \ + --loader "${uefi_image_inverted}" &>/dev/null && { + >&3 printf -- '%s\n' \ + 'EFI boot entry ZFSBootMenu '"${uefi_image_version}"' added.' + } + done + fi + fi +} + function insert_zbm_postconf_hook () { declare postconf_target_abs='/mnt/etc/zfsbootmenu/posthooks.d/'"$(basename "${postconf_hook}")" curl --silent --location "${postconf_hook}" --output "${postconf_target_abs}" @@ -696,7 +716,7 @@ function finalize_os_setup () { configure_reflector #3.5 configure_zfs #3.6 configure_zfs_mount_gen #3.7 - configure_zfsbootmenu #3.8 + set_new_uefi_boot_entries #3.9 insert_zbm_postconf_hook umount_all #3.11 } -- 2.47.2 From 767e9c3b423cbcae94923dbba6b2639b6be88d7f Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 05:09:25 +0200 Subject: [PATCH 65/84] refactor(meta): Reorder functions (#3) --- setup.sh | 139 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 63 deletions(-) diff --git a/setup.sh b/setup.sh index e6149c1..888ef5d 100644 --- a/setup.sh +++ b/setup.sh @@ -289,13 +289,6 @@ function copy_zpool_cache () { zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}" } -function pacman_dl_parallel () { - #2.4 - # We're setting this in Arch Linux ISO CD while we install proper Arch. - # No need to revert this later as it is ephemeral anyway. - sed -ri -e 's'$'\x1''^.*?(ParallelDownloads)[^\r\n\f]*'$'\x1''\1 = 20'$'\x1''g' '/etc/pacman.conf' -} - function pacman_dont_check_space () { # See pacman bug comment # https://bugs.archlinux.org/task/45070#comment142712 @@ -406,13 +399,6 @@ function add_zfs_files_to_new_os () { done } -function enter_chroot () { - #2.1 - arch-chroot /mnt /bin/bash -xe < "${path_unit}" <<"EOF" +[Unit] +Description=chmod initramfs to be root-read-writable only + +[Path] +PathChanged=/boot/initramfs-linux.img + +[Install] +WantedBy=multi-user.target +WantedBy=system-update.target +EOF + + cat > "${service_unit}" <<"EOF" +[Unit] +Description=chmod initramfs to be root-read-writable only + +[Service] +Type=oneshot +ExecStart=/usr/bin/chmod 600 /boot/initramfs-linux.img +EOF + + systemctl enable "${path_unit}" +} + +function pacman_dl_parallel () { + #2.4 + # We're setting this in Arch Linux ISO CD while we install proper Arch. + # No need to revert this later as it is ephemeral anyway. + sed -ri -e 's'$'\x1''^.*?(ParallelDownloads)[^\r\n\f]*'$'\x1''\1 = 20'$'\x1''g' '/etc/pacman.conf' +} + function unleash_makepkg () { #2.5 local path_prefix @@ -436,6 +468,25 @@ function unleash_makepkg () { "${path_prefix}"'/etc/makepkg.conf' } +function add_motd_getting_started_msg () { + #2.6 + cat > '/etc/motd' <<"EOF" + +#################### + +GUI basics: + + paru -S xorg plasma-meta kde-applications-meta sddm + localectl set-x11-keymap de + useradd --create-home --shell /bin/bash --user-group --groups wheel + passwd + systemctl enable --now sddm.service + +#################### + +EOF +} + function get_aur_helper () { #2.7 create_unpriv_user 'build' @@ -519,55 +570,17 @@ EOF zfs set org.zfsbootmenu:commandline='rw nowatchdog rd.vconsole.keymap=de-latin1' "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" } -function keep_initiramfs_root_only_rw () { - #2.3 - declare systemd_local_admin_override_path unit_name - systemd_local_admin_override_path='/etc/systemd/system' - unit_name='chmod-initramfs' - path_unit="${systemd_local_admin_override_path%/}"'/'"${unit_name}"'.path' - service_unit="${systemd_local_admin_override_path%/}"'/'"${unit_name}"'.service' - - cat > "${path_unit}" <<"EOF" -[Unit] -Description=chmod initramfs to be root-read-writable only - -[Path] -PathChanged=/boot/initramfs-linux.img - -[Install] -WantedBy=multi-user.target -WantedBy=system-update.target -EOF - - cat > "${service_unit}" <<"EOF" -[Unit] -Description=chmod initramfs to be root-read-writable only - -[Service] -Type=oneshot -ExecStart=/usr/bin/chmod 600 /boot/initramfs-linux.img -EOF - - systemctl enable "${path_unit}" -} - -function add_motd_getting_started_msg () { - #2.6 - cat > '/etc/motd' <<"EOF" - -#################### - -GUI basics: - - paru -S xorg plasma-meta kde-applications-meta sddm - localectl set-x11-keymap de - useradd --create-home --shell /bin/bash --user-group --groups wheel - passwd - systemctl enable --now sddm.service - -#################### - -EOF +function get_disks_with_one_efipart () { + local disks_with_one_efipart + # Find disks that have exactly one EFI partition and where that EFI + # partition is partition number 1. We expect exactly one disk to meet + # these criteria. Anything else and we bail. + disks_with_one_efipart="$(lsblk --output PATH,PARTTYPE --json --tree | jq --raw-output '.[][] | select(.children | length > 0) | select( any (.children[]; (.path | test("^[^[:digit:]]+1")) and (.parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) and ([select(.children[].parttype=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b")] | length == 1) ) | .path')" + if [[ "$(wc -l <<<"${disks_with_one_efipart}")" -eq '1' ]] && [[ "$(wc -c <<<"${disks_with_one_efipart}")" -gt '1' ]]; then + printf -- '%s' "${disks_with_one_efipart}" + return 0 + fi + return 1 } function install_os_in_chroot () { -- 2.47.2 From d1407f00a971221a369e92f3c46d106ffa476596 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sat, 21 Oct 2023 05:14:38 +0200 Subject: [PATCH 66/84] refactor(meta): Update function numbering (#3) --- setup.sh | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/setup.sh b/setup.sh index 888ef5d..91cf92e 100644 --- a/setup.sh +++ b/setup.sh @@ -284,7 +284,7 @@ function mount_system () { } function copy_zpool_cache () { - #1.9 + #1.8 mkdir -p '/mnt/etc/zfs' zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}" } @@ -304,7 +304,7 @@ function pacman_dont_check_space () { } function install_archlinux () { - #1.10 + #1.9 pacman_dl_parallel pacman_dont_check_space pacstrap /mnt \ @@ -331,7 +331,7 @@ function install_archlinux () { } function gen_fstab () { - #1.11 + #1.10 genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab' } @@ -344,7 +344,7 @@ EOF } function set_hostname () { - #1.12 + #1.11 declare new_hostname install_pkgs 'pwgen' new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)" @@ -353,7 +353,7 @@ function set_hostname () { } function set_locale () { - #1.13 + #1.12 printf -- '%s\n' \ 'KEYMAP=de-latin1' \ 'FONT=Lat2-Terminus16' \ @@ -364,7 +364,7 @@ function set_locale () { } function add_zfs_hook_to_initramfs () { - #1.14 + #1.13 # Add zfs hook, remove fsck hook from initramfs. sed -ri \ -e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \ @@ -379,7 +379,7 @@ function add_zfs_hook_to_initramfs () { } function set_initramfs_build_list () { - #1.15 + #1.14 # No need to build fallback initramfs, our new fallback is ZFS snapshots sed -ri \ -e '/^#/d' \ @@ -393,7 +393,7 @@ function set_initramfs_build_list () { } function add_zfs_files_to_new_os () { - #1.16 + #1.15 for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do rsync -av --itemize-changes {'','/mnt'}"${zfs_file}" done @@ -546,8 +546,7 @@ function paru_install () { } function configure_zfsbootmenu () { - #3.8 - #FIXME + #2.9 paru_install 'zfsbootmenu' mkdir -p '/etc/zfsbootmenu/posthooks.d' cat > '/etc/zfsbootmenu/config.yaml' < Date: Sun, 22 Oct 2023 01:34:49 +0200 Subject: [PATCH 67/84] docs(meta): Start with a one-liner (#3) --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 386b262..57a846c 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,7 @@ The script will use the `EF00` partition to install a ZFSBootMenu EFI executable - Boot an Arch Linux live CD ISO image - Run: ``` - export SCRIPT_URL='https://quico.space/quico-os-setup/arch-zbm/raw/branch/main/setup.sh' - curl -s "${SCRIPT_URL}" | bash + export SCRIPT_URL='https://quico.space/quico-os-setup/arch-zbm/raw/branch/main/setup.sh' && curl -s "${SCRIPT_URL}" | bash ``` During execution the script will call itself when it changes into its `chroot`, that's why we `export SCRIPT_URL`. Feel free to update `"${SCRIPT_URL}"` with whatever branch or revision you want to use from [quico.space/quico-os-setup/arch-zbm](https://quico.space/quico-os-setup/arch-zbm). Typically `.../branch/main/setup.sh` as shown above is what you want. -- 2.47.2 From 863cee43222cbb4be9cb6d1f8174fc5b0c15516c Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 01:35:45 +0200 Subject: [PATCH 68/84] refactor(meta): Remove trailing whitespace (#3) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 57a846c..e10f0e5 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ ZFS generates the master key exactly once when you enable encryption on a datase `man 8 zfs-change-key` from `zfs-utils` version 2.1.9 adds: > If the user's key is compromised, `zfs change-key` does not necessarily protect existing or newly-written data from attack. Newly-written data will continue to be encrypted with the same master key as the existing data. The master key is compromised if an attacker obtains a user key and the corresponding wrapped master key. Currently, `zfs change-key` does not overwrite the previous wrapped master key on disk, so it is accessible via forensic analysis for an indeterminate length of time. -> +> > In the event of a master key compromise, ideally the drives should be securely erased to remove all the old data (which is readable using the compromised master key), a new pool created, and the data copied back. This can be approximated in place by creating new datasets, copying the data (e.g. using `zfs send | zfs recv`), and then clearing the free space with `zpool trim --secure` if supported by your hardware, otherwise `zpool initialize`. On one hand changing the ZFS encryption password is generally a good and useful thing to do. On the other hand changing your password does not currently overwrite previous wrapped master keys on disk. A sufficiently motivated party that gains access to a wrapped master key and the matching user key is able to decrypt the master key and use it to read all data encrypted with it. @@ -314,7 +314,7 @@ The ZFS pool and dataset setup that makes this tick, explained in plain English. 1. We export the zpool once, we then reimport it by scanning only inside `/dev/disk/by-partuuid`, again setting `-R /mnt` as we did during pool creation a moment ago and we do not mount any file systems. 1. We `zfs load-key ` which will load the key from `keylocation` after which the `keystatus` property for `` and all child datasets will change from `unavailable` to `available`. 1. We mount our Arch Linux boot environment dataset. It automatically gets prefixed with `-R /mnt` since that's how we imported the pool. -1. We `zfs mount -a` which automounts `zpool/data/home` into `/home`, which again gets auto-prepended by `/mnt`. +1. We `zfs mount -a` which automounts `zpool/data/home` into `/home`, which again gets auto-prepended by `/mnt`. 1. We lastly mount our EFI partition into `/mnt/efi`. 1. We instruct ZFS to save its pool configuration via `zpool set cachefile=/etc/zfs/zpool.cache zpool`. -- 2.47.2 From 4645a44333387b19b1016d432b1823c9ebffc005 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 01:38:05 +0200 Subject: [PATCH 69/84] docs(meta): UPdate lsblk output (#3) --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e10f0e5..79aac82 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ mkfs.vfat /dev/sda1 The result will be something like this at which point you can start the `setup.sh` script, see [How to run this?](#how-to-run-this) below for more details. ``` -# lsblk --paths -NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS -/dev/loop0 7:0 0 688.5M 1 loop /run/archiso/airootfs -/dev/sr0 11:0 1 810.3M 0 rom /run/archiso/bootmnt -/dev/sda 202:0 0 10G 0 disk -├─/dev/sda1 202:1 0 512M 0 part -└─/dev/sda2 202:2 0 9.9G 0 part +# lsblk --paths +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS +/dev/loop0 7:0 0 685.5M 1 loop /run/archiso/airootfs +/dev/sr0 11:0 1 808.3M 0 rom /run/archiso/bootmnt +/dev/sda 202:0 0 20G 0 disk +├─/dev/sda1 202:1 0 512M 0 part +└─/dev/sda2 202:2 0 19.5G 0 part ``` ## ZFS dataset layout -- 2.47.2 From f2213c2ec22e44c2cb708c62473953e61c59a829 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 01:38:59 +0200 Subject: [PATCH 70/84] refactor(meta): Unify ISO name (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79aac82..cf8b374 100644 --- a/README.md +++ b/README.md @@ -423,7 +423,7 @@ Commit _types_ besides `fix` and `feat` are: The following _scopes_ are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none: -- `iso`: Changing Arch Linux ISO CD +- `iso`: Changing Arch Linux live CD ISO image - `zbm`: Adjusting ZFSBootMenu's behavior - `zfs`: A change to how ZFS interacts with the system, either a pool or a dataset - `os`: Getting an operating system set up to correctly work in a ZFS boot environment -- 2.47.2 From 290e659d2906c85b7547d4a71a299afc43681afe Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 01:39:57 +0200 Subject: [PATCH 71/84] refactor(zfs): Single-quote dataset options for consistency (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 91cf92e..9d29fc1 100644 --- a/setup.sh +++ b/setup.sh @@ -229,7 +229,7 @@ function create_pool () { } function create_root_dataset () { - zfs create -o mountpoint=none -o canmount=off "${zpool_name}"'/root' + zfs create -o 'mountpoint=none' -o 'canmount=off' "${zpool_name}"'/root' # zfs set org.zfsbootmenu:commandline="ro quiet" "${zpool_name}"'/root' zfs set org.zfsbootmenu:commandline="ro" "${zpool_name}"'/root' } -- 2.47.2 From 5d359a3f3922d76fcfc48b2e1cf415d6065169c7 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 01:52:33 +0200 Subject: [PATCH 72/84] refactor(iso): No kernel updates in ISO (#3) --- setup.sh | 66 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/setup.sh b/setup.sh index 9d29fc1..cdef1b0 100644 --- a/setup.sh +++ b/setup.sh @@ -38,18 +38,23 @@ function we_are_changerooted () { fi } -function set_ntp () { +funcion no_kernel_update_in_iso () { #1.1 + sed -r -e 's'$'\x1''#(IgnorePkg)[^\r\n\f]+'$'\x1''\1 = linux linux-headers'$'\x1''g' /etc/pacman.conf +} + +function set_ntp () { + #1.2 timedatectl set-ntp true } function resize_cow_space () { - #1.2 + #1.3 mount -o remount,size='50%' /run/archiso/cowspace } function update_pacman_db () { - #1.3 + #1.4 printf -- '%s\n' 'Refreshing mirror list ...' systemctl start reflector # In an ISO and for the minimal number of packages we need we do not @@ -58,13 +63,13 @@ function update_pacman_db () { } function install_pkgs () { - #1.4 + #1.5 printf -- '%s\n' 'Installing packages ...' pacman -S --needed --noconfirm "${@}" } function install_zfs () { - #1.5 + #1.6 declare reset_colors='\033[0m' curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash printf -- "${reset_colors}" @@ -251,7 +256,7 @@ function export_pool () { } function setup_zpool () { - #1.6 + #1.7 local drive_by_id zpool_drive="$(select_part 'zfs')" drive_by_id="$(get_drive_id "${zpool_drive}")" @@ -271,7 +276,7 @@ function setup_zpool () { } function mount_system () { - #1.7 + #1.8 zfs mount "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" zfs mount -a @@ -284,7 +289,7 @@ function mount_system () { } function copy_zpool_cache () { - #1.8 + #1.9 mkdir -p '/mnt/etc/zfs' zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}" } @@ -304,7 +309,7 @@ function pacman_dont_check_space () { } function install_archlinux () { - #1.9 + #1.10 pacman_dl_parallel pacman_dont_check_space pacstrap /mnt \ @@ -331,7 +336,7 @@ function install_archlinux () { } function gen_fstab () { - #1.10 + #1.11 genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab' } @@ -344,7 +349,7 @@ EOF } function set_hostname () { - #1.11 + #1.12 declare new_hostname install_pkgs 'pwgen' new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)" @@ -353,7 +358,7 @@ function set_hostname () { } function set_locale () { - #1.12 + #1.13 printf -- '%s\n' \ 'KEYMAP=de-latin1' \ 'FONT=Lat2-Terminus16' \ @@ -364,7 +369,7 @@ function set_locale () { } function add_zfs_hook_to_initramfs () { - #1.13 + #1.14 # Add zfs hook, remove fsck hook from initramfs. sed -ri \ -e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \ @@ -379,7 +384,7 @@ function add_zfs_hook_to_initramfs () { } function set_initramfs_build_list () { - #1.14 + #1.15 # No need to build fallback initramfs, our new fallback is ZFS snapshots sed -ri \ -e '/^#/d' \ @@ -393,7 +398,7 @@ function set_initramfs_build_list () { } function add_zfs_files_to_new_os () { - #1.15 + #1.16 for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do rsync -av --itemize-changes {'','/mnt'}"${zfs_file}" done @@ -738,21 +743,22 @@ function main () { if we_are_changerooted; then install_os_in_chroot #2.2 else - set_ntp #1.1 - resize_cow_space #1.2 - update_pacman_db #1.3 - install_pkgs 'base-devel' 'git' 'jq' #1.4 - install_zfs #1.5 - setup_zpool #1.6 - mount_system #1.7 - copy_zpool_cache #1.8 - install_archlinux #1.9 - gen_fstab #1.10 - set_hostname #1.11 - set_locale #1.12 - add_zfs_hook_to_initramfs #1.13 - set_initramfs_build_list #1.14 - add_zfs_files_to_new_os #1.15 + no_kernel_update_in_iso #1.1 + set_ntp #1.2 + resize_cow_space #1.3 + update_pacman_db #1.4 + install_pkgs 'base-devel' 'git' 'jq' #1.5 + install_zfs #1.6 + setup_zpool #1.7 + mount_system #1.8 + copy_zpool_cache #1.9 + install_archlinux #1.10 + gen_fstab #1.11 + set_hostname #1.12 + set_locale #1.13 + add_zfs_hook_to_initramfs #1.14 + set_initramfs_build_list #1.15 + add_zfs_files_to_new_os #1.16 enter_chroot #2.1 # We're done in chroot finalize_os_setup #3.1 -- 2.47.2 From d3be536516c9d695e2358f159b77c60072137506 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 01:59:42 +0200 Subject: [PATCH 73/84] refactor(iso): Typo (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index cdef1b0..bdbbf69 100644 --- a/setup.sh +++ b/setup.sh @@ -38,7 +38,7 @@ function we_are_changerooted () { fi } -funcion no_kernel_update_in_iso () { +function no_kernel_update_in_iso () { #1.1 sed -r -e 's'$'\x1''#(IgnorePkg)[^\r\n\f]+'$'\x1''\1 = linux linux-headers'$'\x1''g' /etc/pacman.conf } -- 2.47.2 From a9c9b3d7884b6f80fd1202038c19d01e757a95d9 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 02:00:16 +0200 Subject: [PATCH 74/84] refactor(iso): Typo (#3) --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index bdbbf69..a890edd 100644 --- a/setup.sh +++ b/setup.sh @@ -40,7 +40,7 @@ function we_are_changerooted () { function no_kernel_update_in_iso () { #1.1 - sed -r -e 's'$'\x1''#(IgnorePkg)[^\r\n\f]+'$'\x1''\1 = linux linux-headers'$'\x1''g' /etc/pacman.conf + sed -ri -e 's'$'\x1''#(IgnorePkg)[^\r\n\f]+'$'\x1''\1 = linux linux-headers'$'\x1''g' /etc/pacman.conf } function set_ntp () { -- 2.47.2 From 0fa1564405d3d74a67290dd67592a84c69683405 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 03:22:12 +0200 Subject: [PATCH 75/84] fix(zbm): We may want to actually run our ZBM postconf hook (#3) --- zbm_set_new_uefi_boot_entries.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zbm_set_new_uefi_boot_entries.sh b/zbm_set_new_uefi_boot_entries.sh index bbf27ed..1b592b2 100644 --- a/zbm_set_new_uefi_boot_entries.sh +++ b/zbm_set_new_uefi_boot_entries.sh @@ -175,3 +175,5 @@ function set_new_uefi_boot_entries () { fi fi } + +set_new_uefi_boot_entries -- 2.47.2 From 214f82becf3f765464eb14b1baaeb8b122dd4097 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 14:41:46 +0200 Subject: [PATCH 76/84] fix(zbm): Use a known good stub loader file (#3) This works around https://github.com/zbm-dev/zfsbootmenu/issues/503 --- setup.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/setup.sh b/setup.sh index a890edd..ede7b4d 100644 --- a/setup.sh +++ b/setup.sh @@ -566,6 +566,7 @@ EFI: ImageDir: /efi/EFI/ZBM Versions: 1 Enabled: true + Stub: /etc/zfsbootmenu/stub-loader.d/linuxx64.efi.stub Kernel: CommandLine: ro loglevel=0 zbm.import_policy=hostid Prefix: vmlinuz @@ -574,6 +575,14 @@ EOF zfs set org.zfsbootmenu:commandline='rw nowatchdog rd.vconsole.keymap=de-latin1' "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" } +function get_known_good_stub_loader () { + local known_good_stub_loader local_stub_loader_abs + known_good_stub_loader='https://github.com/zbm-dev/zfsbootmenu/raw/master/testing/stubs/linuxx64.efi.stub' + local local_stub_loader_abs='/etc/zfsbootmenu/stub-loader.d/linuxx64.efi.stub' + mkdir -p "$(dirname "${local_stub_loader_abs}")" + curl --silent --location "${known_good_stub_loader}" --output "${local_stub_loader_abs}" +} + function get_disks_with_one_efipart () { local disks_with_one_efipart # Find disks that have exactly one EFI partition and where that EFI @@ -613,6 +622,7 @@ function install_os_in_chroot () { # Install ZFSBootMenu image configure_zfsbootmenu #2.9 + get_known_good_stub_loader #2.10 generate-zbm } -- 2.47.2 From cc6e17f06c9bf32c46fff57bbf98f3e1bc63b610 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 14:42:24 +0200 Subject: [PATCH 77/84] fix(zbm): Correctly set EFI loader paths (#3) --- zbm_set_new_uefi_boot_entries.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zbm_set_new_uefi_boot_entries.sh b/zbm_set_new_uefi_boot_entries.sh index 1b592b2..af2b4c6 100644 --- a/zbm_set_new_uefi_boot_entries.sh +++ b/zbm_set_new_uefi_boot_entries.sh @@ -161,7 +161,7 @@ function set_new_uefi_boot_entries () { for uefi_image in "${uefi_images[@]}"; do uefi_image_version="$(basename "${uefi_image##*-}")" uefi_image_version="${uefi_image_version%%.EFI}" - uefi_image_inverted="${uefi_image#/mnt/efi}" + uefi_image_inverted="${uefi_image#/efi}" uefi_image_inverted="${uefi_image_inverted//\//\\}" efibootmgr --disk "${efi_drive}" \ --part 1 \ -- 2.47.2 From 108883fd119b39cd83da7c0290917045e175486f Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 14:48:46 +0200 Subject: [PATCH 78/84] docs(meta): Update lsblk output (#3) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cf8b374..60d2757 100644 --- a/README.md +++ b/README.md @@ -29,12 +29,12 @@ mkfs.vfat /dev/sda1 The result will be something like this at which point you can start the `setup.sh` script, see [How to run this?](#how-to-run-this) below for more details. ``` # lsblk --paths -NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS -/dev/loop0 7:0 0 685.5M 1 loop /run/archiso/airootfs -/dev/sr0 11:0 1 808.3M 0 rom /run/archiso/bootmnt -/dev/sda 202:0 0 20G 0 disk +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS +/dev/loop0 7:0 0 685.5M 1 loop /run/archiso/airootfs +/dev/sr0 11:0 1 808.3M 0 rom /run/archiso/bootmnt +/dev/sda 202:0 0 10G 0 disk ├─/dev/sda1 202:1 0 512M 0 part -└─/dev/sda2 202:2 0 19.5G 0 part +└─/dev/sda2 202:2 0 9.5G 0 part ``` ## ZFS dataset layout -- 2.47.2 From ae00207947346656b473ff979defd744cc6d6b9e Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 15:26:50 +0200 Subject: [PATCH 79/84] refactor(zbm): Point to chroot (#3) --- zbm_set_new_uefi_boot_entries.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zbm_set_new_uefi_boot_entries.sh b/zbm_set_new_uefi_boot_entries.sh index af2b4c6..d972051 100644 --- a/zbm_set_new_uefi_boot_entries.sh +++ b/zbm_set_new_uefi_boot_entries.sh @@ -94,8 +94,7 @@ function select_part () { esac >&3 printf -- '%s\n' \ 'It looks as if there is no '"${part_type_human_readable}" \ - 'on any of the disks. Did you correctly partition a disk before starting?' \ - 'Check https://quico.space/quico-os-setup/arch-zbm#prep. Exiting ...' + 'on any of the disks. Is this a chroot? Exiting ...' exit 77 fi -- 2.47.2 From 7133883a5e0387123eff968e74543074371603b6 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 15:29:46 +0200 Subject: [PATCH 80/84] docs(zfs): Explain how to mount externally (#3) --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/README.md b/README.md index 60d2757..4ffc9d0 100644 --- a/README.md +++ b/README.md @@ -404,6 +404,70 @@ Lastly create the dataset you want mounted: zfs create zpool/data/var/lib/docker ``` +## Mounting zpool for maintenance + +In case you want to mount your zpool on an external operating system such as an Arch Linux live CD ISO image do it like so: + +``` +zpool import zpool -d '/dev/disk/by-partuuid' -R '/mnt' -f -N +zfs load-key -L 'prompt' 'zpool' +zfs mount 'zpool/root/archlinux' +zfs mount -a +mount '/dev/sda1' '/mnt/efi' +arch-chroot '/mnt' '/bin/bash' +``` + +Explanation: + +- We always want to mount pools `by-partuuid` for consistency so we specifically only look for pools at `/dev/disk/by-partuuid`. +- We mount our zpool with `-R /mnt` (aka `-o cachefile=none -o altroot=/mnt`). The pool is never cached, i.e. it's considered temporary. All pool and dataset mount paths have `/mnt` prepended. From `man zpoolprops`: + > This can be used when examining an unknown pool where the mount points cannot be trusted, or in an alternate boot environment, where the typical paths are not valid. `altroot` is not a persistent property. It is valid only while the system is up. +- With `-f` and `-N` we force-mount our pool (`-f`) even if it previously wasn't cleanly exported; and we do not auto-mount any of its datasets (`-N`), not even the ones that have `canmount=on` set. + + ``` + # zfs list -oname,mountpoint,canmount,mounted + NAME MOUNTPOINT CANMOUNT MOUNTED + zpool none off no + zpool/data /mnt off no + zpool/data/home /mnt/home on no <-- Not immediately mounted + zpool/root none off no + zpool/root/archlinux /mnt noauto no <-- Not immediately mounted + ``` +- We load the decryption key by temporarily overriding the `keylocation` property to `-L prompt`. The default value is `file:///etc/zfs/zpool.key` which in all likelihood doesn't exist in this environment. +- We mount our desired boot environment with `zfs mount zpool/root/archlinux` + + ``` + # zfs list -oname,mountpoint,canmount,mounted + NAME MOUNTPOINT CANMOUNT MOUNTED + zpool none off no + zpool/data /mnt off no + zpool/data/home /mnt/home on no + zpool/root none off no + zpool/root/archlinux /mnt noauto yes <-- Only boot env now mounted + ``` +- We mount all child datasets with `zfs mount -a` making `/mnt/home` available as well as any others you may have created yourself. + + ``` + # zfs list -oname,mountpoint,canmount,mounted + NAME MOUNTPOINT CANMOUNT MOUNTED + zpool none off no + zpool/data /mnt off no + zpool/data/home /mnt/home on yes <-- Now mounted + zpool/root none off no + zpool/root/archlinux /mnt noauto yes <-- Now mounted + ``` +- We lastly mount our EFI system partition (ESP), in this example it's living at `/dev/sda1` so adjust this path accordingly. + + ``` + # df -hTP + Filesystem Type Size Used Avail Use% Mounted on + ... ... ... ... ... ... ... + zpool/root/archlinux zfs 8.6G 2.5G 6.2G 29% /mnt + zpool/data/home zfs 6.3G 161M 6.2G 3% /mnt/home + /dev/sda1 vfat 511M 31M 481M 6% /mnt/efi + ``` +- We're ready to `arch-chroot` into our boot environment. + # Development ## Conventional commits -- 2.47.2 From 1a138068d178c632c1ce15561229789008139726 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 15:47:24 +0200 Subject: [PATCH 81/84] refactor(zbm): No ZBM image versioning beyond a main and a backup file (#3) --- setup.sh | 5 ++--- zbm_set_new_uefi_boot_entries.sh | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/setup.sh b/setup.sh index ede7b4d..5da1519 100644 --- a/setup.sh +++ b/setup.sh @@ -564,7 +564,7 @@ Components: Enabled: false EFI: ImageDir: /efi/EFI/ZBM - Versions: 1 + Versions: false Enabled: true Stub: /etc/zfsbootmenu/stub-loader.d/linuxx64.efi.stub Kernel: @@ -705,8 +705,7 @@ function set_new_uefi_boot_entries () { efi_disks_list="$(get_disks_with_one_efipart)" if grep -Piq -- '^'"${efi_drive}"'$' <<<"${efi_disks_list}"; then for uefi_image in "${uefi_images[@]}"; do - uefi_image_version="$(basename "${uefi_image##*-}")" - uefi_image_version="${uefi_image_version%%.EFI}" + uefi_image_version="$(basename "${uefi_image%%.EFI}")" uefi_image_inverted="${uefi_image#/mnt/efi}" uefi_image_inverted="${uefi_image_inverted//\//\\}" efibootmgr --disk "${efi_drive}" \ diff --git a/zbm_set_new_uefi_boot_entries.sh b/zbm_set_new_uefi_boot_entries.sh index d972051..f0729e6 100644 --- a/zbm_set_new_uefi_boot_entries.sh +++ b/zbm_set_new_uefi_boot_entries.sh @@ -158,8 +158,7 @@ function set_new_uefi_boot_entries () { efi_disks_list="$(get_disks_with_one_efipart)" if grep -Piq -- '^'"${efi_drive}"'$' <<<"${efi_disks_list}"; then for uefi_image in "${uefi_images[@]}"; do - uefi_image_version="$(basename "${uefi_image##*-}")" - uefi_image_version="${uefi_image_version%%.EFI}" + uefi_image_version="$(basename "${uefi_image%%.EFI}")" uefi_image_inverted="${uefi_image#/efi}" uefi_image_inverted="${uefi_image_inverted//\//\\}" efibootmgr --disk "${efi_drive}" \ -- 2.47.2 From 4dab010efd7d975a45701d438178ef4c6fb488a2 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 15:48:33 +0200 Subject: [PATCH 82/84] docs(zfs): Export zpool when done working on it (#3) --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ffc9d0..98b0557 100644 --- a/README.md +++ b/README.md @@ -409,7 +409,7 @@ zfs create zpool/data/var/lib/docker In case you want to mount your zpool on an external operating system such as an Arch Linux live CD ISO image do it like so: ``` -zpool import zpool -d '/dev/disk/by-partuuid' -R '/mnt' -f -N +zpool import 'zpool' -d '/dev/disk/by-partuuid' -R '/mnt' -f -N zfs load-key -L 'prompt' 'zpool' zfs mount 'zpool/root/archlinux' zfs mount -a @@ -417,6 +417,14 @@ mount '/dev/sda1' '/mnt/efi' arch-chroot '/mnt' '/bin/bash' ``` +When done cleanly remove your work: + +``` +umount '/mnt/efi' +zfs umount -a +zpool export 'zpool' +``` + Explanation: - We always want to mount pools `by-partuuid` for consistency so we specifically only look for pools at `/dev/disk/by-partuuid`. -- 2.47.2 From 2e390752736459df2a4caa9b0011853049595da9 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 15:50:45 +0200 Subject: [PATCH 83/84] docs(zfs): Fewer single quotes (#3) --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 98b0557..9383bfe 100644 --- a/README.md +++ b/README.md @@ -409,20 +409,20 @@ zfs create zpool/data/var/lib/docker In case you want to mount your zpool on an external operating system such as an Arch Linux live CD ISO image do it like so: ``` -zpool import 'zpool' -d '/dev/disk/by-partuuid' -R '/mnt' -f -N -zfs load-key -L 'prompt' 'zpool' -zfs mount 'zpool/root/archlinux' +zpool import zpool -d /dev/disk/by-partuuid -R /mnt -f -N +zfs load-key -L prompt zpool +zfs mount zpool/root/archlinux zfs mount -a -mount '/dev/sda1' '/mnt/efi' -arch-chroot '/mnt' '/bin/bash' +mount /dev/sda1 /mnt/efi +arch-chroot /mnt /bin/bash ``` When done cleanly remove your work: ``` -umount '/mnt/efi' +umount /mnt/efi zfs umount -a -zpool export 'zpool' +zpool export zpool ``` Explanation: -- 2.47.2 From 4e795c9cb749b6d974ec08d373556ca8cea28726 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 22 Oct 2023 16:04:43 +0200 Subject: [PATCH 84/84] docs(zfs): Export zpool when done working on it (#3) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9383bfe..a3ddb85 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,7 @@ mount /dev/sda1 /mnt/efi arch-chroot /mnt /bin/bash ``` -When done cleanly remove your work: +When done exit `chroot` and cleanly remove your work: ``` umount /mnt/efi -- 2.47.2