Compare commits
7 Commits
b36d4d33c3
...
d1407f00a9
Author | SHA1 | Date | |
---|---|---|---|
d1407f00a9 | |||
767e9c3b42 | |||
915ded9c1b | |||
598b176ec6 | |||
dcc3cf7d93 | |||
be63ed90ad | |||
abffd08c1e |
325
setup.sh
325
setup.sh
@@ -18,6 +18,7 @@ exec 3>&1
|
|||||||
|
|
||||||
declare this_script_url
|
declare this_script_url
|
||||||
this_script_url="${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
|
declare zpool_name zfs_arch_dataset_name
|
||||||
zpool_name='zpool'
|
zpool_name='zpool'
|
||||||
@@ -282,68 +283,12 @@ function mount_system () {
|
|||||||
mount "${efi_part}" '/mnt/efi'
|
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 () {
|
function copy_zpool_cache () {
|
||||||
#1.9
|
#1.8
|
||||||
mkdir -p '/mnt/etc/zfs'
|
mkdir -p '/mnt/etc/zfs'
|
||||||
zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}"
|
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 () {
|
function pacman_dont_check_space () {
|
||||||
# See pacman bug comment
|
# See pacman bug comment
|
||||||
# https://bugs.archlinux.org/task/45070#comment142712
|
# https://bugs.archlinux.org/task/45070#comment142712
|
||||||
@@ -359,7 +304,7 @@ function pacman_dont_check_space () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function install_archlinux () {
|
function install_archlinux () {
|
||||||
#1.10
|
#1.9
|
||||||
pacman_dl_parallel
|
pacman_dl_parallel
|
||||||
pacman_dont_check_space
|
pacman_dont_check_space
|
||||||
pacstrap /mnt \
|
pacstrap /mnt \
|
||||||
@@ -386,7 +331,7 @@ function install_archlinux () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gen_fstab () {
|
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'
|
genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +344,7 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
function set_hostname () {
|
function set_hostname () {
|
||||||
#1.12
|
#1.11
|
||||||
declare new_hostname
|
declare new_hostname
|
||||||
install_pkgs 'pwgen'
|
install_pkgs 'pwgen'
|
||||||
new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)"
|
new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)"
|
||||||
@@ -408,7 +353,7 @@ function set_hostname () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function set_locale () {
|
function set_locale () {
|
||||||
#1.13
|
#1.12
|
||||||
printf -- '%s\n' \
|
printf -- '%s\n' \
|
||||||
'KEYMAP=de-latin1' \
|
'KEYMAP=de-latin1' \
|
||||||
'FONT=Lat2-Terminus16' \
|
'FONT=Lat2-Terminus16' \
|
||||||
@@ -419,7 +364,7 @@ function set_locale () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function add_zfs_hook_to_initramfs () {
|
function add_zfs_hook_to_initramfs () {
|
||||||
#1.14
|
#1.13
|
||||||
# Add zfs hook, remove fsck hook from initramfs.
|
# Add zfs hook, remove fsck hook from initramfs.
|
||||||
sed -ri \
|
sed -ri \
|
||||||
-e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \
|
-e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \
|
||||||
@@ -434,7 +379,7 @@ function add_zfs_hook_to_initramfs () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function set_initramfs_build_list () {
|
function set_initramfs_build_list () {
|
||||||
#1.15
|
#1.14
|
||||||
# No need to build fallback initramfs, our new fallback is ZFS snapshots
|
# No need to build fallback initramfs, our new fallback is ZFS snapshots
|
||||||
sed -ri \
|
sed -ri \
|
||||||
-e '/^#/d' \
|
-e '/^#/d' \
|
||||||
@@ -448,19 +393,12 @@ function set_initramfs_build_list () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function add_zfs_files_to_new_os () {
|
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
|
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}"
|
rsync -av --itemize-changes {'','/mnt'}"${zfs_file}"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
function enter_chroot () {
|
|
||||||
#2.1
|
|
||||||
arch-chroot /mnt /bin/bash -xe <<EOF
|
|
||||||
curl --silent '${this_script_url}' | bash
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_unpriv_user () {
|
function create_unpriv_user () {
|
||||||
account_name="${1:?}"
|
account_name="${1:?}"
|
||||||
full_name="${2:-${account_name}}"
|
full_name="${2:-${account_name}}"
|
||||||
@@ -472,6 +410,52 @@ function create_unpriv_user () {
|
|||||||
chown -R "${account_name}"':' '/home/'"${account_name}"; chmod -R 'u=rwX,go=' "$(dirname "${authorized_keys_abs_path}")"
|
chown -R "${account_name}"':' '/home/'"${account_name}"; chmod -R 'u=rwX,go=' "$(dirname "${authorized_keys_abs_path}")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enter_chroot () {
|
||||||
|
#2.1
|
||||||
|
arch-chroot /mnt /bin/bash -xe <<EOF
|
||||||
|
curl --silent '${this_script_url}' | bash
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 () {
|
function unleash_makepkg () {
|
||||||
#2.5
|
#2.5
|
||||||
local path_prefix
|
local path_prefix
|
||||||
@@ -484,6 +468,25 @@ function unleash_makepkg () {
|
|||||||
"${path_prefix}"'/etc/makepkg.conf'
|
"${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 <user>
|
||||||
|
passwd <user>
|
||||||
|
systemctl enable --now sddm.service
|
||||||
|
|
||||||
|
####################
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
function get_aur_helper () {
|
function get_aur_helper () {
|
||||||
#2.7
|
#2.7
|
||||||
create_unpriv_user 'build'
|
create_unpriv_user 'build'
|
||||||
@@ -542,65 +545,41 @@ function paru_install () {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_zbm_image () {
|
function configure_zfsbootmenu () {
|
||||||
#2.8
|
#2.9
|
||||||
# This takes image files written earlier in our Arch Linux live CD ISO
|
paru_install 'zfsbootmenu'
|
||||||
# image at prepare_zfsbootmenu_efi_bin_pkg() and installs them via their
|
mkdir -p '/etc/zfsbootmenu/posthooks.d'
|
||||||
# locally built package file. When done we delete the manually built
|
cat > '/etc/zfsbootmenu/config.yaml' <<EOF
|
||||||
# package file from pacman's cache dir.
|
Global:
|
||||||
pacman -U "${ZFSBOOTMENU_EFI_BIN_PKG_PATH}" --noconfirm
|
ManageImages: true
|
||||||
rm "${ZFSBOOTMENU_EFI_BIN_PKG_PATH}"
|
BootMountPoint: /efi
|
||||||
|
InitCPIO: true
|
||||||
|
PostHooksDir: /etc/zfsbootmenu/posthooks.d
|
||||||
|
Components:
|
||||||
|
Enabled: false
|
||||||
|
EFI:
|
||||||
|
ImageDir: /efi/EFI/ZBM
|
||||||
|
Versions: 1
|
||||||
|
Enabled: true
|
||||||
|
Kernel:
|
||||||
|
CommandLine: ro loglevel=0 zbm.import_policy=hostid
|
||||||
|
Prefix: vmlinuz
|
||||||
|
EOF
|
||||||
|
# Up here maybe 'ro quiet' instead of 'ro'
|
||||||
|
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 () {
|
function get_disks_with_one_efipart () {
|
||||||
#2.3
|
local disks_with_one_efipart
|
||||||
declare systemd_local_admin_override_path unit_name
|
# Find disks that have exactly one EFI partition and where that EFI
|
||||||
systemd_local_admin_override_path='/etc/systemd/system'
|
# partition is partition number 1. We expect exactly one disk to meet
|
||||||
unit_name='chmod-initramfs'
|
# these criteria. Anything else and we bail.
|
||||||
path_unit="${systemd_local_admin_override_path%/}"'/'"${unit_name}"'.path'
|
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')"
|
||||||
service_unit="${systemd_local_admin_override_path%/}"'/'"${unit_name}"'.service'
|
if [[ "$(wc -l <<<"${disks_with_one_efipart}")" -eq '1' ]] && [[ "$(wc -c <<<"${disks_with_one_efipart}")" -gt '1' ]]; then
|
||||||
|
printf -- '%s' "${disks_with_one_efipart}"
|
||||||
cat > "${path_unit}" <<"EOF"
|
return 0
|
||||||
[Unit]
|
fi
|
||||||
Description=chmod initramfs to be root-read-writable only
|
return 1
|
||||||
|
|
||||||
[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 <user>
|
|
||||||
passwd <user>
|
|
||||||
systemctl enable --now sddm.service
|
|
||||||
|
|
||||||
####################
|
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_os_in_chroot () {
|
function install_os_in_chroot () {
|
||||||
@@ -623,12 +602,13 @@ function install_os_in_chroot () {
|
|||||||
add_motd_getting_started_msg #2.6
|
add_motd_getting_started_msg #2.6
|
||||||
get_aur_helper #2.7
|
get_aur_helper #2.7
|
||||||
paru_install --replace-conflicting 'paru-bin'
|
paru_install --replace-conflicting 'paru-bin'
|
||||||
paru_install 'zfs-dkms' 'zfs-utils' 'rsync'
|
paru_install 'zfs-dkms' 'zfs-utils' 'jq'
|
||||||
hwclock --systohc
|
hwclock --systohc
|
||||||
mkinitcpio -P
|
mkinitcpio -P
|
||||||
|
|
||||||
# Install ZFSBootMenu image
|
# Install ZFSBootMenu image
|
||||||
install_zbm_image #2.8
|
configure_zfsbootmenu #2.9
|
||||||
|
generate-zbm
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_root_pw () {
|
function set_root_pw () {
|
||||||
@@ -683,47 +663,57 @@ function configure_zfs_mount_gen () {
|
|||||||
systemctl enable 'zfs-zed.service' --root='/mnt'
|
systemctl enable 'zfs-zed.service' --root='/mnt'
|
||||||
}
|
}
|
||||||
|
|
||||||
function configure_zfsbootmenu () {
|
function set_new_uefi_boot_entries () {
|
||||||
#3.8
|
#3.8
|
||||||
zfs set org.zfsbootmenu:commandline='rw nowatchdog rd.vconsole.keymap=de-latin1' "${zpool_name}"'/root/'"${zfs_arch_dataset_name}"
|
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}')
|
||||||
|
|
||||||
function get_disks_with_one_efipart () {
|
if efibootmgr | grep -Piq -- 'ZFSBootMenu'; then
|
||||||
local disks_with_one_efipart
|
local -a old_uefi_entries
|
||||||
# Find disks that have exactly one EFI partition and where that EFI
|
mapfile -t old_uefi_entries < \
|
||||||
# partition is partition number 1. We expect exactly one disk to meet
|
<(efibootmgr | \
|
||||||
# these criteria. Anything else and we bail.
|
grep -Pio -- '(?<=^Boot)[^\*[:space:]]+(?=\*? ZFSBootMenu)')
|
||||||
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')"
|
for old_uefi_entry in "${old_uefi_entries[@]}"; do
|
||||||
if [[ "$(wc -l <<<"${disks_with_one_efipart}")" -eq '1' ]] && [[ "$(wc -c <<<"${disks_with_one_efipart}")" -gt '1' ]]; then
|
efibootmgr --bootnum "${old_uefi_entry}" --delete-bootnum &>/dev/null && {
|
||||||
printf -- '%s' "${disks_with_one_efipart}"
|
>&3 printf -- '%s\n' \
|
||||||
return 0
|
'EFI boot entry '"${old_uefi_entry}"' deleted.'
|
||||||
|
}
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function add_zbm_to_efi () {
|
|
||||||
#3.9
|
|
||||||
if ! efibootmgr | grep -Piq -- 'ZFSBootMenu'; then
|
if ! efibootmgr | grep -Piq -- 'ZFSBootMenu'; then
|
||||||
local efi_disks_list
|
local efi_disks_list
|
||||||
efi_disks_list="$(get_disks_with_one_efipart)"
|
efi_disks_list="$(get_disks_with_one_efipart)"
|
||||||
if grep -Piq -- '^'"${efi_drive}"'$' <<<"${efi_disks_list}"; then
|
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}" \
|
efibootmgr --disk "${efi_drive}" \
|
||||||
--part 1 \
|
--part 1 \
|
||||||
--create \
|
--create \
|
||||||
--label "ZFSBootMenu recovery" \
|
--label 'ZFSBootMenu '"${uefi_image_version}" \
|
||||||
--loader "\EFI\zbm\zfsbootmenu-recovery-vmlinuz-x86_64.EFI" \
|
--loader "${uefi_image_inverted}" &>/dev/null && {
|
||||||
--verbose
|
>&3 printf -- '%s\n' \
|
||||||
efibootmgr --disk "${efi_drive}" \
|
'EFI boot entry ZFSBootMenu '"${uefi_image_version}"' added.'
|
||||||
--part 1 \
|
}
|
||||||
--create \
|
done
|
||||||
--label "ZFSBootMenu release" \
|
|
||||||
--loader "\EFI\zbm\zfsbootmenu-release-vmlinuz-x86_64.EFI" \
|
|
||||||
--verbose
|
|
||||||
fi
|
fi
|
||||||
efibootmgr
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insert_zbm_postconf_hook () {
|
||||||
|
#3.9
|
||||||
|
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 () {
|
function umount_all () {
|
||||||
#3.10
|
#3.10
|
||||||
umount '/mnt/efi'
|
umount '/mnt/efi'
|
||||||
@@ -739,9 +729,9 @@ function finalize_os_setup () {
|
|||||||
configure_reflector #3.5
|
configure_reflector #3.5
|
||||||
configure_zfs #3.6
|
configure_zfs #3.6
|
||||||
configure_zfs_mount_gen #3.7
|
configure_zfs_mount_gen #3.7
|
||||||
configure_zfsbootmenu #3.8
|
set_new_uefi_boot_entries #3.8
|
||||||
add_zbm_to_efi #3.9
|
insert_zbm_postconf_hook #3.9
|
||||||
umount_all #3.11
|
umount_all #3.10
|
||||||
}
|
}
|
||||||
|
|
||||||
function main () {
|
function main () {
|
||||||
@@ -755,15 +745,14 @@ function main () {
|
|||||||
install_zfs #1.5
|
install_zfs #1.5
|
||||||
setup_zpool #1.6
|
setup_zpool #1.6
|
||||||
mount_system #1.7
|
mount_system #1.7
|
||||||
prepare_zfsbootmenu_efi_bin_pkg #1.8
|
copy_zpool_cache #1.8
|
||||||
copy_zpool_cache #1.9
|
install_archlinux #1.9
|
||||||
install_archlinux #1.10
|
gen_fstab #1.10
|
||||||
gen_fstab #1.11
|
set_hostname #1.11
|
||||||
set_hostname #1.12
|
set_locale #1.12
|
||||||
set_locale #1.13
|
add_zfs_hook_to_initramfs #1.13
|
||||||
add_zfs_hook_to_initramfs #1.14
|
set_initramfs_build_list #1.14
|
||||||
set_initramfs_build_list #1.15
|
add_zfs_files_to_new_os #1.15
|
||||||
add_zfs_files_to_new_os #1.16
|
|
||||||
enter_chroot #2.1
|
enter_chroot #2.1
|
||||||
# We're done in chroot
|
# We're done in chroot
|
||||||
finalize_os_setup #3.1
|
finalize_os_setup #3.1
|
||||||
|
177
zbm_set_new_uefi_boot_entries.sh
Normal file
177
zbm_set_new_uefi_boot_entries.sh
Normal file
@@ -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
|
||||||
|
}
|
Reference in New Issue
Block a user