diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a4ca833b614840b71baeea18436b3d972089b04e..5f5fa4b3d7fe22c1e5debfc563a44883b3c25eb1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,10 +7,22 @@ Changelog Added ----- +- Add support for LUKS2 image disks: + - ``+luks`` airootfs image types; + - ``keys`` buildmode; + - ``encryption_key`` parameter. +- Add support for persistent partition on ISO: + - ''persistent_size'' parameter; +- Configure the locale for the baseline profile to ``C.UTF-8`` so that a UTF-8 locale is used. +- Add ``efibootimg`` to ``mkarchiso`` to abstract the FAT image path. 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 ------- diff --git a/archiso/mkarchiso b/archiso/mkarchiso index 5f0c79b5495d6ebf71074a380f922cda992d8a80..123bbd3b7c5ed55dfd0e707bec716ea8df6cf8c4 100755 --- a/archiso/mkarchiso +++ b/archiso/mkarchiso @@ -27,26 +27,41 @@ work_dir="" out_dir="" gpg_key="" gpg_sender="" +gpg_home="" iso_name="" iso_label="" iso_publisher="" iso_application="" iso_version="" +isofs_dir="" install_dir="" arch="" pacman_conf="" packages="" bootstrap_packages="" pacstrap_dir="" +keys_dir="" buildmodes=() bootmodes=() airootfs_image_type="" airootfs_image_tool_options=() +airootfs_img_dir="" +xorriso_options=() +xorrisofs_options=() +keys_image_type="" +keys_image_tool_options=() +dongle_isofs_dir="" +dongle_xorriso_options=() +dongle_xorrisofs_options=() cert_list=() sign_netboot_artifacts="" declare -A file_permissions=() efibootimg="" efiboot_files=() +encryption_key="" +persistent_size_kib="" +persistent_image_type="" +persistentimg="" # 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') @@ -102,6 +117,7 @@ usage: ${app_name} [options] Passed to gpg as the value for --default-key -G Set the PGP signer (must include an email address) Passed to gpg as the value for --sender + -H Set the gpg home directory. -h This message -m [mode ..] Build mode(s) to use (valid modes are: 'bootstrap', 'iso' and 'netboot'). Multiple build modes are provided as quoted, space delimited list. @@ -110,7 +126,7 @@ usage: ${app_name} [options] -p [package ..] Package(s) to install. Multiple packages are provided as quoted, space delimited list. -v Enable verbose output - -w Set the working directory + -w Set the working directory (can't be a bind mount). Default: '${work_dir}' profile_dir: Directory of the archiso profile to build @@ -122,7 +138,7 @@ ENDUSAGETEXT # Shows configuration options. _show_config() { local build_date - printf -v build_date '%(%FT%R%z)T' "${SOURCE_DATE_EPOCH}" + TZ=UTC printf -v build_date '%(%FT%R%z)T' "${SOURCE_DATE_EPOCH}" _msg_info "${app_name} configuration settings" _msg_info " Architecture: ${arch}" _msg_info " Working directory: ${work_dir}" @@ -133,6 +149,8 @@ _show_config() { _msg_info " Build modes: ${buildmodes[*]}" _msg_info " GPG key: ${gpg_key:-None}" _msg_info " GPG signer: ${gpg_sender:-None}" + _msg_info " GPG Home: ${gpg_home:-None}" + _msg_info " Encryption Key: ${encryption_key:-None}" _msg_info "Code signing certificates: ${cert_list[*]:-None}" _msg_info " Profile: ${profile}" _msg_info "Pacman configuration file: ${pacman_conf}" @@ -147,132 +165,455 @@ _show_config() { # Cleanup airootfs _cleanup_pacstrap_dir() { + local _images=("initramfs-*img" "vmlinuz-*" "${ucodes[@]}") + local _root="${pacstrap_dir}" + local _boot="${_root}/boot" + local _log="${pacstrap_dir}/var/log" + local _machine_id="${pacstrap_dir}/etc/machine-id" + local _pacman_db="${_root}/var/lib/pacman" + local _pacman_cache="${_root}/var/cache/pacman/pkg" + local _tmp="${pacstrap_dir}/var/tmp" + local _cp_opts=('-af' '--no-preserve=ownership,mode') _msg_info "Cleaning up in pacstrap location..." - # Delete all files in /boot - [[ -d "${pacstrap_dir}/boot" ]] && find "${pacstrap_dir}/boot" -mindepth 1 -delete + # Move kernel, initramfs and microcodes for later usage + install -d -m 0755 "${work_dir}/boot" + for _query in "${_images[@]}"; do + find "${_boot}" -iname "${_query}" -exec cp "${_cp_opts[@]}" {} "${work_dir}/boot" \; + done + [[ -d "${_boot}" ]] && find "${_boot}" -maxdepth 1 -type f -delete # Delete pacman database sync cache files (*.tar.gz) - [[ -d "${pacstrap_dir}/var/lib/pacman" ]] && find "${pacstrap_dir}/var/lib/pacman" -maxdepth 1 -type f -delete + [[ -d "${_pacman_db}" ]] && find "${_pacman_db}" -maxdepth 1 -type f -delete # Delete pacman database sync cache - [[ -d "${pacstrap_dir}/var/lib/pacman/sync" ]] && find "${pacstrap_dir}/var/lib/pacman/sync" -delete - # Delete pacman package cache - [[ -d "${pacstrap_dir}/var/cache/pacman/pkg" ]] && find "${pacstrap_dir}/var/cache/pacman/pkg" -type f -delete + [[ -d "${_pacman_db}/sync" ]] && find "${_pacman_db}/sync" -delete + # Delete pacman cache files + [[ -d "${_pacman_cache}" ]] && find "${_pacman_cache}" -type f -delete # Delete all log files, keeps empty dirs. - [[ -d "${pacstrap_dir}/var/log" ]] && find "${pacstrap_dir}/var/log" -type f -delete + [[ -d "${_log}" ]] && find "${_log}" -type f -delete # Delete all temporary files and dirs - [[ -d "${pacstrap_dir}/var/tmp" ]] && find "${pacstrap_dir}/var/tmp" -mindepth 1 -delete + [[ -d "${_tmp}" ]] && find "${_tmp}" -mindepth 1 -delete # Delete package pacman related files. find "${work_dir}" \( -name '*.pacnew' -o -name '*.pacsave' -o -name '*.pacorig' \) -delete - # Create an empty /etc/machine-id - rm -f -- "${pacstrap_dir}/etc/machine-id" - printf '' > "${pacstrap_dir}/etc/machine-id" - + if [[ "${persistent_size_kib}" != "" ]]; then + dbus-uuidgen --ensure="${_machine_id}" + else + # Create an empty /etc/machine-id + rm -f -- "${_machine_id}" + printf '' > "${_machine_id}" + fi _msg_info "Done!" } -# Create a squashfs image and place it in the ISO 9660 file system. -# $@: options to pass to mksquashfs +# Create a squashfs image from a file system image or directory. _run_mksquashfs() { - local mksquashfs_options=() image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" - rm -f -- "${image_path}" + local _directory_or_fs="${1}" + local _image_path="${2}" + local mksquashfs_options=("${_mkfs_options[@]}") [[ ! "${quiet}" == "y" ]] || mksquashfs_options+=('-no-progress' '-quiet') - mksquashfs "$@" "${image_path}" -noappend "${airootfs_image_tool_options[@]}" "${mksquashfs_options[@]}" + _msg_info "Creating SQUASHFS image, this may take some time..." + mksquashfs "${_directory_or_fs}" "${_image_path}" -noappend "${mksquashfs_options[@]}" +} + +# Create an ext4 image of given size (in KB) from a directory. +_run_mkext4() { + local _dir="${1}" + local _image_path="${1}.img" + local _size="${2}" + local _epoch="${3}" + local _label="${4}" + local _writable="${5}" + local ext4_hash_seed _fsuuid mkfs_ext4_options=() + _fsuuid="$(_epoch_to_uuid "${_epoch}")" + + _msg_info "Creating ext4 image" + _msg_info "Size: ${_size} KB" + _msg_info "Directory: ${_dir}" + _msg_info "Image path: ${_image_path}" + _msg_info "UUID: ${_fsuuid}" + _msg_info "Label: ${_label}" + _msg_info "this may take a while..." + + ext4_hash_seed="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 \ + --name "${_epoch} ext4 hash seed")" + mkfs_ext4_options=('-d' "${_dir}" + '-O' '^has_journal,^resize_inode' + '-E' "lazy_itable_init=0,root_owner=0:0,hash_seed=${ext4_hash_seed}" + '-m' '0' + '-F' + '-U' 'clear') + [[ "${_label}" != "" ]] && mkfs_ext4_options+=('-L' "${_label}") + [[ ! "${quiet}" == "y" ]] || mkfs_ext4_options+=('-q') + rm -f -- "${_image_path}" + E2FSPROGS_FAKE_TIME="${_epoch}" mkfs.ext4 "${mkfs_ext4_options[@]}" -- "${_image_path}" "${_size}K" + tune2fs -c 0 -i 0 -- "${_image_path}" > /dev/null + if [ "${_writable}" != "true" ]; then + tunefs -O read-only "${_image_path}" + fi + _msg_info "Done!" +} + +# Create an EROFS image given a directory. +_run_mkerofs() { + local _image_path="${1}" + local _dir="${2}" + local _epoch="${3}" + local fsuuid + [[ ! "${quiet}" == "y" ]] || mkfs_erofs_options+=('--quiet') + _msg_info "Creating EROFS image" + _msg_info "Directory: ${_dir}" + _msg_info "Image path: ${_image_path}" + _msg_info "UUID: ${fsuuid}" + _msg_info "this may take a while..." + fsuuid="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 --name "${_epoch}")" + mkfs_erofs_options+=('-U' "${fsuuid}" "${_mkfs_options[@]}") + mkfs.erofs "${mkfs_erofs_options[@]}" -- "${_image_path}" "${_dir}" + _msg_info "Done!" +} + +# Create and open a LUKS image of the size of the pacstrap directory plus 200MB. +_run_mkluks() { + local _encryption_key + local _image_path="${1}" + local _size="${2}" + local _encryption_key="${3}" + local _epoch="${4}" + local _label="${5}" + local _writable="${6}" + local _activation_opts=() _format_opts=() _key_msg="" _mapper + local _cryptsetup_opts=('--type' 'luks2') + _mapper=$(basename "${_image_path}")".map" + image_device="/dev/mapper/${_mapper}" + _key_opts=() + _fsuuid="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 --name "${_epoch}")" + + if [[ "${_encryption_key}" != "" ]]; then + _key_opts=("--key-file=${_encryption_key}") + _cryptsetup_opts+=("${_key_opts[@]}") + _key_msg="with key $(basename "${_encryption_key}")" + fi + + _activation_opts+=("${_cryptsetup_opts[@]}") + _format_opts+=("${_cryptsetup_opts[@]}" \ + '--integrity' 'hmac-sha512' \ + '--sector-size' '4096' \ + '--key-size' '512' \ + '--pbkdf-memory' 256) + + if [ "${_writable}" != "true" ]; then + _msg_info "Integrity journal disabled" + _activation_opts+=('--persistent' \ + '--integrity-no-journal' \ + '--key-size' '512') + fi + + _msg_info "Creating LUKS image $(basename "${_image_path}") with cryptsetup (${_size}KB) ${_key_msg}" + fallocate -l "${_size}K" "${_image_path}" + while ! eval "cryptsetup -q -y luksFormat ${_format_opts[*]} ${_image_path}"; do + sleep 1 + done + + _msg_info "Setting label ${_label}" + while ! eval "cryptsetup config ${_cryptsetup_opts[*]} ${_image_path} --label ${_label}"; do + _close_luks_device "${image_device}" + done + + _msg_info "Setting UUID ${_fsuuid}" + while ! eval "cryptsetup -q -y luksUUID --uuid ${_fsuuid} ${_image_path}"; do + _close_luks_device "${image_device}" + done + + _close_luks_device "${image_device}" + + _msg_info "Opening device on mapper ${_mapper}" + while ! eval "cryptsetup ${_activation_opts[*]} open ${_image_path} ${_mapper}"; do + _close_luks_device "${image_device}" + done + _msg_info "Done!" +} + +# Close a LUKS device mapper +_close_luks_device() { + local _device="${1}" + local _mapper + _mapper=$(basename "${_device}") + blockdev --flushbufs "${_device}" || true + cryptsetup luksClose "${_mapper}" || true + if [ -e "${_device}" ]; then + dmsetup remove "${_device}" || true + fi + sync +} + +# Ask the user for a passphrase if not specified +_mkluks_common() { + local _out="${work_dir}/${iso_label}.key" + if [ "${encryption_key}" = "" ]; then + echo -n "Airootfs password:" + read -rs password + echo "${password}" > "${_out}" + encryption_key="${_out}" + fi +} + +# Steps shared by _mkairootfs_fs_type functions +_mkairootfs_common() { + [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 + install -d -m 0755 -- "${airootfs_img_dir}" + image_path="${airootfs_img_dir}/airootfs."$(_get_fs_ext "airootfs") + rm -f -- "${image_path}" + _mkfs_options=("${airootfs_image_tool_options[@]}") } # Create an ext4 image containing the root file system and pack it inside a squashfs image. # Save the squashfs image on the ISO 9660 file system. _mkairootfs_ext4+squashfs() { - local ext4_hash_seed mkfs_ext4_options=() - [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 - - _msg_info "Creating ext4 image of 32 GiB and copying '${pacstrap_dir}/' to it..." - - ext4_hash_seed="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 \ - --name "${SOURCE_DATE_EPOCH} ext4 hash seed")" - mkfs_ext4_options=( - '-d' "${pacstrap_dir}" - '-O' '^has_journal,^resize_inode' - '-E' "lazy_itable_init=0,root_owner=0:0,hash_seed=${ext4_hash_seed}" - '-m' '0' - '-F' - '-U' 'clear' - ) - [[ ! "${quiet}" == "y" ]] || mkfs_ext4_options+=('-q') - rm -f -- "${pacstrap_dir}.img" - E2FSPROGS_FAKE_TIME="${SOURCE_DATE_EPOCH}" mkfs.ext4 "${mkfs_ext4_options[@]}" -- "${pacstrap_dir}.img" 32G - tune2fs -c 0 -i 0 -- "${pacstrap_dir}.img" > /dev/null + _mkairootfs_common + _run_mkext4 "${pacstrap_dir}" "$(_get_internal_size "${airootfs_size}")" \ + "${SOURCE_DATE_EPOCH}" "airootfs" + _run_mksquashfs "${pacstrap_dir}.img" "${image_path}" _msg_info "Done!" + rm -- "${pacstrap_dir}.img" +} - install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" - _msg_info "Creating SquashFS image, this may take some time..." - _run_mksquashfs "${pacstrap_dir}.img" +# Create an ext4 image containing the root file system and pack it inside a squashfs image. +# Pack the squash image inside the LUKS image and save it on the ISO 9660 file system. +_mkairootfs_ext4+squashfs+luks() { + _mkairootfs_common + _mkluks_common + _run_mkluks "${image_path}" "${airootfs_size}" "${encryption_key}" \ + "${SOURCE_DATE_EPOCH}" "${iso_label}" + _run_mkext4 "${pacstrap_dir}" "$(_get_internal_size "${airootfs_size}")" \ + "${SOURCE_DATE_EPOCH}" "airootfs" + _run_mksquashfs "${pacstrap_dir}.img" "${image_device}" + sync + _close_luks_device "${image_device}" _msg_info "Done!" rm -- "${pacstrap_dir}.img" } # Create a squashfs image containing the root file system and saves it on the ISO 9660 file system. _mkairootfs_squashfs() { - [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 + _mkairootfs_common + _run_mksquashfs "${pacstrap_dir}" "${image_path}" +} - install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" - _msg_info "Creating SquashFS image, this may take some time..." - _run_mksquashfs "${pacstrap_dir}" +# Create a squashfs image containing the root file system and saves it on the LUKS image. +# Saves the LUKS image on the ISO 9660 file system. +_mkairootfs_squashfs+luks() { + _mkairootfs_common + _mkluks_common + _run_mkluks "${image_path}" "${airootfs_size}" "${encryption_key}" \ + "${SOURCE_DATE_EPOCH}" "${iso_label}" + _run_mksquashfs "${pacstrap_dir}" "${image_device}" + sync + _close_luks_device "${image_device}" } # Create an EROFS image containing the root file system and saves it on the ISO 9660 file system. _mkairootfs_erofs() { - local fsuuid mkfs_erofs_options=() - [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1 + _mkairootfs_common + _run_mkerofs "${image_path}" "${pacstrap_dir}" "${SOURCE_DATE_EPOCH}" + _msg_info "Done!" +} - install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}" - local image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" +# Create an EROFS image containing the root file system and saves it on the LUKS image. +# Save the LUKS image on the ISO 9660 file system. +_mkairootfs_erofs+luks() { + _mkairootfs_common + _mkluks_common + _run_mkluks "${image_path}" "${airootfs_size}" "${encryption_key}" \ + "${SOURCE_DATE_EPOCH}" "${iso_label}" + _run_mkerofs "${image_device}" "${pacstrap_dir}" "${SOURCE_DATE_EPOCH}" + sync + _close_luks_device "${image_device}" +} + +# Steps shared by _mkkeys+fs_type functions +_mkkeys_common() { + image_path="${dongle_isofs_dir}/keys."$(_get_fs_ext "keys") rm -f -- "${image_path}" - [[ ! "${quiet}" == "y" ]] || mkfs_erofs_options+=('--quiet') - # Generate reproducible file system UUID from SOURCE_DATE_EPOCH - fsuuid="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 --name "${SOURCE_DATE_EPOCH}")" - mkfs_erofs_options+=('-U' "${fsuuid}" "${airootfs_image_tool_options[@]}") - _msg_info "Creating EROFS image, this may take some time..." - mkfs.erofs "${mkfs_erofs_options[@]}" -- "${image_path}" "${pacstrap_dir}" + _mkfs_options=("${keys_image_tool_options[@]}") + keys_epoch=$((SOURCE_DATE_EPOCH + 42 * 69)) +} + +# Create an ext4 image containing the keys file system and pack it inside a squashfs image. +# Save the squashfs image on the ISO 9660 file system. +_mkkeys_ext4+squashfs() { + _mkkeys_common + _run_mkext4 "${keys_dir}" "$(_get_internal_size "${keys_size}")" \ + "${keys_epoch}" "keys" + _run_mksquashfs "${keys_dir}.img" "${image_path}" + _msg_info "Done!" + rm -- "${keys_dir}.img" +} + +# Create an ext4 image containing the keys file system and pack it inside a squashfs image. +# Pack the squash image inside the LUKS image and save it on the ISO 9660 file system. +_mkkeys_ext4+squashfs+luks() { + _mkkeys_common + _run_mkluks "${image_path}" "${keys_size}" "" \ + "${keys_epoch}" "${iso_label}_KEYS" + _run_mkext4 "${keys_dir}" "$(_get_internal_size "${keys_size}")" \ + "${keys_epoch}" "keys" + _run_mksquashfs "${keys_dir}.img" "${image_device}" + sync + _close_luks_device "${image_device}" + _msg_info "Done!" + rm -- "${keys_dir}.img" +} + +# Create a squashfs image containing the keys file system and saves it on the LUKS image. +# Saves the LUKS image on the ISO 9660 file system. +_mkkeys_squashfs+luks() { + _mkkeys_common + _run_mkluks "${image_path}" "${airootfs_size}" "" \ + "${keys_epoch}" "${iso_label}_KEYS" + _run_mksquashfs "${keys_dir}" "${image_device}" + sync + _close_luks_device "${image_device}" +} + +# Create a squashfs image containing the root file system and saves it on the ISO 9660 file system. +_mkkeys_squashfs() { + _mkkeys_common + _run_mksquashfs "${keys_dir}" "${image_path}" +} + +# Create an EROFS image containing the keys file system and saves it on the ISO 9660 file system. +_mkkeys_erofs() { + _mkkeys_common + _run_mkerofs "${image_path}" "${keys_dir}" "${keys_epoch}" + _msg_info "Done!" +} + +# Create an EROFS image containing the keys file system and saves it on the LUKS image. +# Save the LUKS image on the ISO 9660 file system. +_mkkeys_erofs+luks() { + _mkkeys_common + _run_mkluks "${image_path}" "${keys_size}" \ + "${keys_epoch}" "${iso_label}_KEYS" + _run_mkerofs "${image_device}" "${keys_dir}" "${keys_epoch}" + sync + _close_luks_device "${image_device}" +} + +# Steps shared by _mkpersistent+fs_type functions +_mkpersistent_common() { + image_path="${persistentimg}" + rm -f -- "${image_path}" + persistent_epoch=$((SOURCE_DATE_EPOCH + 3 * 1415)) + writable="true" +} + +# Create an ext4 image to be used as the persistent ISO partition. +_mkpersistent_ext4() { + _mkpersistent_common + persistent_guid="0FC63DAF-8483-4772-8E79-3D69D8477DE4" + _run_mkext4 "${persistent_dir}" "${persistent_size_kib}" \ + "${persistent_epoch}" "${iso_label}_PERSISTENT" "${writable}" + mv "${persistent_dir}.img" "${image_path}" + sync _msg_info "Done!" } -# Create checksum file for the rootfs image. +# Create an ext4 fs inside a LUKS container to be used as the persistent ISO partition. +_mkpersistent_ext4+luks() { + _mkpersistent_common + persistent_guid="CA7D7CCB-63ED-4C53-861C-1742536059CC" + _run_mkluks "${image_path}" "${persistent_size_kib}" "${encryption_key}" \ + "${persistent_epoch}" "${iso_label}_PERSISTENT" "${writable}" + _run_mkext4 "${persistent_dir}" "$(_get_internal_size "${persistent_size_kib}")" \ + "${persistent_epoch}" "persistent" "${writable}" + dd if="${persistent_dir}.img" of="${image_device}" + sync + _close_luks_device "${image_device}" + _msg_info "Done!" + rm -- "${persistent_dir}.img" +} + +# Create checksum for a given file. _mkchecksum() { - _msg_info "Creating checksum file for self-test..." - cd -- "${isofs_dir}/${install_dir}/${arch}" - if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then - sha512sum airootfs.sfs > airootfs.sha512 - elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then - sha512sum airootfs.erofs > airootfs.sha512 + local _file + local _dir + local _name + _file="${1}" + _dir=$(dirname "${_file}") + _name=$(basename "${_file%.*}") + + cd -- "${_dir}" + if [[ -e "${_file}" ]]; then + _msg_info "Creating checksum of ${_file} for self-test..." + sha512sum "$(basename "${_file}")" > "${_name}.sha512" fi cd -- "${OLDPWD}" - _msg_info "Done!" } -# GPG sign the root file system image. +# GPG sign a file. _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 - rm -f -- "${airootfs_image_filename}.sig" + local _file="${1}" + local gpg_options=() + rm -f -- "${_file}.sig" # Add gpg sender option if the value is provided [[ -z "${gpg_sender}" ]] || gpg_options+=('--sender' "${gpg_sender}") - # always use the .sig file extension, as that is what mkinitcpio-archiso's hooks expect - gpg --batch --no-armor --no-include-key-block --output "${airootfs_image_filename}.sig" --detach-sign \ - --default-key "${gpg_key}" "${gpg_options[@]}" "${airootfs_image_filename}" + if [ -e "${_file}" ]; then + _msg_info "Signing $(basename "${_file}")..." + # always use the .sig file extension, as that is what + # mkinitcpio-archiso's hooks expect + _msg_info "GPG home: ${gpg_home}" + GNUPGHOME="${gpg_home}" gpg --batch --no-armor --no-include-key-block \ + --output "${_file}.sig" --detach-sign \ + --homedir "${gpg_home}" \ + --default-key "${gpg_key}" "${gpg_options[@]}" "${_file}" + fi _msg_info "Done!" } +# Get image extension. +_get_fs_ext() { + local _image="${1}" + local _fs_type + _fs_type=$(_get_fs_type "${_image}") + if [ "${_fs_type}" = "squashfs" ]; then + echo "sfs" + else + echo "${_fs_type}" + fi +} + +# Get image extension. +_get_fs_type() { + local _image="${1}" + local _no_luks + _no_luks=$(eval echo \$"{${_image}_image_type%%+luks}") + echo "${_no_luks##*"+"}" +} + +_get_internal_size() { + local _size="${1}" + if [[ "${_size}" -lt 50000 ]]; then + ratio=70 + elif [[ "${_size}" -gt 50000 ]] && [[ "${_size}" -lt 200000 ]]; then + ratio=75 + elif [[ "${_size}" -gt 200000 ]] && [[ "${_size}" -lt 1000000 ]]; then + ratio=80 + elif [[ "${_size}" -gt 200000 ]] && [[ "${_size}" -lt 5000000 ]]; then + ratio=80 + else + ratio=85 + fi + echo $(((_size * ratio)/100)) +} + # Helper function to run functions only one time. # $1: function name _run_once() { if [[ ! -e "${work_dir}/${run_once_mode}.${1}" ]]; then "$1" touch "${work_dir}/${run_once_mode}.${1}" + else + if [ "${quiet}" != "y" ]; then + _msg_info "Command ${1} already run" + fi fi } @@ -298,7 +639,7 @@ _make_pacman_conf() { # see `man 8 pacman` for further info pacman-conf --config "${pacman_conf}" | \ sed "/CacheDir/d;/DBPath/d;/HookDir/d;/LogFile/d;/RootDir/d;/\[options\]/a CacheDir = ${_cache_dirs} - /\[options\]/a HookDir = ${pacstrap_dir}/etc/pacman.d/hooks/" > "${work_dir}/${buildmode}.pacman.conf" + /\[options\]/a HookDir = ${pacstrap_dir}/etc/pacman.d/hooks/" > "${work_dir}/${buildmode}.pacman.conf" } # Prepare working directory and copy custom root file system files. @@ -309,6 +650,7 @@ _make_custom_airootfs() { install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}" if [[ -d "${profile}/airootfs" ]]; then + _build_archiso_hooks _msg_info "Copying custom airootfs files..." cp -af --no-preserve=ownership,mode -- "${profile}/airootfs/." "${pacstrap_dir}" # Set ownership and mode for files and directories @@ -397,103 +739,202 @@ _make_customize_airootfs() { } # Set up boot loaders -_make_bootmodes() { +_make_bootmodes_iso() { + local bootmode + for bootmode in "${bootmodes[@]}"; do + _run_once "_make_bootmode_${bootmode}_iso" + done +} + +# Set up boot loaders +_make_bootmodes_dongle() { local bootmode for bootmode in "${bootmodes[@]}"; do - _run_once "_make_bootmode_${bootmode}" + _run_once "_make_bootmode_${bootmode}_dongle" done } # Copy kernel and initramfs to ISO 9660 _make_boot_on_iso9660() { - local ucode_image - _msg_info "Preparing kernel and initramfs for the ISO 9660 file system..." - install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/${arch}" - install -m 0644 -- "${pacstrap_dir}/boot/initramfs-"*".img" "${isofs_dir}/${install_dir}/boot/${arch}/" - install -m 0644 -- "${pacstrap_dir}/boot/vmlinuz-"* "${isofs_dir}/${install_dir}/boot/${arch}/" + isofs_dir="${work_dir}/iso" + _make_boot_on_iso "${isofs_dir}" +} + +# Copy kernel and initramfs to dongle ISO 9660 +_make_boot_on_dongle() { + dongle_isofs_dir="${work_dir}/dongle_iso" + _make_boot_on_iso "${dongle_isofs_dir}" +} + +# Copy kernel and initramfs to ISO 9660 +_make_boot_on_iso() { + local bootable_dir="${1}" + local _query _src ucode_image + local _cp_opts=('-af' '--no-preserve=ownership,mode') + local boot_dir="${bootable_dir}/${install_dir}/boot" + local kernel_dir="${bootable_dir}/${install_dir}/boot/${arch}" + local licenses_src="${pacstrap_dir}/usr/share/licenses" + local licenses_dest="${boot_dir}/licenses" + local images=("initramfs-*.img" "vmlinuz-*") + _msg_info "Preparing kernel and initramfs for the ISO 9660 file system in ${bootable_dir}..." + + install -d -m 0755 -- "${kernel_dir}" + for _query in "${images[@]}"; do + find "${work_dir}" -iname "${_query}" -exec cp "${_cp_opts[@]}" {} "${kernel_dir}" \; + find "${kernel_dir}" -iname "${_query}" -exec chmod 0644 {} \; + done for ucode_image in "${ucodes[@]}"; do - if [[ -e "${pacstrap_dir}/boot/${ucode_image}" ]]; then - install -m 0644 -- "${pacstrap_dir}/boot/${ucode_image}" "${isofs_dir}/${install_dir}/boot/" - if [[ -e "${pacstrap_dir}/usr/share/licenses/${ucode_image%.*}/" ]]; then - install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/${ucode_image%.*}/" - install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/${ucode_image%.*}/"* \ - "${isofs_dir}/${install_dir}/boot/licenses/${ucode_image%.*}/" - fi + find "${work_dir}" -iname "${ucode_image}" -exec cp "${_cp_opts[@]}" {} "${boot_dir}" \; + find "${boot_dir}" -iname "${_query}" -exec chmod 0644 {} \; + if [[ -e "${licenses_src}/${ucode_image%.*}/" ]]; then + install -d -m 0755 -- "${licenses_dest}/${ucode_image%.*}/" + install -m 0644 -- "${licenses_src}/${ucode_image%.*}/"* "${licenses_dest}/${ucode_image%.*}/" fi done _msg_info "Done!" } +_build_archiso_hooks() { + local _hooks=() _mkinitcpio_conf="${profile}/airootfs/etc/mkinitcpio.conf" + if [[ "${airootfs_image_type}" == *luks ]] || [[ " ${buildmodes[*]} " =~ ' dongle ' ]]; then + _hooks+=("encrypt") + fi + _hooks+=("archiso") + + cp "${_mkinitcpio_conf}" "${work_dir}/mkinitcpio.conf" + sed "s|%ARCHISO_HOOKS%|${_hooks[*]}|g" "${work_dir}/mkinitcpio.conf" > "${_mkinitcpio_conf}" +} + +_get_dongle_uuid() { + #shellcheck disable=SC2005 + echo "$(_epoch_to_uuid $((SOURCE_DATE_EPOCH + 42 * 69)))" +} + +_get_archiso_uuid() { + #shellcheck disable=SC2005 + echo "$(_epoch_to_uuid "${SOURCE_DATE_EPOCH}")" +} + +# Produce kernel parameters. +_get_kernel_params() { + local _kparams=() + _kparams+=("archisobasedir=${install_dir}" + "archisolabel=${iso_label}" + "archisouuid=$(_get_archiso_uuid)" + "$(_get_crypto_params)") + if [[ " ${buildmodes[*]} " =~ ' dongle ' ]]; then + _kparams+=("sigdevice=UUID=$(_get_dongle_uuid):iso9660:$(_get_airootfs_path).sig" + "verify=y") + fi + echo "${_kparams[@]}" +} + +# Produce the 'encrypt' hook's kernel parameters needed to boot an encrypted ISO. +_get_crypto_params() { + declare -a _cparams + local _keys_fs_type _keys_path + _keys_fs_type="$(_get_fs_type "keys")" + _keys_path="keys.$(_get_fs_ext "keys")" + _cparams=() + if [[ "${airootfs_image_type}" == *luks ]]; then + _cparams+=("root=/dev/mapper/root" + "cryptdevice=UUID=$(_get_archiso_uuid),$(_get_airootfs_path):root:readonly") + if [ "${encryption_key}" != "" ]; then + _cparams+=("cryptkey=UUID=$(_get_dongle_uuid):iso9660,${_keys_fs_type}:${_keys_path},airootfs.key") + fi + fi + echo "${_cparams[@]}" +} + # Prepare syslinux for booting from MBR (isohybrid) _make_bootmode_bios.syslinux.mbr() { + bootable_dir="${1}" + bootable="${2}" _msg_info "Setting up SYSLINUX for BIOS booting from a disk..." - install -d -m 0755 -- "${isofs_dir}/syslinux" + install -d -m 0755 -- "${bootable_dir}/syslinux" for _cfg in "${profile}/syslinux/"*.cfg; do - sed "s|%ARCHISO_LABEL%|${iso_label}|g; - s|%INSTALL_DIR%|${install_dir}|g; - s|%ARCH%|${arch}|g" \ - "${_cfg}" > "${isofs_dir}/syslinux/${_cfg##*/}" + _build_bootloader_config "${_cfg}" > "${bootable_dir}/syslinux/${_cfg##*/}" done if [[ -e "${profile}/syslinux/splash.png" ]]; then - install -m 0644 -- "${profile}/syslinux/splash.png" "${isofs_dir}/syslinux/" + install -m 0644 -- "${profile}/syslinux/splash.png" "${bootable_dir}/syslinux/" fi - install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/"*.c32 "${isofs_dir}/syslinux/" - install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${isofs_dir}/syslinux/" - install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/memdisk" "${isofs_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/"*.c32 "${bootable_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${bootable_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/memdisk" "${bootable_dir}/syslinux/" - _run_once _make_boot_on_iso9660 + if [[ "${bootable}" == "iso" ]]; then + _run_once _make_boot_on_iso9660 + elif [[ "${bootable}" == "dongle" ]]; then + _run_once _make_boot_on_dongle + fi - if [[ -e "${isofs_dir}/syslinux/hdt.c32" ]]; then - install -d -m 0755 -- "${isofs_dir}/syslinux/hdt" + if [[ -e "${bootable_dir}/syslinux/hdt.c32" ]]; then + install -d -m 0755 -- "${bootable_dir}/syslinux/hdt" if [[ -e "${pacstrap_dir}/usr/share/hwdata/pci.ids" ]]; then gzip -cn9 "${pacstrap_dir}/usr/share/hwdata/pci.ids" > \ - "${isofs_dir}/syslinux/hdt/pciids.gz" + "${bootable_dir}/syslinux/hdt/pciids.gz" fi find "${pacstrap_dir}/usr/lib/modules" -name 'modules.alias' -print -exec gzip -cn9 '{}' ';' -quit > \ - "${isofs_dir}/syslinux/hdt/modalias.gz" + "${bootable_dir}/syslinux/hdt/modalias.gz" fi # Add other aditional/extra files to ${install_dir}/boot/ if [[ -e "${pacstrap_dir}/boot/memtest86+/memtest.bin" ]]; then # rename for PXE: https://wiki.archlinux.org/title/Syslinux#Using_memtest - install -m 0644 -- "${pacstrap_dir}/boot/memtest86+/memtest.bin" "${isofs_dir}/${install_dir}/boot/memtest" - install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/" + install -m 0644 -- "${pacstrap_dir}/boot/memtest86+/memtest.bin" "${bootable_dir}/${install_dir}/boot/memtest" + install -d -m 0755 -- "${bootable_dir}/${install_dir}/boot/licenses/memtest86+/" install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/common/GPL2/license.txt" \ - "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/" + "${bootable_dir}/${install_dir}/boot/licenses/memtest86+/" fi _msg_info "Done! SYSLINUX set up for BIOS booting from a disk successfully." } +_make_bootmode_bios.syslinux.mbr_iso() { + _make_bootmode_bios.syslinux.mbr "${isofs_dir}" "iso" +} + +_make_bootmode_bios.syslinux.mbr_dongle() { + _make_bootmode_bios.syslinux.mbr "${dongle_isofs_dir}" "dongle" +} + # Prepare syslinux for El-Torito booting _make_bootmode_bios.syslinux.eltorito() { + local bootable_dir="${1}" _msg_info "Setting up SYSLINUX for BIOS booting from an optical disc..." - install -d -m 0755 -- "${isofs_dir}/syslinux" - install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isolinux.bin" "${isofs_dir}/syslinux/" - install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${isofs_dir}/syslinux/" + install -d -m 0755 -- "${bootable_dir}/syslinux" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isolinux.bin" "${bootable_dir}/syslinux/" + install -m 0644 -- "${pacstrap_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${bootable_dir}/syslinux/" + + _msg_info "Done! SYSLINUX set up for BIOS booting from an optical disc successfully." +} +_make_bootmode_bios.syslinux.eltorito_iso() { + _make_bootmode_bios.syslinux.eltorito "${isofs_dir}" # ISOLINUX and SYSLINUX installation is shared - _run_once _make_bootmode_bios.syslinux.mbr + _run_once _make_bootmode_bios.syslinux.mbr_iso - _msg_info "Done! SYSLINUX set up for BIOS booting from an optical disc successfully." +} + +_make_bootmode_bios.syslinux.eltorito_dongle() { + _make_bootmode_bios.syslinux.eltorito "${dongle_isofs_dir}" + # ISOLINUX and SYSLINUX installation is shared + _run_once _make_bootmode_bios.syslinux.mbr_dongle } # Copy kernel and initramfs to FAT image _make_boot_on_fat() { - local ucode_image all_ucode_images=() + local _images _ucode_image _msg_info "Preparing kernel and initramfs for the FAT file system..." - mmd -i "${efibootimg}" \ + _images=("initramfs-*.img" "vmlinuz-*") + mmd -D o -i "${efibootimg}" \ "::/${install_dir}" "::/${install_dir}/boot" "::/${install_dir}/boot/${arch}" - 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 - all_ucode_images+=("${pacstrap_dir}/boot/${ucode_image}") - fi + for _query in "${_images[@]}"; do + find "${work_dir}" -iname "${_query}" -exec mcopy -D "o" -i "${efibootimg}" {} "::/${install_dir}/boot/${arch}/" \; + done + for _ucode_image in "${ucodes[@]}"; do + find "${work_dir}" -iname "${_ucode_image}" -exec mcopy -D "o" -i "${efibootimg}" {} "::/${install_dir}/boot/" \; done - if (( ${#all_ucode_images[@]} )); then - mcopy -i "${efibootimg}" "${all_ucode_images[@]}" "::/${install_dir}/boot/" - fi _msg_info "Done!" } @@ -527,29 +968,43 @@ _make_efibootimg() { fi # Create the default/fallback boot path in which a boot loaders will be placed later. - mmd -i "${efibootimg}" ::/EFI ::/EFI/BOOT + mmd -D o -i "${efibootimg}" ::/EFI ::/EFI/BOOT } # 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/"*) + files_to_copy+=("${work_dir}/grub/"*'.cfg') if compgen -G "${profile}/grub/!(*.cfg)" &> /dev/null; then files_to_copy+=("${profile}/grub/"!(*.cfg)) fi - mcopy -i "${efibootimg}" "${files_to_copy[@]}" ::/EFI/BOOT/ + mcopy -D o -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=() +_epoch_to_uuid() { + local _epoch="${1}" + local _uuid + TZ=UTC printf -v _uuid '%(%F-%H-%M-%S-00)T' "${_epoch}" + echo "${_uuid}" +} - files_to_copy+=("${work_dir}/grub/"*) - if compgen -G "${profile}/grub/!(*.cfg)" &> /dev/null; then - files_to_copy+=("${profile}/grub/"!(*.cfg)) +_get_bootable_uuid() { + local _uuid + _uuid="$(_get_archiso_uuid)" + if [[ " ${buildmodes[*]} " =~ ' dongle ' ]]; then + _uuid=$(_get_dongle_uuid) fi - install -m 0644 -- "${files_to_copy[@]}" "${isofs_dir}/EFI/BOOT/" + echo "${_uuid}" +} + +# Fill a bootloader configuration template and copy the result in a file +_build_bootloader_config() { + local _template="${1}" + sed "s|%BOOTABLE_UUID%|$(_get_bootable_uuid)|g; + s|%ARCH%|${arch}|g; + s|%INSTALL_DIR%|${install_dir}|g; + s|%KERNEL_PARAMS%|$(_get_kernel_params)|g" \ + "${_template}" } # Prepare GRUB configuration files @@ -560,10 +1015,7 @@ _make_common_bootmode_grub_cfg(){ # 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##*/}" + _build_bootloader_config "${_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/" @@ -582,7 +1034,37 @@ EOF printf '%s\n' "$grubembedcfg" > "${work_dir}/grub-embed.cfg" } +_make_common_bootmode_grub_copy_to_isofs_iso() { + isofs_dir="${work_dir}/iso" + _make_common_bootmode_grub_copy_to_isofs "${isofs_dir}" +} + +_make_common_bootmode_grub_copy_to_isofs_dongle() { + dongle_isofs_dir="${work_dir}/dongle_iso" + _make_common_bootmode_grub_copy_to_isofs "${dongle_isofs_dir}" +} + +_make_common_bootmode_grub_copy_to_isofs() { + local isofs_dir="${1}" + local files_to_copy=() + + files_to_copy+=("${work_dir}/grub/"*'.cfg') + 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/" +} + +_get_grubmodules(){ + echo 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 +} + _make_bootmode_uefi-ia32.grub.esp() { + local bootable="${1}" local grubmodules=() # Prepare configuration files @@ -596,21 +1078,22 @@ _make_bootmode_uefi-ia32.grub.esp() { 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="${grubmodules[*]}" \ + --modules="$(_get_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 # TODO: Remove this branch. - _run_once _make_bootmode_uefi-x64.systemd-boot.esp + _run_once "_make_bootmode_uefi-x64.systemd-boot.esp_${bootable}" elif [[ " ${bootmodes[*]} " =~ uefi-x64.grub.esp ]]; then - _run_once _make_bootmode_uefi-x64.grub.esp + _run_once "_make_bootmode_uefi-x64.grub.esp_${bootable}" else efiboot_imgsize="$(du -bcs -- "${efiboot_files[@]}" 2>/dev/null | awk 'END { print $1 }')" # Create a FAT image for the EFI system partition @@ -618,23 +1101,33 @@ _make_bootmode_uefi-ia32.grub.esp() { fi # Copy GRUB EFI binary to the default/fallback boot path - mcopy -i "${efibootimg}" "${work_dir}/BOOTIA32.EFI" ::/EFI/BOOT/BOOTIA32.EFI + mcopy -D o -i "${efibootimg}" "${work_dir}/BOOTIA32.EFI" ::/EFI/BOOT/BOOTIA32.EFI # Copy GRUB files _run_once _make_common_bootmode_grub_copy_to_efibootimg if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ]]; then - mcopy -i "${efibootimg}" "${pacstrap_dir}/usr/share/edk2-shell/ia32/Shell_Full.efi" ::/shellia32.efi + mcopy -D o -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." } +_make_bootmode_uefi-ia32.grub.esp_iso() { + _make_bootmode_uefi-ia32.grub.esp "iso" +} + +_make_bootmode_uefi-ia32.grub.esp_dongle() { + _make_bootmode_uefi-ia32.grub.esp "dongle" +} + # Prepare GRUB for El Torito booting _make_bootmode_uefi-ia32.grub.eltorito() { + local bootable_dir="${1}" + local bootable="${2}" # El Torito UEFI boot requires an image containing the EFI system partition. # uefi-ia32.grub.eltorito has the same requirements as uefi-ia32.grub.esp - _run_once _make_bootmode_uefi-ia32.grub.esp + _run_once "_make_bootmode_uefi-ia32.grub.esp_${bootable}" # Prepare configuration files _run_once _make_common_bootmode_grub_cfg @@ -643,22 +1136,30 @@ _make_bootmode_uefi-ia32.grub.eltorito() { # 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" + install -d -m 0755 -- "${bootable_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" "${bootable_dir}/EFI/BOOT/BOOTIA32.EFI" # Copy GRUB configuration files - _run_once _make_common_bootmode_grub_copy_to_isofs + _run_once "_make_common_bootmode_grub_copy_to_isofs_${bootable}" # edk2-shell based UEFI shell 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" "${bootable_dir}/shellia32.efi" fi _msg_info "Done!" } +_make_bootmode_uefi-ia32.grub.eltorito_iso() { + _make_bootmode_uefi-ia32.grub.eltorito "${isofs_dir}" "iso" +} + +_make_bootmode_uefi-ia32.grub.eltorito_dongle() { + _make_bootmode_uefi-ia32.grub.eltorito "${dongle_isofs_dir}" "dongle" +} + _make_bootmode_uefi-x64.grub.esp() { local grubmodules=() @@ -689,23 +1190,35 @@ _make_bootmode_uefi-x64.grub.esp() { _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 + mcopy -D o -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 + mcopy -D o -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." } +_make_bootmode_uefi-x64.grub.esp_iso() { + _make_bootmode_uefi-x64.grub.esp +} + +_make_bootmode_uefi-x64.grub.esp_dongle() { + _make_bootmode_uefi-x64.grub.esp +} + # Prepare GRUB for El Torito booting _make_bootmode_uefi-x64.grub.eltorito() { + local bootable_dir="${1}" + local bootable="${2}" # 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 + _run_once "_make_bootmode_uefi-x64.grub.esp_${bootable}" # Prepare configuration files _run_once _make_common_bootmode_grub_cfg @@ -714,22 +1227,31 @@ _make_bootmode_uefi-x64.grub.eltorito() { # 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" + install -d -m 0755 -- "${bootable_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" + install -m 0644 -- "${work_dir}/BOOTx64.EFI" \ + "${bootable_dir}/EFI/BOOT/BOOTx64.EFI" # Copy GRUB files - _run_once _make_common_bootmode_grub_copy_to_isofs + _run_once "_make_common_bootmode_grub_copy_to_isofs_${bootable}" # 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" + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${bootable_dir}/shellx64.efi" fi _msg_info "Done!" } +_make_bootmode_uefi-x64.grub.eltorito_iso() { + _make_bootmode_uefi-x64.grub.eltorito "${isofs_dir}" "iso" +} + +_make_bootmode_uefi-x64.grub.eltorito_dongle() { + _make_bootmode_uefi-x64.grub.eltorito "${dongle_isofs_dir}" "dongle" +} + # Prepare systemd-boot for booting when written to a disk (isohybrid) _make_bootmode_uefi-x64.systemd-boot.esp() { local _file efiboot_imgsize @@ -754,22 +1276,19 @@ _make_bootmode_uefi-x64.systemd-boot.esp() { _make_efibootimg "$efiboot_imgsize" # Copy systemd-boot EFI binary to the default/fallback boot path - mcopy -i "${efibootimg}" \ + mcopy -D o -i "${efibootimg}" \ "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI # Copy systemd-boot configuration files - mmd -i "${efibootimg}" ::/loader ::/loader/entries - mcopy -i "${efibootimg}" "${profile}/efiboot/loader/loader.conf" ::/loader/ + mmd -D o -i "${efibootimg}" ::/loader ::/loader/entries + mcopy -D o -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 "${efibootimg}" - "::/loader/entries/${_conf##*/}" - done + _build_bootloader_config "${_conf}" | mcopy -D o -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 "${efibootimg}" \ + mcopy -D o -i "${efibootimg}" \ "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi fi @@ -780,41 +1299,58 @@ _make_bootmode_uefi-x64.systemd-boot.esp() { _msg_info "Done! systemd-boot set up for UEFI booting successfully." } +_make_bootmode_uefi-x64.systemd-boot.esp_iso() { + _make_bootmode_uefi-x64.systemd-boot.esp +} + +_make_bootmode_uefi-x64.systemd-boot.esp_dongle() { + _make_bootmode_uefi-x64.systemd-boot.esp +} + # Prepare systemd-boot for El Torito booting _make_bootmode_uefi-x64.systemd-boot.eltorito() { + local bootable_dir="${1}" + local bootable="${2}" # 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 + _run_once "_make_bootmode_uefi-x64.systemd-boot.esp_${bootable}" # 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" + install -d -m 0755 -- "${bootable_dir}/EFI/BOOT" # Copy systemd-boot EFI binary to the default/fallback boot path install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \ - "${isofs_dir}/EFI/BOOT/BOOTx64.EFI" + "${bootable_dir}/EFI/BOOT/BOOTx64.EFI" # Copy systemd-boot configuration files - install -d -m 0755 -- "${isofs_dir}/loader/entries" - install -m 0644 -- "${profile}/efiboot/loader/loader.conf" "${isofs_dir}/loader/" + install -d -m 0755 -- "${bootable_dir}/loader/entries" + install -m 0644 -- "${profile}/efiboot/loader/loader.conf" "${bootable_dir}/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}" > "${isofs_dir}/loader/entries/${_conf##*/}" - done + _build_bootloader_config "${_conf}" > "${bootable_dir}/loader/entries/${_conf##*/}" + done # edk2-shell based UEFI shell # shellx64.efi is picked up automatically when on / 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" + install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${bootable_dir}/shellx64.efi" fi _msg_info "Done!" } +# Prepare systemd-boot for El Torito booting +_make_bootmode_uefi-x64.systemd-boot.eltorito_iso() { + _make_bootmode_uefi-x64.systemd-boot.eltorito "${isofs_dir}" "iso" +} + +# Prepare systemd-boot for El Torito booting +_make_bootmode_uefi-x64.systemd-boot.eltorito_dongle() { + _make_bootmode_uefi-x64.systemd-boot.eltorito "${dongle_isofs_dir}" "dongle" +} + _validate_requirements_bootmode_bios.syslinux.mbr() { # bios.syslinux.mbr requires bios.syslinux.eltorito # shellcheck disable=SC2076 @@ -947,7 +1483,7 @@ _validate_requirements_bootmode_uefi-x64.grub.esp() { _msg_error "Validating '${bootmode}': grub-install is not available on this host. Install 'grub'!" 0 fi - # Check if mkfs.fat is available + # 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 @@ -994,12 +1530,57 @@ _validate_requirements_bootmode_uefi-x64.grub.eltorito() { _validate_requirements_bootmode_uefi-x64.grub.esp } +_get_airootfs_path(){ + echo "${install_dir}/${arch}/airootfs.$(_get_fs_ext "airootfs")" +} + +_get_airootfs_img(){ + echo "${airootfs_img_dir}/airootfs.$(_get_fs_ext "airootfs")" +} + # Build airootfs filesystem image _prepare_airootfs_image() { + local _sig_dir airootfs_size pacstrap_size + + pacstrap_size=$(du -s "${pacstrap_dir}" | cut -f 1) + airootfs_size=$((pacstrap_size+200000)) + _run_once "_mkairootfs_${airootfs_image_type}" - _mkchecksum + _mkchecksum "$(_get_airootfs_img)" if [[ -n "${gpg_key}" ]]; then - _mksignature + _mksignature "$(_get_airootfs_img)" + if [[ " ${buildmodes[*]} " =~ ' dongle ' ]]; then + dongle_isofs_dir="${work_dir}/dongle_iso" + _sig_dir="${dongle_isofs_dir}/${install_dir}/${arch}" + install -d -m711 "${_sig_dir}" + cp "$(_get_airootfs_img).sig" "${_sig_dir}" + fi + fi +} + +# Build keys filesystem image +_prepare_keys_image() { + keys_size=25000 + _run_once "_mkkeys_${keys_image_type}" + + _mkchecksum "${dongle_isofs_dir}/keys.$(_get_fs_ext "keys")" + if [[ -n "${gpg_key}" ]]; then + _mksignature "${dongle_isofs_dir}/keys.$(_get_fs_ext "keys")" + fi +} + +# Build persistent filesystem image +_prepare_persistent_image() { + local persistent_dir_size + + if [ -d "${profile}/persistent" ]; then + cp -af --no-preserve=ownership,mode -- "${profile}/persistent/." "${persistent_dir}" + persistent_dir_size=$(du -s "${persistent_dir}" | cut -f 1) + persistent_size_kib=$(( persistent_dir_size > persistent_size_kib ? persistent_dir_size : persistent_size_kib )) + fi + + if [ "${persistent_size_kib}" != "" ]; then + _run_once "_mkpersistent_${persistent_image_type}" fi } @@ -1017,13 +1598,13 @@ _sign_netboot_artifacts() { local _file _dir local _files_to_sign=() _msg_info "Signing netboot artifacts..." - _dir="${isofs_dir}/${install_dir}/boot/" + _dir="${isofs_dir}/${install_dir}/boot" for _file in "${ucodes[@]}"; do - if [[ -e "${_dir}${_file}" ]]; then - _files_to_sign+=("${_dir}${_file}") + if [[ -e "${_dir}/${_file}" ]]; then + _files_to_sign+=("${_dir}/${_file}") fi done - for _file in "${_files_to_sign[@]}" "${_dir}${arch}/vmlinuz-"* "${_dir}${arch}/initramfs-"*.img; do + for _file in "${_files_to_sign[@]}" "${_dir}/${arch}/vmlinuz-"* "${_dir}/${arch}/initramfs-"*.img; do openssl cms \ -sign \ -binary \ @@ -1033,25 +1614,53 @@ _sign_netboot_artifacts() { -inkey "${cert_list[1]}" \ -outform DER \ -out "${_file}".ipxe.sig - done - _msg_info "Done!" + done + _msg_info "Done!" + } + + _validate_requirements_airootfs_image_type_squashfs() { + if ! command -v mksquashfs &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${airootfs_image_type}': mksquashfs is not available on this host. Install 'squashfs-tools'!" 0 + fi + } + + _validate_requirements_airootfs_image_type_ext4() { + if ! { command -v mkfs.ext4 &> /dev/null && command -v tune2fs &> /dev/null; }; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${airootfs_image_type}': mkfs.ext4 and/or tune2fs is not available on this host. Install 'e2fsprogs'!" 0 + fi + } + + _validate_requirements_airootfs_image_type_ext4+squashfs() { + _validate_requirements_airootfs_image_type_ext4 + _validate_requirements_airootfs_image_type_squashfs } -_validate_requirements_airootfs_image_type_squashfs() { - if ! command -v mksquashfs &> /dev/null; then - (( validation_error=validation_error+1 )) - _msg_error "Validating '${airootfs_image_type}': mksquashfs is not available on this host. Install 'squashfs-tools'!" 0 +# +_resolve_encryption_key(){ + if [ ! -f "${encryption_key}" ]; then + if [ "${encryption_key}" = 'auto' ]; then + encryption_key="${work_dir}/${iso_label}.key" + [ ! -d "${work_dir}" ] && install -d "${work_dir}" + dd if=/dev/random bs=512 count=1 of="${encryption_key}" + elif [ "${encryption_key}" != 'auto' ]; then + _msg_error "File '${encryption_key}' does not exist." 0 + fi fi } -_validate_requirements_airootfs_image_type_ext4+squashfs() { - if ! { command -v mkfs.ext4 &> /dev/null && command -v tune2fs &> /dev/null; }; then - (( validation_error=validation_error+1 )) - _msg_error "Validating '${airootfs_image_type}': mkfs.ext4 and/or tune2fs is not available on this host. Install 'e2fsprogs'!" 0 - fi +_validate_requirements_airootfs_image_type_squashfs+luks() { + _validate_requirements_airootfs_image_type_luks _validate_requirements_airootfs_image_type_squashfs } +_validate_requirements_airootfs_image_type_ext4+squashfs+luks() { + _validate_requirements_airootfs_image_type_luks + _validate_requirements_airootfs_image_type_squashfs + _validate_requirements_airootfs_image_type_ext4 +} + _validate_requirements_airootfs_image_type_erofs() { if ! command -v mkfs.erofs &> /dev/null; then (( validation_error=validation_error+1 )) @@ -1059,6 +1668,19 @@ _validate_requirements_airootfs_image_type_erofs() { fi } +_validate_requirements_airootfs_image_type_luks() { + if ! command -v cryptsetup &> /dev/null && command -v mkfs.erofs &> /dev/null; then + (( validation_error=validation_error+1 )) + _msg_error "Validating '${airootfs_image_type}': cryptsetup is not available on this host. Install 'cryptsetup'!" 0 + fi + [[ -n "$encryption_key" ]] && _resolve_encryption_key +} + +_validate_requirements_airootfs_image_type_erofs+luks() { + _validate_requirements_airootfs_image_type_luks + _validate_requirements_airootfs_image_type_erofs +} + _validate_common_requirements_buildmode_all() { if ! command -v pacman &> /dev/null; then (( validation_error=validation_error+1 )) @@ -1072,6 +1694,9 @@ _validate_common_requirements_buildmode_all() { (( validation_error=validation_error+1 )) _msg_error "Validating build mode '${_buildmode}': gzip is not available on this host. Install 'gzip'!" 0 fi + if [[ ! " ${buildmodes[*]} " =~ ' dongle ' ]]; then + _msg_warning "Validating build mode '${_buildmode}': 'dongle' build mode not selected, the resulting image will be vulnerable to 'evil maids'." + fi } _validate_requirements_buildmode_bootstrap() { @@ -1128,6 +1753,11 @@ _validate_common_requirements_buildmode_iso_netboot() { fi } +_validate_requirements_buildmode_dongle() { + _validate_common_requirements_buildmode_all + [[ -n "$encryption_key" ]] && _resolve_encryption_key +} + _validate_requirements_buildmode_iso() { _validate_common_requirements_buildmode_iso_netboot _validate_common_requirements_buildmode_all @@ -1183,23 +1813,25 @@ _validate_requirements_buildmode_netboot() { fi } -# SYSLINUX El Torito -_add_xorrisofs_options_bios.syslinux.eltorito() { - xorrisofs_options+=( - # El Torito boot image for x86 BIOS - '-eltorito-boot' 'syslinux/isolinux.bin' - # El Torito boot catalog file - '-eltorito-catalog' 'syslinux/boot.cat' - # Required options to boot with ISOLINUX - '-no-emul-boot' '-boot-load-size' '4' '-boot-info-table' - ) +_add_xorrisofs_options_persistent_partition() { + local _xorrisofs_options=("$@") + if [[ "${persistent_image_type}" == *"luks" ]]; then + persistent_guid="CA7D7CCB-63ED-4C53-861C-1742536059CC" + else + persistent_guid="0FC63DAF-8483-4772-8E79-3D69D8477DE4" + fi + _xorrisofs_options+=('-append_partition' '3' "${persistent_guid}" "${persistentimg}") + echo "${_xorrisofs_options[@]}" } # SYSLINUX MBR (isohybrid) _add_xorrisofs_options_bios.syslinux.mbr() { - xorrisofs_options+=( + local bootable_dir="${1}" + shift + local _xorrisofs_options=("$@") + _xorrisofs_options+=( # SYSLINUX MBR bootstrap code; does not work without "-eltorito-boot syslinux/isolinux.bin" - '-isohybrid-mbr' "${isofs_dir}/syslinux/isohdpfx.bin" + '-isohybrid-mbr' "${bootable_dir}/syslinux/isohdpfx.bin" # When GPT is used, create an additional partition in the MBR (besides 0xEE) for sectors 0–1 (MBR # bootstrap code area) and mark it as bootable # May allow booting on some systems @@ -1210,35 +1842,88 @@ _add_xorrisofs_options_bios.syslinux.mbr() { # https://dev.lovelyhq.com/libburnia/libisoburn/src/branch/master/doc/partition_offset.wiki '-partition_offset' '16' ) + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_bios.syslinux.mbr_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_bios.syslinux.mbr "${isofs_dir}" "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_bios.syslinux.mbr_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_bios.syslinux.mbr "${dongle_isofs_dir}" "${dongle_xorrisofs_options[@]}")") +} + +# SYSLINUX El Torito +_add_xorrisofs_options_bios.syslinux.eltorito() { + local _xorrisofs_options=("$@") + _xorrisofs_options+=(# El Torito boot image for x86 BIOS + '-eltorito-boot' 'syslinux/isolinux.bin' + # El Torito boot catalog file + '-eltorito-catalog' 'syslinux/boot.cat' + # Required options to boot with ISOLINUX + '-no-emul-boot' '-boot-load-size' '4' '-boot-info-table') + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_bios.syslinux.eltorito_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_bios.syslinux.eltorito "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_bios.syslinux.eltorito_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_bios.syslinux.eltorito "${dongle_xorrisofs_options[@]}")") } # GRUB in an attached EFI system partition _add_xorrisofs_options_uefi-ia32.grub.esp() { + local _xorrisofs_options=("$@") # 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 ' && ! " ${bootmodes[*]} " =~ ' uefi-x64.grub.esp ' ]]; then # _add_xorrisofs_options_uefi-x64.systemd-boot.esp - _add_xorrisofs_options_uefi-x64.grub.esp + _xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.grub.esp "${_xorrisofs_options[@]}")") fi + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_uefi-ia32.grub.esp_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_uefi-ia32.grub.esp "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_uefi-ia32.grub.esp_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_uefi-ia32.grub.esp "${dongle_xorrisofs_options[@]}")") } # GRUB via El Torito _add_xorrisofs_options_uefi-ia32.grub.eltorito() { + local _xorrisofs_options=("$@") # shellcheck disable=SC2076 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 + _xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.grub.eltorito "${_xorrisofs_options[@]}")") fi + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_uefi-ia32.grub.eltorito_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_uefi-ia32.grub.eltorito "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_uefi-ia32.grub.eltorito_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_uefi-ia32.grub.eltorito "${dongle_xorrisofs_options[@]}")") } # systemd-boot in an attached EFI system partition _add_xorrisofs_options_uefi-x64.systemd-boot.esp() { + local _xorrisofs_options=("$@") # 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') + [[ " ${_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}") + _xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${efibootimg}") + if [ "${persistent_size_kib}" != "" ]; then + _xorrisofs_options=("$(_add_xorrisofs_options_persistent_partition "${_xorrisofs_options[@]}")") + fi # Ensure GPT is used as some systems do not support UEFI booting without it # shellcheck disable=SC2076 if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then @@ -1249,67 +1934,91 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.esp() { # 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') + 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') + _xorrisofs_options+=('-appended_part_as_gpt') fi + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_uefi-x64.systemd-boot.esp_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.systemd-boot.esp "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_uefi-x64.systemd-boot.esp_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.systemd-boot.esp "${dongle_xorrisofs_options[@]}")") } # systemd-boot via El Torito _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() { + local bootable_dir="${1}" + shift + local _xorrisofs_options=("$@") # shellcheck disable=SC2076 if [[ " ${bootmodes[*]} " =~ ' uefi-x64.systemd-boot.esp ' || " ${bootmodes[*]} " =~ ' uefi-ia32.grub.esp ' ]]; then # systemd-boot 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 + _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" + install -d -m 0755 -- "${bootable_dir}/EFI/archiso" + cp -a -- "${efibootimg}" "${bootable_dir}/EFI/archiso/efiboot.img" # systemd-boot in an embedded efiboot.img via El Torito - xorrisofs_options+=( + _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' - ) + '-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') + [[ " ${bootmodes[*]} " =~ ' bios.' ]] || _xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat') + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_uefi-x64.systemd-boot.eltorito_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.systemd-boot.eltorito "${isofs_dir}" "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_uefi-x64.systemd-boot.eltorito_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.systemd-boot.eltorito "${dongle_isofs_dir}" "${dongle_xorrisofs_options[@]}")") } # GRUB in an attached EFI system partition. # Same as _add_xorrisofs_options_uefi-x64.systemd-boot.esp. _add_xorrisofs_options_uefi-x64.grub.esp() { + local _xorrisofs_options=("$@") # 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') + [[ " ${_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}") + _xorrisofs_options+=('-append_partition' '2' 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' "${efibootimg}") + if [ "${persistent_size_kib}" != "" ]; then + _xorrisofs_options=("$(_add_xorrisofs_options_persistent_partition "${_xorrisofs_options[@]}")") + fi # Ensure GPT is used as some systems do not support UEFI booting without it # shellcheck disable=SC2076 if [[ " ${bootmodes[*]} " =~ ' bios.syslinux.mbr ' ]]; then @@ -1320,57 +2029,78 @@ _add_xorrisofs_options_uefi-x64.grub.esp() { # 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') + 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') + _xorrisofs_options+=('-appended_part_as_gpt') fi + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_uefi-x64.grub.esp_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.grub.esp "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_uefi-x64.grub.esp_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.grub.esp "${dongle_xorrisofs_options[@]}")") } # GRUB via El Torito # Same as _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito. _add_xorrisofs_options_uefi-x64.grub.eltorito() { + local bootable_dir="${1}" + shift + local _xorrisofs_options=("$@") # 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' + _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 + # 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" + install -d -m 0755 -- "${bootable_dir}/EFI/archiso" + cp -a -- "${efibootimg}" "${bootable_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' + _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') + [[ " ${bootmodes[*]} " =~ ' bios.' ]] || _xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat') + echo "${_xorrisofs_options[@]}" +} + +_add_xorrisofs_options_uefi-x64.grub.eltorito_iso() { + xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.grub.eltorito "${isofs_dir}" "${xorrisofs_options[@]}")") +} + +_add_xorrisofs_options_uefi-x64.grub.eltorito_dongle() { + dongle_xorrisofs_options=("$(_add_xorrisofs_options_uefi-x64.grub.eltorito "${dongle_isofs_dir}" "${dongle_xorrisofs_options[@]}")") } # Build bootstrap image @@ -1389,9 +2119,57 @@ _build_bootstrap_image() { cd -- "${OLDPWD}" } +_build_dongle_image() { + local bootmode dongle_xorriso_cmd_line dongle_xorriso_options=() dongle_xorrisofs_options=() + dongle_isofs_dir="${work_dir}/dongle_iso" + + # Add required xorrisofs options for each boot mode + for bootmode in "${bootmodes[@]}"; do + "_add_xorrisofs_options_${bootmode}_dongle" + done + + [[ -d "${out_dir}" ]] || install -d -- "${out_dir}" + + if [[ "${quiet}" == "y" ]]; then + # The when xorriso is run in mkisofs compatibility mode (xorrisofs), the mkisofs option -quiet is interpreted + # too late (e.g. messages about SOURCE_DATE_EPOCH still get shown). + # Instead use native xorriso option to silence the output. + dongle_xorriso_options+=('-report_about' 'SORRY' "${dongle_xorriso_options[@]}") + fi + + # Update SORCE_DATE_EPOCH for dongle ISO UUID + SOURCE_DATE_EPOCH=$((SOURCE_DATE_EPOCH + 69 * 42)) + + rm -f -- "${out_dir}/${image_name}" + _msg_info "Creating ISO image..." + _msg_info "xorriso options: ${dongle_xorriso_options[*]}" + _msg_info "xorrisofs options: ${dongle_xorrisofs_options[*]}" + # shellcheck disable=SC2116 + dongle_xorriso_cmd_line=( + "${dongle_xorriso_options[@]}" + '-as' 'mkisofs' + '-iso-level' 3 + '-full-iso9660-filenames' + '-joliet' + '-joliet-long' + '-rational-rock' + '-volid' "${iso_label}_KEYS" + '-appid' "\"${iso_application} dongle CD\"" + '-publisher' "\"${iso_publisher}\"" + '-preparer' "\"prepared by ${app_name}\"" + "${dongle_xorrisofs_options[@]}" + '-output' "\"${out_dir}/${image_name}\"" + "${dongle_isofs_dir}/" + ) + eval "xorriso ${dongle_xorriso_cmd_line[*]}" + _msg_info "Done!" + du -h -- "${out_dir}/${image_name}" +} + # Build ISO _build_iso_image() { - local xorriso_options=() xorrisofs_options=() + local xorriso_cmd_line + isofs_dir="${work_dir}/iso" local bootmode [[ -d "${out_dir}" ]] || install -d -- "${out_dir}" @@ -1400,31 +2178,40 @@ _build_iso_image() { # The when xorriso is run in mkisofs compatibility mode (xorrisofs), the mkisofs option -quiet is interpreted # too late (e.g. messages about SOURCE_DATE_EPOCH still get shown). # Instead use native xorriso option to silence the output. - xorriso_options=('-report_about' 'SORRY' "${xorriso_options[@]}") + xorriso_options+=('-report_about' 'SORRY' "${xorriso_options[@]}") fi # Add required xorrisofs options for each boot mode for bootmode in "${bootmodes[@]}"; do - typeset -f "_add_xorrisofs_options_${bootmode}" &> /dev/null && "_add_xorrisofs_options_${bootmode}" + "_add_xorrisofs_options_${bootmode}_iso" done rm -f -- "${out_dir}/${image_name}" + # shellcheck disable=SC2116 + xorriso_cmd_line=( + "${xorriso_options[@]}" '-as' 'mkisofs' + '-iso-level' 3 + '-full-iso9660-filenames' + '-joliet' + '-joliet-long' + '-rational-rock' + '-volid' "${iso_label}" + '-appid' "\"${iso_application}\"" + '-publisher' "\"${iso_publisher}\"" + '-preparer' "\"prepared by ${app_name}\"" + "${xorrisofs_options[@]}" + '-output' "${out_dir}/${image_name}" + "${isofs_dir}/" + ) _msg_info "Creating ISO image..." - xorriso "${xorriso_options[@]}" -as mkisofs \ - -iso-level 3 \ - -full-iso9660-filenames \ - -joliet \ - -joliet-long \ - -rational-rock \ - -volid "${iso_label}" \ - -appid "${iso_application}" \ - -publisher "${iso_publisher}" \ - -preparer "prepared by ${app_name}" \ - "${xorrisofs_options[@]}" \ - -output "${out_dir}/${image_name}" \ - "${isofs_dir}/" + _msg_info "xorriso args: ${xorriso_cmd_line[*]}" + eval "xorriso ${xorriso_cmd_line[*]}" _msg_info "Done!" du -h -- "${out_dir}/${image_name}" + + if [[ "${airootfs_image_type}" == *"luks"* ]] && [[ ! " ${buildmodes[*]} " =~ ' dongle ' ]]; then + cp "${encryption_key}" "${out_dir}" + fi } # Read profile's values from profiledef.sh @@ -1541,6 +2328,7 @@ _set_overrides() { fi [[ ! -v override_gpg_key ]] || gpg_key="$override_gpg_key" [[ ! -v override_gpg_sender ]] || gpg_sender="$override_gpg_sender" + [[ ! -v override_gpg_home ]] || gpg_home="$override_gpg_home" if [[ -v override_cert_list ]]; then sign_netboot_artifacts="y" fi @@ -1553,12 +2341,21 @@ _set_overrides() { # Set variables that do not have overrides [[ -n "$airootfs_image_type" ]] || airootfs_image_type="squashfs" + [[ -n "$keys_image_type" ]] || keys_image_type="squashfs+luks" + [[ -n "$persistent_image_type" ]] || persistent_image_type="ext4+luks" [[ -n "$iso_name" ]] || iso_name="${app_name}" + [[ -n "$isofs_dir" ]] || isofs_dir="${work_dir}/iso" + [[ -n "$airootfs_img_dir" ]] || airootfs_img_dir="${isofs_dir}/${install_dir}/${arch}" + [[ -n "$dongle_isofs_dir" ]] || dongle_isofs_dir="${work_dir}/dongle_iso" + [[ -n "$efibootimg" ]] || efibootimg="${work_dir}/efiboot.img" + [[ -n "$persistentimg" ]] || persistentimg="${work_dir}/persistent."$(_get_fs_ext "persistent") } _export_gpg_publickey() { rm -f -- "${work_dir}/pubkey.gpg" - gpg --batch --no-armor --output "${work_dir}/pubkey.gpg" --export "${gpg_key}" + GNUPGHOME="${gpg_home}" gpg --homedir "${gpg_home}" \ + --batch --no-armor --output "${work_dir}/pubkey.gpg" \ + --export "${gpg_key}" } _make_version() { @@ -1604,7 +2401,13 @@ _make_pkglist() { "bootstrap") pacman -Q --sysroot "${pacstrap_dir}" > "${pacstrap_dir}/pkglist.${arch}.txt" ;; - "iso"|"netboot") + "iso") + install -d -m 0755 -- "${isofs_dir}/${install_dir}" + if [[ ! "${airootfs_image_type}" == *"luks"* ]]; then + pacman -Q --sysroot "${pacstrap_dir}" > "${isofs_dir}/${install_dir}/pkglist.${arch}.txt" + fi + ;; + "netboot") install -d -m 0755 -- "${isofs_dir}/${install_dir}" pacman -Q --sysroot "${pacstrap_dir}" > "${isofs_dir}/${install_dir}/pkglist.${arch}.txt" ;; @@ -1612,6 +2415,29 @@ _make_pkglist() { _msg_info "Done!" } +# build the base for an ISO and/or a netboot target +_build_dongle_base() { + local run_once_mode="base" + local _sig_dir + _sig_dir="${dongle_isofs_dir}/${install_dir}/${arch}" + keys_dir="${work_dir}/keys" + + [[ -d "${keys_dir}" ]] || install -d -- "${keys_dir}" + [[ -d "${dongle_isofs_dir}" ]] || install -d -- "${dongle_isofs_dir}" + + if [ "${encryption_key}" != "" ]; then + cp "${encryption_key}" "${keys_dir}/airootfs.key" + fi + + if [[ "${airootfs_image_type}" == *"luks"* ]] && [[ " ${buildmodes[*]} " =~ ' dongle ' ]]; then + _run_once _prepare_keys_image + fi + + _run_once _make_boot_on_dongle + _make_bootmodes_dongle +} + + # build the base for an ISO and/or a netboot target _build_iso_base() { local run_once_mode="base" @@ -1621,9 +2447,15 @@ _build_iso_base() { # Set up essential directory paths pacstrap_dir="${work_dir}/${arch}/airootfs" isofs_dir="${work_dir}/iso" + keys_dir="${work_dir}/keys" + airootfs_img_dir="${isofs_dir}/${install_dir}/${arch}" + persistent_dir="${work_dir}/persistent" # Create working directory - [[ -d "${work_dir}" ]] || install -d -- "${work_dir}" + [[ -d "${airootfs_img_dir}" ]] || install -d -- "${airootfs_img_dir}" + [[ -d "${keys_dir}" ]] || install -d -- "${keys_dir}" + [[ -d "${persistent_dir}" ]] || install -d -- "${persistent_dir}" + # Write build date to file or if the file exists, read it from there if [[ -e "${work_dir}/build_date" ]]; then SOURCE_DATE_EPOCH="$(<"${work_dir}/build_date")" @@ -1639,10 +2471,11 @@ _build_iso_base() { _run_once _make_version _run_once _make_customize_airootfs _run_once _make_pkglist + _run_once _prepare_persistent_image if [[ "${buildmode}" == 'netboot' ]]; then _run_once _make_boot_on_iso9660 else - _make_bootmodes + _make_bootmodes_iso fi _run_once _cleanup_pacstrap_dir _run_once _prepare_airootfs_image @@ -1690,6 +2523,15 @@ _build_buildmode_iso() { _run_once _build_iso_image } +# Build the dongle ISO buildmode +_build_buildmode_dongle() { + local image_name="${iso_name}-dongle-${iso_version}-${arch}.iso" + local run_once_mode="${buildmode}" + efibootimg="${work_dir}/efiboot.img" + _build_dongle_base + _run_once _build_dongle_image +} + # build all buildmodes _build() { local buildmode @@ -1700,7 +2542,7 @@ _build() { done } -while getopts 'c:p:C:L:P:A:D:w:m:o:g:G:vh?' arg; do +while getopts 'c:p:C:L:P:A:D:w:m:o:g:G:H:vh?' arg; do case "${arg}" in p) read -r -a override_pkg_list <<< "${OPTARG}" ;; C) override_pacman_conf="${OPTARG}" ;; @@ -1714,6 +2556,7 @@ while getopts 'c:p:C:L:P:A:D:w:m:o:g:G:vh?' arg; do o) override_out_dir="${OPTARG}" ;; g) override_gpg_key="${OPTARG}" ;; G) override_gpg_sender="${OPTARG}" ;; + H) override_gpg_home="${OPTARG}" ;; v) override_quiet="n" ;; h|?) _usage 0 ;; *) diff --git a/configs/baseline/airootfs/etc/mkinitcpio.conf b/configs/baseline/airootfs/etc/mkinitcpio.conf index 34b1a0666c6aadaf6a1e58be545ce7d508500840..4dec74d44819b6e163753a80b357c2276badfa9d 100644 --- a/configs/baseline/airootfs/etc/mkinitcpio.conf +++ b/configs/baseline/airootfs/etc/mkinitcpio.conf @@ -49,7 +49,7 @@ FILES=() # ## NOTE: If you have /usr on a separate partition, you MUST include the # usr, fsck and shutdown hooks. -HOOKS=(base udev modconf archiso block filesystems) +HOOKS=(base udev modconf %ARCHISO_HOOKS% block filesystems) # COMPRESSION # Use this to compress the initramfs image. By default, gzip compression diff --git a/configs/baseline/airootfs/etc/systemd/system/system-generators/systemd-gpt-auto-generator b/configs/baseline/airootfs/etc/systemd/system/system-generators/systemd-gpt-auto-generator new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/configs/baseline/efiboot/loader/entries/01-archiso-x86_64-linux.conf b/configs/baseline/efiboot/loader/entries/01-archiso-x86_64-linux.conf index 11624b658a80564635eeded5c08f2a93c1375124..814678d9bc9452b0e179872d9acf5eb8d860961e 100644 --- a/configs/baseline/efiboot/loader/entries/01-archiso-x86_64-linux.conf +++ b/configs/baseline/efiboot/loader/entries/01-archiso-x86_64-linux.conf @@ -1,4 +1,5 @@ -title Arch Linux (x86_64, UEFI) -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% +title Arch Linux (%ARCH%, UEFI) +sort-key 01 +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img +options %KERNEL_PARAMS% diff --git a/configs/baseline/efiboot/loader/entries/02-archiso-x86_64-ram-linux.conf b/configs/baseline/efiboot/loader/entries/02-archiso-x86_64-ram-linux.conf index d66f5a6b9642968a72011efbb2792426e051e08b..f37a0011f969d64ca45e92e5d544dc8474ffd890 100644 --- a/configs/baseline/efiboot/loader/entries/02-archiso-x86_64-ram-linux.conf +++ b/configs/baseline/efiboot/loader/entries/02-archiso-x86_64-ram-linux.conf @@ -1,4 +1,5 @@ -title Arch Linux (x86_64, UEFI) Copy to RAM -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram +title Arch Linux (%ARCH%, UEFI) Copy to RAM +sort-key 02 +linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img +options %KERNEL_PARAMS% copytoram diff --git a/configs/baseline/grub/grub.cfg b/configs/baseline/grub/grub.cfg index dead8ce2841d0fa7dd3b09fccef88370ab5ffe98..d63427770a42ef47cf58a05f69cf980030f443fd 100644 --- a/configs/baseline/grub/grub.cfg +++ b/configs/baseline/grub/grub.cfg @@ -28,16 +28,16 @@ timeout_style=menu # Menu entries -menuentry "Arch Linux (x86_64, UEFI)" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' { +menuentry "Arch Linux (%ARCH%, 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% - initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img + search --no-floppy --set=root --fs-uuid %BOOTABLE_UUID% + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux %KERNEL_PARAMS% + initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img } -menuentry "Arch Linux (x86_64, UEFI) Copy to RAM" --class arch --class gnu-linux --class gnu --class os --id 'archlinux-copy-to-ram' { +menuentry "Arch Linux (%ARCH%, 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 - initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img + search --no-floppy --set=root --fs-uuid %BOOTABLE_UUID% + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux %KERNEL_PARAMS% copytoram + initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img } diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index 411558149c0f5e652a030cc75f5f6b005c8ea572..a2ee6393fdf7f6c7b4a1ac47c94eda929631f9b7 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -7,14 +7,21 @@ iso_publisher="Arch Linux " iso_application="Arch Linux baseline" iso_version="$(date +%Y.%m.%d)" install_dir="arch" -buildmodes=('iso') -bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' - 'uefi-ia32.grub.esp' 'uefi-x64.grub.esp' - 'uefi-ia32.grub.eltorito' 'uefi-x64.grub.eltorito') +buildmodes=('iso' 'dongle') +bootmodes=('bios.syslinux.mbr' + 'bios.syslinux.eltorito' + 'uefi-ia32.grub.esp' + 'uefi-ia32.grub.eltorito' + 'uefi-x64.systemd-boot.esp' + 'uefi-x64.systemd-boot.eltorito') arch="x86_64" pacman_conf="pacman.conf" airootfs_image_type="erofs" airootfs_image_tool_options=('-zlz4hc,12' -E ztailpacking) +encryption_key="auto" +persistent_size=10000 +keys_image_type="erofs" +keys_image_tool_options=('-zlz4hc,12' -E ztailpacking) file_permissions=( ["/etc/shadow"]="0:0:400" ) diff --git a/configs/baseline/run/archiso/keys/.gitkeep b/configs/baseline/run/archiso/keys/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/configs/baseline/syslinux/syslinux-linux.cfg b/configs/baseline/syslinux/syslinux-linux.cfg index 6bfd0c3047fd8c6c716cd93a7579e4fd84ade0c7..274515a7540f2cd0fad60bb1d346b0896a501234 100644 --- a/configs/baseline/syslinux/syslinux-linux.cfg +++ b/configs/baseline/syslinux/syslinux-linux.cfg @@ -1,11 +1,11 @@ LABEL arch -MENU LABEL Arch Linux (x86_64, BIOS) +MENU LABEL Arch Linux (%ARCH%, BIOS) LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% +APPEND %KERNEL_PARAMS% LABEL arch-ram -MENU LABEL Arch Linux (x86_64, BIOS) Copy to RAM +MENU LABEL Arch Linux (%ARCH%, BIOS) Copy to RAM LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux INITRD /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram +APPEND %KERNEL_PARAMS% copytoram diff --git a/configs/releng/airootfs/etc/mkinitcpio.conf b/configs/releng/airootfs/etc/mkinitcpio.conf index f57dbdd2e9332d14ff6122f746a1d14a7c90f544..1e8601ab1d90ae4bcc518a78cb7ad03e3c7e1c8a 100644 --- a/configs/releng/airootfs/etc/mkinitcpio.conf +++ b/configs/releng/airootfs/etc/mkinitcpio.conf @@ -49,7 +49,7 @@ FILES=() # ## NOTE: If you have /usr on a separate partition, you MUST include the # usr, fsck and shutdown hooks. -HOOKS=(base udev modconf memdisk archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_kms block filesystems keyboard) +HOOKS=(base udev modconf memdisk keyboard %ARCHISO_HOOKS% archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_kms block filesystems) # COMPRESSION # Use this to compress the initramfs image. By default, gzip compression diff --git a/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/setup-persistent-storage.service b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/setup-persistent-storage.service new file mode 120000 index 0000000000000000000000000000000000000000..875f86200480093059234649cdfc1a772dd59aa4 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/setup-persistent-storage.service @@ -0,0 +1 @@ +/etc/systemd/system/setup-persistent-storage.service \ No newline at end of file diff --git a/configs/releng/airootfs/etc/systemd/system/setup-persistent-storage.service b/configs/releng/airootfs/etc/systemd/system/setup-persistent-storage.service new file mode 100644 index 0000000000000000000000000000000000000000..823cb1ee949a28c2b1e18fd5f139cf782e74f522 --- /dev/null +++ b/configs/releng/airootfs/etc/systemd/system/setup-persistent-storage.service @@ -0,0 +1,9 @@ +[Unit] +Description=Setup an encrypted persistent storage on the USB drive + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/setup-persistent-storage + +[Install] +WantedBy=multi-user.target diff --git a/configs/releng/airootfs/usr/local/bin/setup-persistent-storage b/configs/releng/airootfs/usr/local/bin/setup-persistent-storage new file mode 100755 index 0000000000000000000000000000000000000000..743f959541929d76597abbf1cb99ae52d714f4b2 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/setup-persistent-storage @@ -0,0 +1,139 @@ +#!/bin/bash + +grub_cfg="/run/archiso/bootmnt/EFI/BOOT/grub.cfg" +archisouuid="$(grep "archisouuid=" < "${grub_cfg}" | head -1 | awk '{print $5}' | sed 's/archisouuid=//g')" +archisolabel="$(grep "archisolabel=" < "${grub_cfg}" | head -1 | awk '{print $5}' | sed 's/archisouuid=//g')" +guid="0FC63DAF-8483-4772-8E79-3D69D8477DE4" + +_find_iso() { + for disk in /dev/disk/by-diskseq/*; do + disk_uuid=$(blkid -o value -s UUID "${disk}") + disk_type=$(blkid -o value -s TYPE "${disk}") + #shellcheck disable=SC2154 + if [ "${disk_uuid}" = "${archisouuid}" ] && [ "${disk_type}" = "iso9660" ]; then + break + fi + done +} + +_get_avail_space() { + disk_avail="$(parted "${disk}" unit MB print free | grep 'Free Space' | tail -n1 | awk '{print $3}' | sed 's/MB//g')" + mem_avail=$(( $(grep MemAvailable <"/proc/meminfo" | awk '{print $2}') / 1000)) + avail=$(( disk_avail < mem_avail ? disk_avail : mem_avail )) +} + +_mount_keys_device() { + keys_device="/dev/disk/by-label/${archisolabel}_KEYS" + mkdir /ckey /ckey2 + chmod 700 /ckey /ckey2 + mount "${keys_device}" "/ckey" + cryptsetup --type luks2 open "/ckey/keys.erofs" "keys.map" + mount -t erofs "/dev/mapper/keys.map" "/ckey2" +} + +_unmount_keys_device() { + umount "/ckey2" + _close_luks_device "/dev/mapper/keys.map" + umount "/ckey" +} + +_resolve_encryption_key() { + local passwd_path="/tmp/persistent.passwd" + if [ "${encryption_key}" = "" ]; then + echo -n "Enter a new password for the persistent partition:" + read -rs password + echo "${password}" > "${passwd_path}" + encryption_key="${passwd_path}" + elif [ ! -f "${encryption_key}" ]; then + if [ "${encryption_key}" = "auto" ]; then + encryption_key="${passwd_path}" + dd if="/dev/random" bs=32 count=1 of="${encryption_key}" + echo "The encryption key has been saved to ${encryption_key}" + elif [ "${encryption_key}" = "airootfs" ]; then + _mount_keys_device + mkdir /tmp/keys + chmod 700 /tmp/keys + cp /ckey2/airootfs.key /tmp/keys/storage.key + encryption_key="/tmp/keys/storage.key" + else + echo "File ${encryption_key} does not exist." + exit 0 + fi + fi +} + +_luks_format(){ + mapper=$(basename "${image_path}")".map" + image_device="/dev/mapper/${mapper}" + cryptsetup_opts=('--type' 'luks2') + if [ "${encryption_key}" != "" ]; then + cryptsetup_opts+=("--key-file=${encryption_key}") + fi + cryptsetup_opts+=('--integrity' 'cmac-aes' \ + '--sector-size' '4096' \ + '--pbkdf-memory' 256) + while ! eval "cryptsetup -q -y luksFormat ${cryptsetup_opts[*]} ${image_path}"; do + sleep 1 + done + while ! eval "cryptsetup open ${image_path} ${mapper}"; do + _close_luks_device "${image_device}" + done +} + +_close_luks_device() { + local device="${1}" + local mapper + mapper=$(basename "${device}") + blockdev --flushbufs "${device}" + cryptsetup luksClose "${mapper}" || true + if [ -e "${device}" ]; then + dmsetup remove "${device}" || true + fi + sync +} + +_make_persistent() { + encryption_key="${1}" + image_path="/tmp/persistent.img" + passwd_path="/tmp/persistent.passwd" + mount -o remount,rw,size=1E "/run/archiso/cowspace" + fallocate -l "${avail}M" "${image_path}" + losetup "/dev/loop314" "${image_path}" + luks_format + mkfs.ext4 -O '^has_journal,^resize_inode' \ + -E 'lazy_itable_init=0,root_owner=0:0' \ + -m '0' -F -U 'clear' -- "${image_device}" + tune2fs -c 0 -i 0 - "${image_device}" > /dev/null + sync + _close_luks_device "${image_device}" + losetup -d "/dev/loop314" + # rm "${encryption_key}" +} + +_add_persistent() { + xorriso -indev "${disk}" -outdev "${disk}" -append_partition 3 "${guid}" "${image_path}" -boot_image any replay +} + +_validate_requirements() { + partitions=$(partx -g "${disk}" | wl -l) + if [ "${partitions}" -gt 2 ]; then + exit 0 + fi + _resolve_encryption_key +} + +_refresh_partitions() { + partprobe "${disk}" +} + +_start() { + local encryption_key="${1}" + _find_iso + _validate_requirements + _get_avail_space + _make_persistent "${encryption_key}" + _add_persistent + _refresh_partitions +} + +_start "${1}" diff --git a/configs/releng/efiboot/loader/entries/01-archiso-x86_64-linux.conf b/configs/releng/efiboot/loader/entries/01-archiso-x86_64-linux.conf index 1c2a7a82ae3cb6038c4d321c08fa736cfe2e4be4..7e0ab9357bfb18964f0dfce5fa05add3396a2ca5 100644 --- a/configs/releng/efiboot/loader/entries/01-archiso-x86_64-linux.conf +++ b/configs/releng/efiboot/loader/entries/01-archiso-x86_64-linux.conf @@ -1,7 +1,7 @@ -title Arch Linux install medium (x86_64, UEFI) +title Arch Linux install medium (%ARCH%, UEFI) sort-key 01 -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux initrd /%INSTALL_DIR%/boot/intel-ucode.img initrd /%INSTALL_DIR%/boot/amd-ucode.img -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% +initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +options %KERNEL_PARAMS% diff --git a/configs/releng/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf b/configs/releng/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf index 64253d3b5d306803224f647424d5e8a26b079f1e..f0d4ddc0d388c986bc800ada54eb774025ed6354 100644 --- a/configs/releng/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf +++ b/configs/releng/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf @@ -1,7 +1,7 @@ -title Arch Linux install medium (x86_64, UEFI) with speech +title Arch Linux install medium (%ARCH%, UEFI) with speech sort-key 02 -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux initrd /%INSTALL_DIR%/boot/intel-ucode.img initrd /%INSTALL_DIR%/boot/amd-ucode.img -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% accessibility=on +initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +options %KERNEL_PARAMS% accessibility=on diff --git a/configs/releng/efiboot/loader/entries/03-archiso-x86_64-ram-linux.conf b/configs/releng/efiboot/loader/entries/03-archiso-x86_64-ram-linux.conf index 3e2665193b4f6e0a62c1df8fd45ed201859a11cc..63a552d9856671d1c69539d4466def5b7777cfcd 100644 --- a/configs/releng/efiboot/loader/entries/03-archiso-x86_64-ram-linux.conf +++ b/configs/releng/efiboot/loader/entries/03-archiso-x86_64-ram-linux.conf @@ -1,7 +1,7 @@ -title Arch Linux install medium (x86_64, UEFI, Copy to RAM) +title Arch Linux install medium (%ARCH%, UEFI, Copy to RAM) sort-key 03 -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux initrd /%INSTALL_DIR%/boot/intel-ucode.img initrd /%INSTALL_DIR%/boot/amd-ucode.img -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram +initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +options %KERNEL_PARAMS% copytoram diff --git a/configs/releng/efiboot/loader/entries/04-archiso-x86_64-ram-speech-linux.conf b/configs/releng/efiboot/loader/entries/04-archiso-x86_64-ram-speech-linux.conf index 0d67999c57d8092e5f29131af55b99fbe008705e..0f64f5c0050a88e37de638fdb97084ded1d3b361 100644 --- a/configs/releng/efiboot/loader/entries/04-archiso-x86_64-ram-speech-linux.conf +++ b/configs/releng/efiboot/loader/entries/04-archiso-x86_64-ram-speech-linux.conf @@ -1,7 +1,7 @@ -title Arch Linux install medium (x86_64, UEFI, Copy to RAM) with speech +title Arch Linux install medium (%ARCH%, UEFI, Copy to RAM) with speech sort-key 04 -linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux +linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux initrd /%INSTALL_DIR%/boot/intel-ucode.img initrd /%INSTALL_DIR%/boot/amd-ucode.img -initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram accessibility=on +initrd /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +options %KERNEL_PARAMS% copytoram accessibility=on diff --git a/configs/releng/grub/grub.cfg b/configs/releng/grub/grub.cfg index 43fad0e83e80467f6c52afd1f3e0e405c65a3193..c5b5afcb28b28311a46b8affa28449bedc677b64 100644 --- a/configs/releng/grub/grub.cfg +++ b/configs/releng/grub/grub.cfg @@ -30,31 +30,31 @@ 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' { +menuentry "Arch Linux install medium (%ARCH%, 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% - initrd /%INSTALL_DIR%/boot/intel-ucode.img /%INSTALL_DIR%/boot/amd-ucode.img /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img + search --no-floppy --set=root --fs-uuid %BOOTABLE_UUID% + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux %KERNEL_PARAMS% + initrd /%INSTALL_DIR%/boot/intel-ucode.img /%INSTALL_DIR%/boot/amd-ucode.img /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img } -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' { +menuentry "Arch Linux install medium with speakup screen reader (%ARCH%, 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 + search --no-floppy --set=root --fs-uuid %BOOTABLE_UUID% + linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux %KERNEL_PARAMS% accessibility=on + initrd /%INSTALL_DIR%/boot/intel-ucode.img /%INSTALL_DIR%/boot/amd-ucode.img /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img } if [ "${grub_platform}" == "efi" ]; then if [ "${grub_cpu}" == "x86_64" ]; then menuentry "UEFI Shell" { insmod chain - search --no-floppy --set=root --label %ARCHISO_LABEL% + search --no-floppy --set=root --fs-uuid %BOOTABLE_UUID% chainloader /shellx64.efi } elif [ "${grub_cpu}" == "i386" ]; then menuentry "UEFI Shell" { insmod chain - search --no-floppy --set=root --label %ARCHISO_LABEL% + search --no-floppy --set=root --fs-uuid %BOOTABLE_UUID% chainloader /shellia32.efi } fi diff --git a/configs/releng/packages.x86_64 b/configs/releng/packages.x86_64 index 8a0c80dbf8f6a60662cba51d4d97ee1574d03931..fc0d3e7ce389cbf98070fdd59697b90757c74d8a 100644 --- a/configs/releng/packages.x86_64 +++ b/configs/releng/packages.x86_64 @@ -121,4 +121,5 @@ wpa_supplicant wvdial xfsprogs xl2tpd +xorriso zsh diff --git a/configs/releng/profiledef.sh b/configs/releng/profiledef.sh index 4b4e68c0227e41091d6013275d2c8dfb370fea3f..e5e3487ae7399e3c9b2579260de60c2e1ebae677 100644 --- a/configs/releng/profiledef.sh +++ b/configs/releng/profiledef.sh @@ -7,19 +7,27 @@ iso_publisher="Arch Linux " iso_application="Arch Linux Live/Rescue CD" iso_version="$(date +%Y.%m.%d)" install_dir="arch" -buildmodes=('iso') -bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' - 'uefi-ia32.grub.esp' 'uefi-x64.grub.esp' - 'uefi-ia32.grub.eltorito' 'uefi-x64.grub.eltorito') +buildmodes=('iso' 'dongle') +bootmodes=('bios.syslinux.mbr' + 'bios.syslinux.eltorito' + 'uefi-ia32.grub.esp' + 'uefi-ia32.grub.eltorito' + 'uefi-x64.systemd-boot.esp' + 'uefi-x64.systemd-boot.eltorito') arch="x86_64" pacman_conf="pacman.conf" -airootfs_image_type="squashfs" -airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M') +airootfs_image_type="erofs" +airootfs_image_tool_options=('-zlz4hc,12' -E ztailpacking) +encryption_key="auto" +keys_image_type="erofs" +keys_image_tool_options=('-zlz4hc,12') file_permissions=( ["/etc/shadow"]="0:0:400" ["/root"]="0:0:750" ["/root/.automated_script.sh"]="0:0:755" + ["/run/archiso/keys"]="0:0:700" ["/usr/local/bin/choose-mirror"]="0:0:755" ["/usr/local/bin/Installation_guide"]="0:0:755" ["/usr/local/bin/livecd-sound"]="0:0:755" + ["/usr/local/bin/setup-persistent-storage"]="0:0:755" ) diff --git a/configs/releng/syslinux/archiso_pxe-linux.cfg b/configs/releng/syslinux/archiso_pxe-linux.cfg index d812402a94b25a5b09558c017bc95f1819d273b9..b5e300fcb9e976cbc09ccf7796f634efb059d4df 100644 --- a/configs/releng/syslinux/archiso_pxe-linux.cfg +++ b/configs/releng/syslinux/archiso_pxe-linux.cfg @@ -3,10 +3,10 @@ TEXT HELP Boot the Arch Linux install medium using NBD. It allows you to install Arch Linux or perform system maintenance. ENDTEXT -MENU LABEL Arch Linux install medium (x86_64, NBD) -LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% archiso_nbd_srv=${pxeserver} checksum verify +MENU LABEL Arch Linux install medium (%ARCH%, NBD) +LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND %KERNEL_PARAMS% archiso_nbd_srv=${pxeserver} checksum verify SYSAPPEND 3 LABEL arch64_nfs @@ -14,10 +14,10 @@ TEXT HELP Boot the Arch Linux live medium using NFS. It allows you to install Arch Linux or perform system maintenance. ENDTEXT -MENU LABEL Arch Linux install medium (x86_64, NFS) -LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt checksum verify +MENU LABEL Arch Linux install medium (%ARCH%, NFS) +LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND %KERNEL_PARAMS% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt checksum verify SYSAPPEND 3 LABEL arch64_http @@ -25,8 +25,8 @@ TEXT HELP Boot the Arch Linux live medium using HTTP. It allows you to install Arch Linux or perform system maintenance. ENDTEXT -MENU LABEL Arch Linux install medium (x86_64, HTTP) -LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archiso_http_srv=http://${pxeserver}/ checksum verify +MENU LABEL Arch Linux install medium (%ARCH%, HTTP) +LINUX ::/%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND %KERNEL_PARAMS% archiso_http_srv=http://${pxeserver}/ checksum verify SYSAPPEND 3 diff --git a/configs/releng/syslinux/archiso_sys-linux.cfg b/configs/releng/syslinux/archiso_sys-linux.cfg index 0d85fccf1b0b34216e7a33234b9bcf056701ad5c..e47f3fadba2eaac16d5e086672f4c48fba5da21f 100644 --- a/configs/releng/syslinux/archiso_sys-linux.cfg +++ b/configs/releng/syslinux/archiso_sys-linux.cfg @@ -3,10 +3,10 @@ TEXT HELP Boot the Arch Linux install medium on BIOS. It allows you to install Arch Linux or perform system maintenance. ENDTEXT -MENU LABEL Arch Linux install medium (x86_64, BIOS) -LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% +MENU LABEL Arch Linux install medium (%ARCH%, BIOS) +LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND %KERNEL_PARAMS% # Accessibility boot option LABEL arch64speech @@ -14,10 +14,10 @@ TEXT HELP Boot the Arch Linux install medium on BIOS with speakup screen reader. It allows you to install Arch Linux or perform system maintenance with speech feedback. ENDTEXT -MENU LABEL Arch Linux install medium (x86_64, BIOS) with ^speech -LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% accessibility=on +MENU LABEL Arch Linux install medium (%ARCH%, BIOS) with ^speech +LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND %KERNEL_PARAMS% accessibility=on # Copy to RAM boot option LABEL arch64ram @@ -25,7 +25,7 @@ TEXT HELP Boot the Arch Linux install medium on BIOS with Copy-to-RAM option It allows you to install Arch Linux or perform system maintenance. ENDTEXT -MENU LABEL Arch Linux install medium (x86_64, BIOS, Copy to RAM) -LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux -INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img -APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram +MENU LABEL Arch Linux install medium (%ARCH%, BIOS, Copy to RAM) +LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux +INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img +APPEND %KERNEL_PARAMS% copytoram diff --git a/docs/README.profile.rst b/docs/README.profile.rst index efcb86124a5a3481d81d7de3cfb63043b29c94a0..d4da0d809c97c947b4a5b1fb6d018a0332422313 100644 --- a/docs/README.profile.rst +++ b/docs/README.profile.rst @@ -39,6 +39,7 @@ The image file is constructed from some of the variables in ``profiledef.sh``: ` understood: - ``bootstrap``: Build a compressed file containing a minimal system to bootstrap from + - ``keys``: Build a "keys" ISO that is able to boot encrypted bootable ISO images. - ``iso``: Build a bootable ISO image (implicit default, if no ``buildmodes`` are set) - ``netboot``: Build artifacts required for netboot using iPXE * ``bootmodes``: A list of strings, that state the supported boot modes of the resulting image. Only the following are @@ -60,10 +61,21 @@ The image file is constructed from some of the variables in ``profiledef.sh``: ` * ``airootfs_image_type``: The image type to create. The following options are understood (defaults to ``squashfs``): - ``squashfs``: Create a squashfs image directly from the airootfs work directory + - ``squashfs+luks``: Create a LUKS image containing a squashfs generated directly from the airootfs work directory - ``ext4+squashfs``: Create an ext4 partition, copy the airootfs work directory to it and create a squashfs image from it + - ``ext4+squashfs+luks``: Create an ext4 partition, copy the airootfs work directory to it and create a LUKS containing a squashfs image generated from it - ``erofs``: Create an EROFS image for the airootfs work directory + - ``erofs+luks``: Create a LUKS image containing an EROFS image for the airootfs work directory * ``airootfs_image_tool_options``: An array of options to pass to the tool to create the airootfs image. ``mksquashfs`` and ``mkfs.erofs`` are supported. See ``mksquashfs --help`` or ``mkfs.erofs --help`` for all possible options +* ``encryption_key``: If pointing to a file, it will use as encryption key for the airootfs; if "auto" will generate a key + at build time; if empty, will prompt for password. +* ``persistent_size_kib``: Size in KB of the persistent partition. +* ``persistent_image_type``: The type of the persistent portion of the ISO. + - ``ext4``: Create an ext4 partition. + - ``ext4+luks``: Create a LUKS container with an ext4 partition inside. +* ``keys_image_type``: Same as ``airootfs_image_type`` for the "keys" ISO. +* ``keys_image_tool_options``: Same as ``airootfs_image_tool_options`` for the "keys" ISO. * ``file_permissions``: An associative array that lists files and/or directories who need specific ownership or permissions. The array's keys contain the path and the value is a colon separated list of owner UID, owner GID and access mode. E.g. ``file_permissions=(["/etc/shadow"]="0:0:400")``. When directories are listed with a trailing backslash (``/``) **all** files and directories contained within the listed directory will have the same owner UID, owner GID, and access mode applied recursively.