index : archiso32 | |
Archlinux32 iso tools | gitolite user |
summaryrefslogtreecommitdiff |
author | Andreas Baumann <mail@andreasbaumann.cc> | 2022-09-30 19:00:21 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2022-09-30 19:00:21 +0200 |
commit | d418c7d5ce88175061bb3b7db873738a06434e91 (patch) | |
tree | a64a4dbbc22938850909c7c728abb40bbd77e365 | |
parent | c9c0199bf7e2c007000ef8165882ba0c6167b6be (diff) | |
parent | fbc72247b834262c24a26470bf623007d90b6e87 (diff) |
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | .gitlab-ci.yml | 29 | ||||
-rwxr-xr-x | .gitlab/ci/build_archiso.sh | 80 | ||||
-rw-r--r-- | AUTHORS.rst | 3 | ||||
-rw-r--r-- | CHANGELOG.rst | 73 | ||||
-rw-r--r-- | README.rst | 2 | ||||
-rwxr-xr-x | archiso/mkarchiso | 547 | ||||
-rw-r--r-- | configs/baseline/airootfs/etc/locale.conf | 1 | ||||
-rw-r--r-- | configs/baseline/grub/grub.cfg | 24 | ||||
-rw-r--r-- | configs/baseline/profiledef.sh | 6 | ||||
-rw-r--r-- | configs/releng/airootfs/etc/locale.conf | 2 | ||||
-rw-r--r-- | configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook | 13 | ||||
l--------- | configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.timesync1.service | 1 | ||||
-rw-r--r-- | configs/releng/airootfs/etc/systemd/system/pacman-init.service | 4 | ||||
l--------- | configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service | 1 | ||||
l--------- | configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service | 1 | ||||
-rw-r--r-- | configs/releng/grub/grub.cfg | 67 | ||||
-rw-r--r-- | configs/releng/packages.x86_64 | 2 | ||||
-rw-r--r-- | docs/README.profile.rst | 11 |
@@ -3,5 +3,10 @@ archiso32-*.tar.gz* work/ out/ *.iso +*.img +*.cer +*.crt +*.key +*.pem user-data meta-data diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 628c28f..17ac5ff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,20 +2,6 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -# NOTE: most functionality (apart from building) is abstracted by this include -include: - - project: 'archlinux/ci-scripts' - ref: master - file: '/prepare_archiso_vm.yml' - -variables: - BUILD_SCRIPT: ./.gitlab/ci/build_archiso.sh - PACKAGE_LIST: dosfstools e2fsprogs erofs-utils jq libisoburn mtools openssl qemu-headless squashfs-tools zsync - QEMU_BUILD_TIMEOUT: 2400 - QEMU_COPY_ARTIFACTS_TIMEOUT: 120 - QEMU_VM_MEMORY: 3072 - ARCHISO_COW_SPACE_SIZE: 2g - stages: - check - build @@ -33,6 +19,19 @@ check: stage: check interruptible: true +.build: + artifacts: + reports: + metrics: output/metrics.txt + before_script: + - pacman -Sy --needed --noconfirm archlinux-keyring + - pacman -Syu --needed --noconfirm arch-install-scripts bash dosfstools e2fsprogs erofs-utils gnupg grub jq libarchive libisoburn mtools openssl qemu-headless squashfs-tools zsync + script: + - ./.gitlab/ci/build_archiso.sh ${BUILD_SCRIPT_ARGS} + stage: build + tags: + - vm + build_short: extends: .build parallel: @@ -59,8 +58,6 @@ build_long: - BUILD_SCRIPT_ARGS: baseline netboot - BUILD_SCRIPT_ARGS: releng iso - BUILD_SCRIPT_ARGS: releng netboot - tags: - - fast-single-thread only: refs: - master diff --git a/.gitlab/ci/build_archiso.sh b/.gitlab/ci/build_archiso.sh index 5250b51..104792a 100755 --- a/.gitlab/ci/build_archiso.sh +++ b/.gitlab/ci/build_archiso.sh @@ -30,6 +30,8 @@ gnupg_homedir="" codesigning_dir="" codesigning_cert="" codesigning_key="" +ca_cert="" +ca_key="" pgp_key_id="" print_section_start() { @@ -204,43 +206,103 @@ EOF print_section_end "ephemeral_pgp_key" } -create_ephemeral_codesigning_key() { +create_ephemeral_codesigning_keys() { # create ephemeral certificates used for codesigning - print_section_start "ephemeral_codesigning_key" "Creating ephemeral codesigning key" + print_section_start "ephemeral_codesigning_key" "Creating ephemeral codesigning keys" + # The exact steps in creating a CA with Codesigning being signed was taken from + # https://jamielinux.com/docs/openssl-certificate-authority/introduction.html + # (slight modifications to the process to not disturb default values of /etc/ssl/openssl.cnf) + codesigning_dir="${tmpdir}/.codesigning/" - local codesigning_conf="${codesigning_dir}/openssl.cnf" + local ca_dir="${codesigning_dir}/ca/" + + local ca_conf="${ca_dir}/certificate_authority.cnf" + local ca_subj="/C=DE/ST=Berlin/L=Berlin/O=Arch Linux/OU=Release Engineering/CN=archlinux.org" + ca_cert="${ca_dir}/cacert.pem" + ca_key="${ca_dir}/private/cakey.pem" + + local codesigning_conf="${codesigning_dir}/code_signing.cnf" local codesigning_subj="/C=DE/ST=Berlin/L=Berlin/O=Arch Linux/OU=Release Engineering/CN=archlinux.org" codesigning_cert="${codesigning_dir}/codesign.crt" codesigning_key="${codesigning_dir}/codesign.key" + + mkdir -p "${ca_dir}/"{private,newcerts,crl} mkdir -p "${codesigning_dir}" cp -- /etc/ssl/openssl.cnf "${codesigning_conf}" - printf "\n[codesigning]\nkeyUsage=digitalSignature\nextendedKeyUsage=codeSigning\n" >> "${codesigning_conf}" + cp -- /etc/ssl/openssl.cnf "${ca_conf}" + touch "${ca_dir}/index.txt" + echo "1000" > "${ca_dir}/serial" + + # Prepare the ca configuration for the change in directory + sed -i "s#/etc/ssl#${ca_dir}#g" "${ca_conf}" + + # Create the Certificate Authority + openssl req \ + -newkey rsa:4096 \ + -sha256 \ + -nodes \ + -x509 \ + -new \ + -sha256 \ + -keyout "${ca_key}" \ + -config "${ca_conf}" \ + -subj "${ca_subj}" \ + -out "${ca_cert}" + + cat << EOF >> "${ca_conf}" + +[ v3_intermediate_ca ] +# Extensions for a typical intermediate CA ('man x509v3_config'). +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true, pathlen:0 +keyUsage = critical, digitalSignature, cRLSign, keyCertSign + +EOF + + cat << EOF >> "${codesigning_conf}" + +[codesigning] +keyUsage=digitalSignature +extendedKeyUsage=codeSigning, clientAuth, emailProtection + +EOF + openssl req \ -newkey rsa:4096 \ -keyout "${codesigning_key}" \ -nodes \ -sha256 \ - -x509 \ - -days 365 \ - -out "${codesigning_cert}" \ + -out "${codesigning_cert}.csr" \ -config "${codesigning_conf}" \ -subj "${codesigning_subj}" \ -extensions codesigning + # Sign the code signing certificate with the CA + openssl ca \ + -batch \ + -config "${ca_conf}" \ + -extensions v3_intermediate_ca \ + -days 3650 \ + -notext \ + -md sha256 \ + -in "${codesigning_cert}.csr" \ + -out "${codesigning_cert}" + print_section_end "ephemeral_codesigning_key" } run_mkarchiso() { # run mkarchiso create_ephemeral_pgp_key - create_ephemeral_codesigning_key + create_ephemeral_codesigning_keys print_section_start "mkarchiso" "Running mkarchiso" mkdir -p "${output}/" "${tmpdir}/" GNUPGHOME="${gnupg_homedir}" ./archiso/mkarchiso \ -D "${install_dir}" \ - -c "${codesigning_cert} ${codesigning_key}" \ + -c "${codesigning_cert} ${codesigning_key} ${ca_cert}" \ -g "${pgp_key_id}" \ -G "${pgp_sender}" \ -o "${output}/" \ diff --git a/AUTHORS.rst b/AUTHORS.rst index 3a03c0e..18207eb 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -34,3 +34,6 @@ Archiso Authors * Yu Li-Yu <afg984@gmail.com> * nl6720 <nl6720@gmail.com> * Øyvind Heggstad <heggstad@gmail.com> +* plain linen <bcdedit@hotmail.com> +* Pellegrino Prevete <pellegrinoprevete@gmail.com> +* Anton Hvornum <anton@hvornum.se> diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 639c266..1b05ff4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,15 +8,84 @@ Changelog Added ----- -- Add ``uefi-ia32.grub.esp`` boot mode to support IA32 UEFI boot on x86_64 machines. -- Add GRUB configuration files to profiles. +Changed +------- + +Removed +------- + +[67] - 2022-09-25 +================= + +Added +----- + +- The ability to generate rootfs signatures using openssl CMS module if ``-c`` is given. + +Changed +------- + +- Order ``pacman-init.service`` before ``archlinux-keyring-wkd-sync.service`` since + ``archlinux-keyring-wkd-sync.service`` needs an initialized pacman keyring. +- Order ``pacman-init.service`` after ``time-sync.target`` since ``pacman-init.service`` may otherwise create local + signatures that are not valid on target systems after installation. + +[66] - 2022-08-28 +================= + +Added +----- + +- Add ``efibootimg`` to ``mkarchiso`` to abstract the FAT image path. +- Unset ``LANGUAGE`` since ``LC_ALL=C.UTF-8``, unlike ``LC_ALL=C``, does not override ``LANGUAGE``. +- Copy all files from the ``grub`` directory to ISO9660 and the FAT image, not just only ``grub.cfg``. +- Touching ``/usr/lib/clock-epoch`` to to help ``systemd`` with screwed or broken RTC. Changed ------- +- Disable GRUB's shim_lock verifier and preload more modules. This allows reusing the GRUB EFI binaries when repacking + the ISO to support Secure Boot with custom signatures. + +[65] - 2022-06-30 +================= + +Added +----- + +- Configure the locale for the baseline profile to ``C.UTF-8`` so that a UTF-8 locale is used. +- Add ``uefi-x64.grub.esp`` and ``uefi-x64.grub.eltorito`` boot mode to support x86_64 UEFI boot on x86_64 machines. +- Use ``mkfs.erofs``'s ``ztailpacking`` option in the baseline profile to reduce the image size. + +Changed +------- + +- Change the releng profile's locale from ``en_US.UTF-8`` to ``C.UTF-8``. +- Set ``LC_ALL`` to ``C.UTF-8`` instead of ``C`` in mkarchiso since it is now available and non-UTF-8 locales should be + avoided. + Removed ------- +- Remove the custom pacman hook that ran ``locale-gen`` on glibc install from the releng profile. The used locale now + ships with the glibc package itself. + +[64] - 2022-05-30 +================= + +Added +----- + +- Add ``uefi-ia32.grub.esp`` boot mode to support IA32 UEFI boot on x86_64 machines. +- Add GRUB configuration files to profiles. +- Add accessible ``copytoram`` entry. +- Enable beeps in systemd-boot menu. + +Changed +------- + +- Fix systemd-boot menu entry sorting by using the ``sort-key`` option. + [63] - 2022-04-30 ================= @@ -156,7 +156,7 @@ Releases `Releases of archiso <https://gitlab.archlinux.org/archlinux/archiso/-/tags>`_ are created by their current maintainers -- `David Runge <https://gitlab.archlinux.org/dvzrv>`_ (``C7E7849466FE2358343588377258734B41C31549``) +- `David Runge <https://gitlab.archlinux.org/dvzrv>`_ (``991F6E3F0765CF6295888586139B09DA5BF0D338``) - `nl6720 <https://gitlab.archlinux.org/nl6720>`_ (``BB8E6F1B81CF0BB301D74D1CBF425A01E68B38EF``) Tags are signed using respective PGP keys. diff --git a/archiso/mkarchiso b/archiso/mkarchiso index b81b700..33a0c1a 100755 --- a/archiso/mkarchiso +++ b/archiso/mkarchiso @@ -3,10 +3,16 @@ # SPDX-License-Identifier: GPL-3.0-or-later set -e -u +shopt -s extglob # Control the environment umask 0022 -export LC_ALL="C" +export LC_ALL="C.UTF-8" +if [[ -v LANGUAGE ]]; then + # LC_ALL=C.UTF-8, unlike LC_ALL=C, does not override LANGUAGE. + # See https://sourceware.org/bugzilla/show_bug.cgi?id=16621 and https://savannah.gnu.org/bugs/?62815 + unset LANGUAGE +fi [[ -v SOURCE_DATE_EPOCH ]] || printf -v SOURCE_DATE_EPOCH '%(%s)T' -1 export SOURCE_DATE_EPOCH @@ -39,8 +45,8 @@ bootmodes=() airootfs_image_type="" airootfs_image_tool_options=() cert_list=() -sign_netboot_artifacts="" declare -A file_permissions=() +efibootimg="" efiboot_files=() # adapted from GRUB_EARLY_INITRD_LINUX_STOCK in https://git.savannah.gnu.org/cgit/grub.git/tree/util/grub-mkconfig.in readonly ucodes=('intel-uc.img' 'intel-ucode.img' 'amd-uc.img' 'amd-ucode.img' 'early_ucode.cpio' 'microcode.cpio') @@ -89,10 +95,11 @@ usage: ${app_name} [options] <profile_dir> Default: '${iso_label}' -P <publisher> Set the ISO publisher Default: '${iso_publisher}' - -c [cert ..] Provide certificates for codesigning of netboot artifacts + -c [cert ..] Provide certificates for codesigning of netboot artifacts as + well as the rootfs artifact. Multiple files are provided as quoted, space delimited list. The first file is considered as the signing certificate, - the second as the key. + the second as the key and the third as the optional certificate authority. -g <gpg_key> Set the PGP key ID to be used for signing the rootfs image. Passed to gpg as the value for --default-key -G <mbox> Set the PGP signer (must include an email address) @@ -245,14 +252,11 @@ _mkchecksum() { } # GPG sign the root file system image. -_mksignature() { - local airootfs_image_filename gpg_options=() - _msg_info "Signing rootfs image..." - if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then - airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" - elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then - airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" - fi +_mk_pgp_signature() { + local gpg_options=() + local airootfs_image_filename="${1}" + _msg_info "Signing rootfs image using GPG..." + rm -f -- "${airootfs_image_filename}.sig" # Add gpg sender option if the value is provided [[ -z "${gpg_sender}" ]] || gpg_options+=('--sender' "${gpg_sender}") @@ -337,6 +341,15 @@ _make_packages() { exec {ARCHISO_GNUPG_FD}<>"${work_dir}/pubkey.gpg" export ARCHISO_GNUPG_FD fi + if [[ -v cert_list[0] ]]; then + exec {ARCHISO_TLS_FD}<>"${cert_list[0]}" + export ARCHISO_TLS_FD + fi + if [[ -v cert_list[2] ]]; then + exec {ARCHISO_TLSCA_FD}<>"${cert_list[2]}" + export ARCHISO_TLSCA_FD + fi + # Unset TMPDIR to work around https://bugs.archlinux.org/task/70580 if [[ "${quiet}" = "y" ]]; then @@ -345,6 +358,14 @@ _make_packages() { env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" fi + if [[ -v cert_list[0] ]]; then + exec {ARCHISO_TLS_FD}<&- + unset ARCHISO_TLS_FD + fi + if [[ -v cert_list[2] ]]; then + exec {ARCHISO_TLSCA_FD}<&- + unset ARCHISO_TLSCA_FD + fi if [[ -n "${gpg_key}" ]]; then exec {ARCHISO_GNUPG_FD}<&- unset ARCHISO_GNUPG_FD @@ -477,9 +498,9 @@ _make_bootmode_bios.syslinux.eltorito() { _make_boot_on_fat() { local ucode_image all_ucode_images=() _msg_info "Preparing kernel and initramfs for the FAT file system..." - mmd -i "${work_dir}/efiboot.img" \ + mmd -i "${efibootimg}" \ "::/${install_dir}" "::/${install_dir}/boot" "::/${install_dir}/boot/${arch}" - mcopy -i "${work_dir}/efiboot.img" "${pacstrap_dir}/boot/vmlinuz-"* \ + mcopy -i "${efibootimg}" "${pacstrap_dir}/boot/vmlinuz-"* \ "${pacstrap_dir}/boot/initramfs-"*".img" "::/${install_dir}/boot/${arch}/" for ucode_image in "${ucodes[@]}"; do if [[ -e "${pacstrap_dir}/boot/${ucode_image}" ]]; then @@ -487,7 +508,7 @@ _make_boot_on_fat() { fi done if (( ${#all_ucode_images[@]} )); then - mcopy -i "${work_dir}/efiboot.img" "${all_ucode_images[@]}" "::/${install_dir}/boot/" + mcopy -i "${efibootimg}" "${all_ucode_images[@]}" "::/${install_dir}/boot/" fi _msg_info "Done!" } @@ -495,74 +516,131 @@ _make_boot_on_fat() { # Create a FAT image (efiboot.img) which will serve as the EFI system partition # $1: image size in bytes _make_efibootimg() { - local imgsize="0" + local imgsize_kib="0" + local imgsize_bytes=${1} + + if (( imgsize_bytes < 2*1024*1024 )); then + _msg_info "Validating '${bootmode}': efiboot.img size is ${imgsize_bytes} bytes is less than 2 MiB! Bumping up to 2 MiB" + imgsize_bytes=$((2*1024*1024)) + fi # Convert from bytes to KiB and round up to the next full MiB with an additional MiB for reserved sectors. - imgsize="$(awk 'function ceil(x){return int(x)+(x>int(x))} + imgsize_kib="$(awk 'function ceil(x){return int(x)+(x>int(x))} function byte_to_kib(x){return x/1024} function mib_to_kib(x){return x*1024} - END {print mib_to_kib(ceil((byte_to_kib($1)+1024)/1024))}' <<< "${1}" + END {print mib_to_kib(ceil((byte_to_kib($1)+1024)/1024))}' <<< "${imgsize_bytes}" )" # The FAT image must be created with mkfs.fat not mformat, as some systems have issues with mformat made images: # https://lists.gnu.org/archive/html/grub-devel/2019-04/msg00099.html - rm -f -- "${work_dir}/efiboot.img" - _msg_info "Creating FAT image of size: ${imgsize} KiB..." + rm -f -- "${efibootimg}" + _msg_info "Creating FAT image of size: ${imgsize_kib} KiB..." if [[ "${quiet}" == "y" ]]; then # mkfs.fat does not have a -q/--quiet option, so redirect stdout to /dev/null instead # https://github.com/dosfstools/dosfstools/issues/103 - mkfs.fat -C -n ARCHISO_EFI "${work_dir}/efiboot.img" "${imgsize}" > /dev/null + mkfs.fat -C -n ARCHISO_EFI "${efibootimg}" "${imgsize_kib}" > /dev/null else - mkfs.fat -C -n ARCHISO_EFI "${work_dir}/efiboot.img" "${imgsize}" + mkfs.fat -C -n ARCHISO_EFI "${efibootimg}" "${imgsize_kib}" fi # Create the default/fallback boot path in which a boot loaders will be placed later. - mmd -i "${work_dir}/efiboot.img" ::/EFI ::/EFI/BOOT + mmd -i "${efibootimg}" ::/EFI ::/EFI/BOOT } -_make_bootmode_uefi-ia32.grub.esp() { - # Fill Grub configuration files - sed "s|%ARCHISO_LABEL%|${iso_label}|g; - s|%INSTALL_DIR%|${install_dir}|g; - s|%ARCH%|${arch}|g" \ - "${profile}/grub/grub.cfg" > "${work_dir}/grub.cfg" +# Copy GRUB files to efiboot.img which is used by both IA32 UEFI and x64 UEFI. +_make_common_bootmode_grub_copy_to_efibootimg() { + local files_to_copy=() + + files_to_copy+=("${work_dir}/grub/"*) + if compgen -G "${profile}/grub/!(*.cfg)" &> /dev/null; then + files_to_copy+=("${profile}/grub/"!(*.cfg)) + fi + mcopy -i "${efibootimg}" "${files_to_copy[@]}" ::/EFI/BOOT/ +} + +# Copy GRUB files to efiboot.img which is used by both IA32 UEFI and x64 UEFI. +_make_common_bootmode_grub_copy_to_isofs() { + local files_to_copy=() + + files_to_copy+=("${work_dir}/grub/"*) + if compgen -G "${profile}/grub/!(*.cfg)" &> /dev/null; then + files_to_copy+=("${profile}/grub/"!(*.cfg)) + fi + install -m 0644 -- "${files_to_copy[@]}" "${isofs_dir}/EFI/BOOT/" +} + +# Prepare GRUB configuration files +_make_common_bootmode_grub_cfg(){ + local _cfg + + install -d -- "${work_dir}/grub" + + # Fill GRUB configuration files + for _cfg in "${profile}/grub/"*'.cfg'; do + sed "s|%ARCHISO_LABEL%|${iso_label}|g; + s|%INSTALL_DIR%|${install_dir}|g; + s|%ARCH%|${arch}|g" \ + "${_cfg}" > "${work_dir}/grub/${_cfg##*/}" + done + # Add all GRUB files to the list of files used to calculate the required FAT image size. + efiboot_files+=("${work_dir}/grub/" + "${profile}/grub/"!(*.cfg)) - # shellcheck disable=SC2016 - printf 'configfile ${cmdpath}/grub.cfg\n' > "${work_dir}/grub-embed.cfg" + IFS='' read -r -d '' grubembedcfg <<'EOF' || true +if ! [ -d "$cmdpath" ]; then + # On some firmware, GRUB has a wrong cmdpath when booted from an optical disc. + # https://gitlab.archlinux.org/archlinux/archiso/-/issues/183 + if regexp --set=1:isodevice '^(\([^)]+\))\/?[Ee][Ff][Ii]\/[Bb][Oo][Oo][Tt]\/?$' "$cmdpath"; then + cmdpath="${isodevice}/EFI/BOOT" + fi +fi +configfile "${cmdpath}/grub.cfg" +EOF + printf '%s\n' "$grubembedcfg" > "${work_dir}/grub-embed.cfg" +} - # Create EFI file +_make_bootmode_uefi-ia32.grub.esp() { + local grubmodules=() + + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Create EFI binary + # Module list from https://bugs.archlinux.org/task/71382#comment202911 + grubmodules=(all_video at_keyboard boot btrfs cat chain configfile echo efifwsetup efinet ext2 f2fs fat font \ + gfxmenu gfxterm gzio halt hfsplus iso9660 jpeg keylayouts linux loadenv loopback lsefi lsefimmap \ + minicmd normal part_apple part_gpt part_msdos png read reboot regexp search search_fs_file \ + search_fs_uuid search_label serial sleep tpm usb usbserial_common usbserial_ftdi usbserial_pl2303 \ + usbserial_usbdebug video xfs zstd) grub-mkstandalone -O i386-efi \ - --modules="part_gpt part_msdos fat iso9660" \ + --modules="${grubmodules[*]}" \ --locales="en@quot" \ --themes="" \ + --sbat=/usr/share/grub/sbat.csv \ + --disable-shim-lock \ -o "${work_dir}/BOOTIA32.EFI" "boot/grub/grub.cfg=${work_dir}/grub-embed.cfg" # Add GRUB to the list of files used to calculate the required FAT image size. efiboot_files+=("${work_dir}/BOOTIA32.EFI" "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi") - if [[ ! " ${bootmodes[*]} " =~ uefi-x64.systemd-boot.esp ]]; then - efiboot_files+=("${pacstrap_dir}/boot/vmlinuz-"* - "${pacstrap_dir}/boot/initramfs-"*".img") - - efiboot_imgsize="$(du -bc "${efiboot_files[@]}" \ - 2>/dev/null | awk 'END { print $1 }')" + if [[ " ${bootmodes[*]} " =~ uefi-x64.systemd-boot.esp ]]; then + # TODO: Remove this branch. + _run_once _make_bootmode_uefi-x64.systemd-boot.esp + elif [[ " ${bootmodes[*]} " =~ uefi-x64.grub.esp ]]; then + _run_once _make_bootmode_uefi-x64.grub.esp + else + efiboot_imgsize="$(du -bcs -- "${efiboot_files[@]}" 2>/dev/null | awk 'END { print $1 }')" # Create a FAT image for the EFI system partition _make_efibootimg "$efiboot_imgsize" - else - _run_once _make_bootmode_uefi-x64.systemd-boot.esp fi - # Copy grub EFI binary to the default/fallback boot path - mcopy -i "${work_dir}/efiboot.img" \ - "${work_dir}/BOOTIA32.EFI" ::/EFI/BOOT/BOOTIA32.EFI + # Copy GRUB EFI binary to the default/fallback boot path + mcopy -i "${efibootimg}" "${work_dir}/BOOTIA32.EFI" ::/EFI/BOOT/BOOTIA32.EFI - # Copy GRUB configuration files - mcopy -i "${work_dir}/efiboot.img" \ - "${work_dir}/grub.cfg" ::/EFI/BOOT/grub.cfg + # Copy GRUB files + _run_once _make_common_bootmode_grub_copy_to_efibootimg - # shellia32.efi is picked up automatically when on / if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ]]; then - mcopy -i "${work_dir}/efiboot.img" \ - "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ::/shellia32.efi + mcopy -i "${efibootimg}" "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ::/shellia32.efi fi _msg_info "Done! GRUB set up for UEFI booting successfully." @@ -574,30 +652,101 @@ _make_bootmode_uefi-ia32.grub.eltorito() { # uefi-ia32.grub.eltorito has the same requirements as uefi-ia32.grub.esp _run_once _make_bootmode_uefi-ia32.grub.esp - # Additionally set up system-boot in ISO 9660. This allows creating a medium for the live environment by using + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Additionally set up systemd-boot in ISO 9660. This allows creating a medium for the live environment by using # manual partitioning and simply copying the ISO 9660 file system contents. # This is not related to El Torito booting and no firmware uses these files. _msg_info "Preparing an /EFI directory for the ISO 9660 file system..." install -d -m 0755 -- "${isofs_dir}/EFI/BOOT" # Copy GRUB EFI binary to the default/fallback boot path - install -m 0644 -- "${work_dir}/BOOTIA32.EFI" \ - "${isofs_dir}/EFI/BOOT/BOOTIA32.EFI" + install -m 0644 -- "${work_dir}/BOOTIA32.EFI" "${isofs_dir}/EFI/BOOT/BOOTIA32.EFI" # Copy GRUB configuration files - install -m 0644 -- "${work_dir}/grub.cfg" "${isofs_dir}/EFI/BOOT/grub.cfg" + _run_once _make_common_bootmode_grub_copy_to_isofs # edk2-shell based UEFI shell - # shellia32.efi is picked up automatically when on / if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ]]; then - install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" \ - "${isofs_dir}/shellia32.efi" + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" "${isofs_dir}/shellia32.efi" fi _msg_info "Done!" } -# Prepare system-boot for booting when written to a disk (isohybrid) +_make_bootmode_uefi-x64.grub.esp() { + local grubmodules=() + + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Create EFI binary + # Module list from https://bugs.archlinux.org/task/71382#comment202911 + grubmodules=(all_video at_keyboard boot btrfs cat chain configfile echo efifwsetup efinet ext2 f2fs fat font \ + gfxmenu gfxterm gzio halt hfsplus iso9660 jpeg keylayouts linux loadenv loopback lsefi lsefimmap \ + minicmd normal part_apple part_gpt part_msdos png read reboot regexp search search_fs_file \ + search_fs_uuid search_label serial sleep tpm usb usbserial_common usbserial_ftdi usbserial_pl2303 \ + usbserial_usbdebug video xfs zstd) + grub-mkstandalone -O x86_64-efi \ + --modules="${grubmodules[*]}" \ + --locales="en@quot" \ + --themes="" \ + --sbat=/usr/share/grub/sbat.csv \ + --disable-shim-lock \ + -o "${work_dir}/BOOTx64.EFI" "boot/grub/grub.cfg=${work_dir}/grub-embed.cfg" + # Add GRUB to the list of files used to calculate the required FAT image size. + efiboot_files+=("${work_dir}/BOOTx64.EFI" + "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi") + + efiboot_imgsize="$(du -bcs -- "${efiboot_files[@]}" 2>/dev/null | awk 'END { print $1 }')" + + # Create a FAT image for the EFI system partition + _make_efibootimg "$efiboot_imgsize" + + # Copy GRUB EFI binary to the default/fallback boot path + mcopy -i "${efibootimg}" "${work_dir}/BOOTx64.EFI" ::/EFI/BOOT/BOOTx64.EFI + + # Copy GRUB files + _run_once _make_common_bootmode_grub_copy_to_efibootimg + + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then + mcopy -i "${efibootimg}" "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi + fi + + _msg_info "Done! GRUB set up for UEFI booting successfully." +} + +# Prepare GRUB for El Torito booting +_make_bootmode_uefi-x64.grub.eltorito() { + # El Torito UEFI boot requires an image containing the EFI system partition. + # uefi-x64.grub.eltorito has the same requirements as uefi-x64.grub.esp + _run_once _make_bootmode_uefi-x64.grub.esp + + # Prepare configuration files + _run_once _make_common_bootmode_grub_cfg + + # Additionally set up systemd-boot in ISO 9660. This allows creating a medium for the live environment by using + # manual partitioning and simply copying the ISO 9660 file system contents. + # This is not related to El Torito booting and no firmware uses these files. + _msg_info "Preparing an /EFI directory for the ISO 9660 file system..." + install -d -m 0755 -- "${isofs_dir}/EFI/BOOT" + + # Copy GRUB EFI binary to the default/fallback boot path + install -m 0644 -- "${work_dir}/BOOTx64.EFI" "${isofs_dir}/EFI/BOOT/BOOTx64.EFI" + + # Copy GRUB files + _run_once _make_common_bootmode_grub_copy_to_isofs + + # edk2-shell based UEFI shell + if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${isofs_dir}/shellx64.efi" + fi + + _msg_info "Done!" +} + +# Prepare systemd-boot for booting when written to a disk (isohybrid) _make_bootmode_uefi-x64.systemd-boot.esp() { local _file efiboot_imgsize local _available_ucodes=() @@ -615,28 +764,28 @@ _make_bootmode_uefi-x64.systemd-boot.esp() { "${pacstrap_dir}/boot/vmlinuz-"* "${pacstrap_dir}/boot/initramfs-"*".img" "${_available_ucodes[@]}") - efiboot_imgsize="$(du -bc "${efiboot_files[@]}" \ + efiboot_imgsize="$(du -bcs -- "${efiboot_files[@]}" \ 2>/dev/null | awk 'END { print $1 }')" # Create a FAT image for the EFI system partition _make_efibootimg "$efiboot_imgsize" # Copy systemd-boot EFI binary to the default/fallback boot path - mcopy -i "${work_dir}/efiboot.img" \ + mcopy -i "${efibootimg}" \ "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI # Copy systemd-boot configuration files - mmd -i "${work_dir}/efiboot.img" ::/loader ::/loader/entries - mcopy -i "${work_dir}/efiboot.img" "${profile}/efiboot/loader/loader.conf" ::/loader/ + mmd -i "${efibootimg}" ::/loader ::/loader/entries + mcopy -i "${efibootimg}" "${profile}/efiboot/loader/loader.conf" ::/loader/ for _conf in "${profile}/efiboot/loader/entries/"*".conf"; do sed "s|%ARCHISO_LABEL%|${iso_label}|g; s|%INSTALL_DIR%|${install_dir}|g; s|%ARCH%|${arch}|g" \ - "${_conf}" | mcopy -i "${work_dir}/efiboot.img" - "::/loader/entries/${_conf##*/}" + "${_conf}" | mcopy -i "${efibootimg}" - "::/loader/entries/${_conf##*/}" done # shellx64.efi is picked up automatically when on / if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then - mcopy -i "${work_dir}/efiboot.img" \ + mcopy -i "${efibootimg}" \ "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi fi @@ -647,13 +796,13 @@ _make_bootmode_uefi-x64.systemd-boot.esp() { _msg_info "Done! systemd-boot set up for UEFI booting successfully." } -# Prepare system-boot for El Torito booting +# Prepare systemd-boot for El Torito booting _make_bootmode_uefi-x64.systemd-boot.eltorito() { # El Torito UEFI boot requires an image containing the EFI system partition. # uefi-x64.systemd-boot.eltorito has the same requirements as uefi-x64.systemd-boot.esp _run_once _make_bootmode_uefi-x64.systemd-boot.esp - # Additionally set up system-boot in ISO 9660. This allows creating a medium for the live environment by using + # Additionally set up systemd-boot in ISO 9660. This allows creating a medium for the live environment by using # manual partitioning and simply copying the ISO 9660 file system contents. # This is not related to El Torito booting and no firmware uses these files. _msg_info "Preparing an /EFI directory for the ISO 9660 file system..." @@ -726,6 +875,11 @@ _validate_requirements_bootmode_bios.syslinux.eltorito() { } _validate_requirements_bootmode_uefi-x64.systemd-boot.esp() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.grub.esp!" 0 + fi + # Check if mkfs.fat is available if ! command -v mkfs.fat &> /dev/null; then (( validation_error=validation_error+1 )) @@ -766,6 +920,11 @@ _validate_requirements_bootmode_uefi-x64.systemd-boot.esp() { } _validate_requirements_bootmode_uefi-x64.systemd-boot.eltorito() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.eltorito ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.grub.eltorito!" 0 + fi + # uefi-x64.systemd-boot.eltorito has the exact same requirements as uefi-x64.systemd-boot.esp _validate_requirements_bootmode_uefi-x64.systemd-boot.esp } @@ -776,7 +935,15 @@ _validate_requirements_bootmode_uefi-ia32.grub.esp() { (( validation_error=validation_error+1 )) _msg_error "Validating '${bootmode}': grub-install is not available on this host. Install 'grub'!" 0 fi - _validate_requirements_bootmode_uefi-x64.systemd-boot.esp + + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' ]]; then + _validate_requirements_bootmode_uefi-x64.systemd-boot.esp + elif [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' ]]; then + _validate_requirements_bootmode_uefi-x64.grub.esp + else + _msg_error "Validating '${bootmode}': requires one of bootmode uefi-x64.systemd-boot.esp or uefi-x64.grub.esp" 0 + fi } _validate_requirements_bootmode_uefi-ia32.grub.eltorito() { @@ -784,12 +951,81 @@ _validate_requirements_bootmode_uefi-ia32.grub.eltorito() { _validate_requirements_bootmode_uefi-ia32.grub.esp } +_validate_requirements_bootmode_uefi-x64.grub.esp() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.systemd-boot.esp!" 0 + fi + + # Check if GRUB is available + if ! command -v grub-mkstandalone &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': grub-install is not available on this host. Install 'grub'!" 0 + fi + + # Check if mkfs.fat is available + if ! command -v mkfs.fat &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': mkfs.fat is not available on this host. Install 'dosfstools'!" 0 + fi + + # Check if mmd and mcopy are available + if ! { command -v mmd &> /dev/null && command -v mcopy &> /dev/null; }; then + _msg_error "Validating '${bootmode}': mmd and/or mcopy are not available on this host. Install 'mtools'!" 0 + fi + + # Check if GRUB configuration files exist + if [[ ! -d "${profile}/grub" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': The '${profile}/grub' directory is missing!" 0 + else + if [[ ! -e "${profile}/grub/grub.cfg" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': File '${profile}/grub/grub.cfg' not found!" 0 + fi + local conffile + for conffile in "${profile}/grub/"*'.cfg'; do + if [[ -e "${conffile}" ]]; then + break + else + (( validation_error=validation_error+1 )) + _msg_error "Validating '${bootmode}': No configuration file found in '${profile}/grub/'!" 0 + fi + done + fi + + # Check for optional packages + # shellcheck disable=SC2076 + if [[ ! " ${pkg_list[*]} " =~ ' edk2-shell ' ]]; then + _msg_info "'edk2-shell' is not in the package list. The ISO will not contain a bootable UEFI shell." + fi +} + +_validate_requirements_bootmode_uefi-x64.grub.eltorito() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' ]]; then + _msg_error "Validating '${bootmode}': cannot be used with bootmode uefi-x64.systemd-boot.eltorito!" 0 + fi + # uefi-x64.grub.eltorito has the exact same requirements as uefi-x64.grub.esp + _validate_requirements_bootmode_uefi-x64.grub.esp +} + # Build airootfs filesystem image _prepare_airootfs_image() { _run_once "_mkairootfs_${airootfs_image_type}" _mkchecksum + + if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" + elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" + fi + if [[ -n "${gpg_key}" ]]; then - _mksignature + _mk_pgp_signature "${airootfs_image_filename}" + fi + if [[ -v cert_list ]]; then + _cms_sign_artifact "${airootfs_image_filename}" fi } @@ -802,6 +1038,32 @@ _export_netboot_artifacts() { du -hs -- "${out_dir}/${install_dir}" } +_cms_sign_artifact() { + local artifact="${1}" + local openssl_flags=( + "-sign" + "-binary" + "-nocerts" + "-noattr" + "-outform" "DER" "-out" "${artifact}.cms.sig" + "-in" "${artifact}" + "-signer" "${cert_list[0]}" + "-inkey" "${cert_list[1]}" + ) + + if (( ${#cert_list[@]} > 2 )); then + openssl_flags+=("-certfile" "${cert_list[2]}") + fi + + _msg_info "Signing ${artifact} image using openssl cms..." + + rm -f -- "${artifact}.cms.sig" + + openssl cms "${openssl_flags[@]}" + + _msg_info "Done!" +} + # sign build artifacts for netboot _sign_netboot_artifacts() { local _file _dir @@ -905,6 +1167,26 @@ _validate_common_requirements_buildmode_iso_netboot() { _msg_error "Packages file '${packages}' does not exist." 0 fi + if [[ -v cert_list ]]; then + # Check if the certificate files exist + for _cert in "${cert_list[@]}"; do + if [[ ! -e "${_cert}" ]]; then + (( validation_error=validation_error+1 )) + _msg_error "File '${_cert}' does not exist." 0 + fi + done + # Check if there are at least three certificate files to sign netboot and rootfs. + if (( ${#cert_list[@]} < 2 )); then + (( validation_error=validation_error+1 )) + _msg_error "Two certificates are required for codesigning netboot artifacts, but '${cert_list[*]}' is provided." 0 + fi + + if ! command -v openssl &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating build mode '${_buildmode}': openssl is not available on this host. Install 'openssl'!" 0 + fi + fi + # Check if the specified airootfs_image_type is supported if typeset -f "_mkairootfs_${airootfs_image_type}" &> /dev/null; then if typeset -f "_validate_requirements_airootfs_image_type_${airootfs_image_type}" &> /dev/null; then @@ -946,31 +1228,8 @@ _validate_requirements_buildmode_iso() { } _validate_requirements_buildmode_netboot() { - local _override_cert_list=() - - if [[ "${sign_netboot_artifacts}" == "y" ]]; then - # Check if the certificate files exist - for _cert in "${cert_list[@]}"; do - if [[ -e "${_cert}" ]]; then - _override_cert_list+=("$(realpath -- "${_cert}")") - else - (( validation_error=validation_error+1 )) - _msg_error "File '${_cert}' does not exist." 0 - fi - done - cert_list=("${_override_cert_list[@]}") - # Check if there are at least two certificate files - if (( ${#cert_list[@]} < 2 )); then - (( validation_error=validation_error+1 )) - _msg_error "Two certificates are required for codesigning, but '${cert_list[*]}' is provided." 0 - fi - fi _validate_common_requirements_buildmode_iso_netboot _validate_common_requirements_buildmode_all - if ! command -v openssl &> /dev/null; then - (( validation_error=validation_error+1 )) - _msg_error "Validating build mode '${_buildmode}': openssl is not available on this host. Install 'openssl'!" 0 - fi } # SYSLINUX El Torito @@ -1004,17 +1263,20 @@ _add_xorrisofs_options_bios.syslinux.mbr() { # GRUB in an attached EFI system partition _add_xorrisofs_options_uefi-ia32.grub.esp() { + # TODO: how does the bootmodes systemd-boot vs x64.grub affect ${bootmodes[*]} tests in _add_xorrisofs_options_uefi-x64.systemd-boot.esp etc? # shellcheck disable=SC2076 - if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' ]]; then - _add_xorrisofs_options_uefi-x64.systemd-boot.esp + if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' && ! " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' ]]; then + # _add_xorrisofs_options_uefi-x64.systemd-boot.esp + _add_xorrisofs_options_uefi-x64.grub.esp fi } # GRUB via El Torito _add_xorrisofs_options_uefi-ia32.grub.eltorito() { # shellcheck disable=SC2076 - if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' ]]; then - _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito + if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.eltorito ' && ! " ${bootmodes[*]} " =~ ' uefi-x64.grub.eltorito ' ]]; then + # _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito + _add_xorrisofs_options_uefi-x64.grub.eltorito fi } @@ -1025,7 +1287,7 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.esp() { # shellcheck disable=SC2076 [[ " ${xorrisofs_options[*]} " =~ ' -partition_offset ' ]] || xorrisofs_options+=('-partition_offset' '16') # Attach efiboot.img as a second partition and set its partition type to "EFI system partition" - xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${work_dir}/efiboot.img") + xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${efibootimg}") # Ensure GPT is used as some systems do not support UEFI booting without it # shellcheck disable=SC2076 if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then @@ -1072,7 +1334,7 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { # The ISO will not contain a GPT partition table, so to be able to reference efiboot.img, place it as a # file inside the ISO 9660 file system install -d -m 0755 -- "${isofs_dir}/EFI/archiso" - cp -a -- "${work_dir}/efiboot.img" "${isofs_dir}/EFI/archiso/efiboot.img" + cp -a -- "${efibootimg}" "${isofs_dir}/EFI/archiso/efiboot.img" # systemd-boot in an embedded efiboot.img via El Torito xorrisofs_options+=( # Start a new El Torito boot entry for UEFI @@ -1088,6 +1350,78 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { [[ " ${bootmodes[*]} " =~ ' bios.' ]] || xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat') } +# GRUB in an attached EFI system partition. +# Same as _add_xorrisofs_options_uefi-x64.systemd-boot.esp. +_add_xorrisofs_options_uefi-x64.grub.esp() { + # Move the first partition away from the start of the ISO, otherwise the GPT will not be valid and ISO 9660 + # partition will not be mountable + # shellcheck disable=SC2076 + [[ " ${xorrisofs_options[*]} " =~ ' -partition_offset ' ]] || xorrisofs_options+=('-partition_offset' '16') + # Attach efiboot.img as a second partition and set its partition type to "EFI system partition" + xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${efibootimg}") + # Ensure GPT is used as some systems do not support UEFI booting without it + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then + # A valid GPT prevents BIOS booting on some systems, instead use an invalid GPT (without a protective MBR). + # The attached partition will have the EFI system partition type code in MBR, but in the invalid GPT it will + # have a Microsoft basic partition type code. + if [[ ! " ${bootmodes[*]} " =~ ' uefi-x64.grub.eltorito ' && ! " ${bootmodes[*]} " =~ ' uefi-ia32.grub.eltorito ' ]]; then + # If '-isohybrid-gpt-basdat' is specified before '-e', then the appended EFI system partition will have the + # EFI system partition type ID/GUID in both MBR and GPT. If '-isohybrid-gpt-basdat' is specified after '-e', + # the appended EFI system partition will have the Microsoft basic data type GUID in GPT. + if [[ ! " ${xorrisofs_options[*]} " =~ ' -isohybrid-gpt-basdat ' ]]; then + xorrisofs_options+=('-isohybrid-gpt-basdat') + fi + fi + else + # Use valid GPT if BIOS booting support will not be required + xorrisofs_options+=('-appended_part_as_gpt') + fi +} + +# GRUB via El Torito +# Same as _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito. +_add_xorrisofs_options_uefi-x64.grub.eltorito() { + # shellcheck disable=SC2076 + if [[ " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' || " ${bootmodes[*]} " =~ ' uefi-ia32.grub.esp ' ]]; then + # grub in an attached EFI system partition via El Torito + xorrisofs_options+=( + # Start a new El Torito boot entry for UEFI + '-eltorito-alt-boot' + # Set the second partition as the El Torito UEFI boot image + '-e' '--interval:appended_partition_2:all::' + # Boot image is not emulating floppy or hard disk; required for all known boot loaders + '-no-emul-boot' + ) + # A valid GPT prevents BIOS booting on some systems, use an invalid GPT instead. + if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then + # If '-isohybrid-gpt-basdat' is specified before '-e', then the appended EFI system partition will have the + # EFI system partition type ID/GUID in both MBR and GPT. If '-isohybrid-gpt-basdat' is specified after '-e', + # the appended EFI system partition will have the Microsoft basic data type GUID in GPT. + if [[ ! " ${xorrisofs_options[*]} " =~ ' -isohybrid-gpt-basdat ' ]]; then + xorrisofs_options+=('-isohybrid-gpt-basdat') + fi + fi + else + # The ISO will not contain a GPT partition table, so to be able to reference efiboot.img, place it as a + # file inside the ISO 9660 file system + install -d -m 0755 -- "${isofs_dir}/EFI/archiso" + cp -a -- "${efibootimg}" "${isofs_dir}/EFI/archiso/efiboot.img" + # grub in an embedded efiboot.img via El Torito + xorrisofs_options+=( + # Start a new El Torito boot entry for UEFI + '-eltorito-alt-boot' + # Set efiboot.img as the El Torito UEFI boot image + '-e' 'EFI/archiso/efiboot.img' + # Boot image is not emulating floppy or hard disk; required for all known boot loaders + '-no-emul-boot' + ) + fi + # Specify where to save the El Torito boot catalog file in case it is not already set by bios.syslinux.eltorito + # shellcheck disable=SC2076 + [[ " ${bootmodes[*]} " =~ ' bios.' ]] || xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat') +} + # Build bootstrap image _build_bootstrap_image() { local _bootstrap_parent @@ -1256,10 +1590,7 @@ _set_overrides() { fi [[ ! -v override_gpg_key ]] || gpg_key="$override_gpg_key" [[ ! -v override_gpg_sender ]] || gpg_sender="$override_gpg_sender" - if [[ -v override_cert_list ]]; then - sign_netboot_artifacts="y" - fi - [[ ! -v override_cert_list ]] || cert_list+=("${override_cert_list[@]}") + [[ ! -v override_cert_list ]] || mapfile -t cert_list < <(realpath -- "${override_cert_list[@]}") if [[ -v override_quiet ]]; then quiet="$override_quiet" elif [[ -z "$quiet" ]]; then @@ -1305,6 +1636,11 @@ _make_version() { [[ ! -e "${_os_release}" ]] || sed -i '/^IMAGE_ID=/d;/^IMAGE_VERSION=/d' "${_os_release}" printf 'IMAGE_ID=%s\nIMAGE_VERSION=%s\n' "${iso_name}" "${iso_version}" >> "${_os_release}" fi + + # Touch /usr/lib/clock-epoch to give another hint on date and time + # for systems with screwed or broken RTC. + touch -m -d"@${SOURCE_DATE_EPOCH}" -- "${pacstrap_dir}/usr/lib/clock-epoch" + _msg_info "Done!" } @@ -1385,8 +1721,16 @@ _build_buildmode_netboot() { local run_once_mode="${buildmode}" _build_iso_base + + if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" + elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then + airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" + fi + if [[ -v cert_list ]]; then _run_once _sign_netboot_artifacts + _cms_sign_artifact "${airootfs_image_filename}" fi _run_once _export_netboot_artifacts } @@ -1395,6 +1739,7 @@ _build_buildmode_netboot() { _build_buildmode_iso() { local image_name="${iso_name}-${iso_version}-${arch}.iso" local run_once_mode="${buildmode}" + efibootimg="${work_dir}/efiboot.img" _build_iso_base _run_once _build_iso_image } diff --git a/configs/baseline/airootfs/etc/locale.conf b/configs/baseline/airootfs/etc/locale.conf new file mode 100644 index 0000000..f9c983c --- /dev/null +++ b/configs/baseline/airootfs/etc/locale.conf @@ -0,0 +1 @@ +LANG=C.UTF-8 diff --git a/configs/baseline/grub/grub.cfg b/configs/baseline/grub/grub.cfg index 0e5db49..dead8ce 100644 --- a/configs/baseline/grub/grub.cfg +++ b/configs/baseline/grub/grub.cfg @@ -1,12 +1,12 @@ +# Load partition table and file system modules insmod part_gpt insmod part_msdos insmod fat insmod iso9660 +# Use graphics-mode output insmod all_video - insmod font - if loadfont "${prefix}/fonts/unicode.pf2" ; then insmod gfxterm set gfxmode="auto" @@ -14,14 +14,28 @@ if loadfont "${prefix}/fonts/unicode.pf2" ; then terminal_output gfxterm fi -menuentry "Arch Linux (x86_64, UEFI)" { +# Enable serial console +if serial --unit=0 --speed=115200; then + terminal_input --append serial + terminal_output --append serial +fi + +# Set default menu entry +default=archlinux +timeout=15 +timeout_style=menu + + +# Menu entries + +menuentry "Arch Linux (x86_64, UEFI)" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' { set gfxpayload=keep search --no-floppy --set=root --label %ARCHISO_LABEL% - linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% + linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img } -menuentry "Arch Linux (x86_64, UEFI) Copy to RAM" { +menuentry "Arch Linux (x86_64, UEFI) Copy to RAM" --class arch --class gnu-linux --class gnu --class os --id 'archlinux-copy-to-ram' { set gfxpayload=keep search --no-floppy --set=root --label %ARCHISO_LABEL% linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index 34060f2..4115581 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -9,12 +9,12 @@ iso_version="$(date +%Y.%m.%d)" install_dir="arch" buildmodes=('iso') bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' - 'uefi-ia32.grub.esp' 'uefi-x64.systemd-boot.esp' - 'uefi-ia32.grub.eltorito' 'uefi-x64.systemd-boot.eltorito') + 'uefi-ia32.grub.esp' 'uefi-x64.grub.esp' + 'uefi-ia32.grub.eltorito' 'uefi-x64.grub.eltorito') arch="x86_64" pacman_conf="pacman.conf" airootfs_image_type="erofs" -airootfs_image_tool_options=('-zlz4hc,12') +airootfs_image_tool_options=('-zlz4hc,12' -E ztailpacking) file_permissions=( ["/etc/shadow"]="0:0:400" ) diff --git a/configs/releng/airootfs/etc/locale.conf b/configs/releng/airootfs/etc/locale.conf index 01ec548..f9c983c 100644 --- a/configs/releng/airootfs/etc/locale.conf +++ b/configs/releng/airootfs/etc/locale.conf @@ -1 +1 @@ -LANG=en_US.UTF-8 +LANG=C.UTF-8 diff --git a/configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook b/configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook deleted file mode 100644 index 82dd199..0000000 --- a/configs/releng/airootfs/etc/pacman.d/hooks/40-locale-gen.hook +++ /dev/null @@ -1,13 +0,0 @@ -# remove from airootfs! -[Trigger] -Operation = Install -Type = Package -Target = glibc - -[Action] -Description = Uncommenting en_US.UTF-8 locale and running locale-gen... -When = PostTransaction -Depends = glibc -Depends = sed -Depends = sh -Exec = /bin/sh -c "sed -i 's/#\(en_US\.UTF-8\)/\1/' /etc/locale.gen && locale-gen" diff --git a/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.timesync1.service b/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.timesync1.service new file mode 120000 index 0000000..cd00411 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/dbus-org.freedesktop.timesync1.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-timesyncd.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/pacman-init.service b/configs/releng/airootfs/etc/systemd/system/pacman-init.service index 77704e4..5ee3824 100644 --- a/configs/releng/airootfs/etc/systemd/system/pacman-init.service +++ b/configs/releng/airootfs/etc/systemd/system/pacman-init.service @@ -1,7 +1,9 @@ [Unit] Description=Initializes Pacman keyring Requires=etc-pacman.d-gnupg.mount -After=etc-pacman.d-gnupg.mount +After=etc-pacman.d-gnupg.mount time-sync.target +BindsTo=etc-pacman.d-gnupg.mount +Before=archlinux-keyring-wkd-sync.service [Service] Type=oneshot diff --git a/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service new file mode 120000 index 0000000..cabf28b --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-time-wait-sync.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-time-wait-sync.service
\ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service new file mode 120000 index 0000000..cd00411 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/systemd-timesyncd.service
\ No newline at end of file diff --git a/configs/releng/grub/grub.cfg b/configs/releng/grub/grub.cfg index 4a707b9..43fad0e 100644 --- a/configs/releng/grub/grub.cfg +++ b/configs/releng/grub/grub.cfg @@ -1,12 +1,12 @@ +# Load partition table and file system modules insmod part_gpt insmod part_msdos insmod fat insmod iso9660 +# Use graphics-mode output insmod all_video - insmod font - if loadfont "${prefix}/fonts/unicode.pf2" ; then insmod gfxterm set gfxmode="auto" @@ -14,33 +14,62 @@ if loadfont "${prefix}/fonts/unicode.pf2" ; then terminal_output gfxterm fi +# Enable serial console +if serial --unit=0 --speed=115200; then + terminal_input --append serial + terminal_output --append serial +fi + +# Set default menu entry +default=archlinux +timeout=15 +timeout_style=menu + # GRUB init tune for accessibility -# -# Morse translation table: -# "." is "500 1 300 1" -# "-" is "600 3 300 1" -# " " is "100 2" -# "/" is "100 5" -# -# Message: "s for blind" -play 500 500 1 300 1 500 1 300 1 500 1 300 1 100 5 500 1 300 1 500 1 300 1 100 2 500 1 300 1 500 1 300 1 600 3 300 1 500 1 300 1 100 5 600 3 300 1 500 1 300 1 500 1 300 1 500 1 300 1 100 2 500 1 300 1 600 3 300 1 500 1 300 1 500 1 300 1 100 2 500 1 300 1 500 1 300 1 100 2 500 1 300 1 500 1 300 1 100 2 600 3 300 1 500 1 300 1 100 2 600 3 300 1 500 1 300 1 500 1 300 1 - -menuentry "Arch Linux install medium (x86_64, UEFI)" { +play 600 988 1 1319 4 + +# Menu entries + +menuentry "Arch Linux install medium (x86_64, UEFI)" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' { set gfxpayload=keep search --no-floppy --set=root --label %ARCHISO_LABEL% - linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% + linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% initrd /%INSTALL_DIR%/boot/intel-ucode.img /%INSTALL_DIR%/boot/amd-ucode.img /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img } -menuentry "Arch Linux install medium with speakup screen reader (x86_64, UEFI)" --hotkey=s { +menuentry "Arch Linux install medium with speakup screen reader (x86_64, UEFI)" --hotkey s --class arch --class gnu-linux --class gnu --class os --id 'archlinux-accessibility' { set gfxpayload=keep search --no-floppy --set=root --label %ARCHISO_LABEL% linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% accessibility=on initrd /%INSTALL_DIR%/boot/intel-ucode.img /%INSTALL_DIR%/boot/amd-ucode.img /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img } -menuentry "UEFI Shell" { - insmod chain - search --no-floppy --set=root --label %ARCHISO_LABEL% - chainloader /shellia32.efi +if [ "${grub_platform}" == "efi" ]; then + if [ "${grub_cpu}" == "x86_64" ]; then + menuentry "UEFI Shell" { + insmod chain + search --no-floppy --set=root --label %ARCHISO_LABEL% + chainloader /shellx64.efi + } + elif [ "${grub_cpu}" == "i386" ]; then + menuentry "UEFI Shell" { + insmod chain + search --no-floppy --set=root --label %ARCHISO_LABEL% + chainloader /shellia32.efi + } + fi + + menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' { + fwsetup + } +fi + +menuentry "System shutdown" --class shutdown --class poweroff { + echo "System shutting down..." + halt +} + +menuentry "System restart" --class reboot --class restart { + echo "System rebooting..." + reboot } diff --git a/configs/releng/packages.x86_64 b/configs/releng/packages.x86_64 index 8a0c80d..02ef538 100644 --- a/configs/releng/packages.x86_64 +++ b/configs/releng/packages.x86_64 @@ -38,8 +38,6 @@ grub hdparm hyperv intel-ucode -ipw2100-fw -ipw2200-fw irssi iw iwd diff --git a/docs/README.profile.rst b/docs/README.profile.rst index a3d4309..efcb861 100644 --- a/docs/README.profile.rst +++ b/docs/README.profile.rst @@ -48,6 +48,8 @@ The image file is constructed from some of the variables in ``profiledef.sh``: ` - ``bios.syslinux.eltorito``: Syslinux for x86 BIOS booting from an optical disc - ``uefi-ia32.grub.esp``: GRUB for IA32 UEFI booting from a disk - ``uefi-ia32.grub.eltorito``: GRUB for IA32 UEFI booting from an optical disc + - ``uefi-x64.grub.esp``: GRUB for x86_64 UEFI booting from a disk + - ``uefi-x64.grub.eltorito``: GRUB for x86_64 UEFI booting from an optical disc - ``uefi-x64.systemd-boot.esp``: systemd-boot for x86_64 UEFI booting from a disk - ``uefi-x64.systemd-boot.eltorito``: systemd-boot for x86_64 UEFI booting from an optical disc Note that BIOS El Torito boot mode must always be listed before UEFI El Torito boot mode. @@ -168,7 +170,12 @@ The *custom template identifiers* are understood in all `.cfg` files in this dir grub ---- -This directory is mandatory when the ``uefi-ia32.grub.esp`` or ``uefi-ia32.grub.eltorito`` bootmodes are selected in -``profiledef.sh``. +This directory is mandatory when any of the following bootmodes is used in ``profiledef.sh``: + +- ``uefi-ia32.grub.esp`` or +- ``uefi-ia32.grub.eltorito`` or +- ``uefi-x64.grub.esp`` or +- ``uefi-x64.grub.eltorito`` + It contains configuration files for `GRUB <https://www.gnu.org/software/grub/>`_ used in the resulting image. |