Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archiso
diff options
context:
space:
mode:
authorDavid Runge <dvzrv@archlinux.org>2021-05-02 18:58:47 +0200
committerDavid Runge <dvzrv@archlinux.org>2021-05-09 15:50:08 +0200
commit2cac53967b99a497914c001ddeeb9b72d090b5d4 (patch)
tree1bc3a99b5e2a5b4d32cde699e854c15a89ba680f /archiso
parent535bc3c0daa761728bd4578ab3bc3726c0a60fda (diff)
mkarchiso: Implement buildmodes that allow building bootstrap images
archiso/mkarchiso: Introduce a buildmodes array, that can be used to build towards more than one output artifact type. Add a buildmode for building a bootstrap image (a compressed file containing a very minimal Arch installation). The buildmodes can be set either using a `buildmodes` array in a `profiledef.sh` or by using the `-m` option flag to mkarchiso and providing a space delimited, quoted list. The 'iso' buildmode is always the default if no buildmodes are setup. Implement building a bootstrap image, when using the 'bootstrap' `buildmode`, which uses a profile's 'bootstrap_packages.$arch' file to install packages using pacstrap and compressing it to a bootstrap image. The name of the output file is currently constructed from the `iso_name` value by appending `-bootstrap`. Replace the uses of `airootfs_dir` with the more generic `pacstrap_dir`, as the location denotes where pacstrap is being used. Replace uses of `img_name` with `image_name` and removing it from the global scope, so that it can be overridden per each buildmode. Rename `_cleanup_airootfs_dir()` to `_cleanup_pacstrap_dir()`. Make `_run_once()` more generic by prepending the state files with a string defined by `run_once_mode`. Add `_validate_requirements_buildmode_all()`, `_validate_requirements_buildmode_bootstrap()` and `_validate_requirements_buildmode_iso()` to validate the general requirements of the different buildmodes. Add `_build_bootstrap_image()` to generate the bootstrap image using bsdtar. Rename `_build_iso()` to `_build_iso_image()` to fit the naming of the respective bootstrap function. Extend `_read_profile()` to include the reading of bootstrap image specific packages from a file. Extend `_validate_options()` to include testing of the bootstrap packages and running of validation functions for all buildmodes. Change `_set_overrides()` to override the buildmodes if they are specified via the `-m` option flag. Change `_make_version()` to be used generically in all buildmodes. Change `_make_pkglist()` to be used generically in all buildmodes. Rename `_build_profile()` to `_build_buildmode_iso()` and set local variables that are specific to the buildmode, such as `image_name`, `pacstrap_dir`, `run_once_mode` , `buildmode_packages` and `buildmode_pkg_list`. Add `_build_buildmode_bootstrap()` and set local variables that are specific to the buildmode, such as `image_name`, `pacstrap_dir`, `run_once_mode` , `buildmode_packages` and `buildmode_pkg_list`. Add the `-m` option flag to the list of flags. Closes #127
Diffstat (limited to 'archiso')
-rwxr-xr-xarchiso/mkarchiso393
1 files changed, 272 insertions, 121 deletions
diff --git a/archiso/mkarchiso b/archiso/mkarchiso
index aaf8325..683f90e 100755
--- a/archiso/mkarchiso
+++ b/archiso/mkarchiso
@@ -14,10 +14,10 @@ app_name="${0##*/}"
# Define global variables. All of them will be overwritten later
pkg_list=()
+bootstrap_pkg_list=()
quiet=""
work_dir=""
out_dir=""
-img_name=""
gpg_key=""
iso_name=""
iso_label=""
@@ -28,6 +28,9 @@ install_dir=""
arch=""
pacman_conf=""
packages=""
+bootstrap_packages=""
+pacstrap_dir=""
+buildmodes=()
bootmodes=()
airootfs_image_type=""
airootfs_image_tool_options=()
@@ -63,8 +66,8 @@ _msg_error() {
_mount_airootfs() {
trap "_umount_airootfs" EXIT HUP INT TERM
install -d -m 0755 -- "${work_dir}/mnt/airootfs"
- _msg_info "Mounting '${airootfs_dir}.img' on '${work_dir}/mnt/airootfs'..."
- mount -- "${airootfs_dir}.img" "${work_dir}/mnt/airootfs"
+ _msg_info "Mounting '${pacstrap_dir}.img' on '${work_dir}/mnt/airootfs'..."
+ mount -- "${pacstrap_dir}.img" "${work_dir}/mnt/airootfs"
_msg_info "Done!"
}
@@ -95,6 +98,8 @@ usage: ${app_name} [options] <profile_dir>
Default: '${iso_publisher}'
-g <gpg_key> Set the PGP key ID to be used for signing the rootfs image
-h This message
+ -m [build modes] Build modes to use (valid modes are: 'bootstrap' and 'iso').
+ Multiple build modes are provided as quoted, space delimited list.
-o <out_dir> Set the output directory
Default: '${out_dir}'
-p PACKAGE(S) Package(s) to install.
@@ -119,38 +124,41 @@ _show_config() {
_msg_info " Installation directory: ${install_dir}"
_msg_info " Build date: ${build_date}"
_msg_info " Output directory: ${out_dir}"
+ _msg_info " Current build mode: ${buildmode}"
+ _msg_info " Build modes: ${buildmodes[*]}"
_msg_info " GPG key: ${gpg_key:-None}"
_msg_info " Profile: ${profile}"
_msg_info "Pacman configuration file: ${pacman_conf}"
- _msg_info " Image file name: ${img_name}"
+ _msg_info " Image file name: ${image_name:-None}"
_msg_info " ISO volume label: ${iso_label}"
_msg_info " ISO publisher: ${iso_publisher}"
_msg_info " ISO application: ${iso_application}"
_msg_info " Boot modes: ${bootmodes[*]}"
- _msg_info " Packages: ${pkg_list[*]}"
+ _msg_info " Packages File: ${buildmode_packages}"
+ _msg_info " Packages: ${buildmode_pkg_list[*]}"
}
# Cleanup airootfs
-_cleanup_airootfs() {
- _msg_info "Cleaning up what we can on airootfs..."
+_cleanup_pacstrap_dir() {
+ _msg_info "Cleaning up in pacstrap location..."
# Delete all files in /boot
- [[ -d "${airootfs_dir}/boot" ]] && find "${airootfs_dir}/boot" -mindepth 1 -delete
+ [[ -d "${pacstrap_dir}/boot" ]] && find "${pacstrap_dir}/boot" -mindepth 1 -delete
# Delete pacman database sync cache files (*.tar.gz)
- [[ -d "${airootfs_dir}/var/lib/pacman" ]] && find "${airootfs_dir}/var/lib/pacman" -maxdepth 1 -type f -delete
+ [[ -d "${pacstrap_dir}/var/lib/pacman" ]] && find "${pacstrap_dir}/var/lib/pacman" -maxdepth 1 -type f -delete
# Delete pacman database sync cache
- [[ -d "${airootfs_dir}/var/lib/pacman/sync" ]] && find "${airootfs_dir}/var/lib/pacman/sync" -delete
+ [[ -d "${pacstrap_dir}/var/lib/pacman/sync" ]] && find "${pacstrap_dir}/var/lib/pacman/sync" -delete
# Delete pacman package cache
- [[ -d "${airootfs_dir}/var/cache/pacman/pkg" ]] && find "${airootfs_dir}/var/cache/pacman/pkg" -type f -delete
+ [[ -d "${pacstrap_dir}/var/cache/pacman/pkg" ]] && find "${pacstrap_dir}/var/cache/pacman/pkg" -type f -delete
# Delete all log files, keeps empty dirs.
- [[ -d "${airootfs_dir}/var/log" ]] && find "${airootfs_dir}/var/log" -type f -delete
+ [[ -d "${pacstrap_dir}/var/log" ]] && find "${pacstrap_dir}/var/log" -type f -delete
# Delete all temporary files and dirs
- [[ -d "${airootfs_dir}/var/tmp" ]] && find "${airootfs_dir}/var/tmp" -mindepth 1 -delete
+ [[ -d "${pacstrap_dir}/var/tmp" ]] && find "${pacstrap_dir}/var/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 -- "${airootfs_dir}/etc/machine-id"
- printf '' > "${airootfs_dir}/etc/machine-id"
+ rm -f -- "${pacstrap_dir}/etc/machine-id"
+ printf '' > "${pacstrap_dir}/etc/machine-id"
_msg_info "Done!"
}
@@ -166,49 +174,49 @@ _run_mksquashfs() {
# Makes a ext4 filesystem inside a SquashFS from a source directory.
_mkairootfs_ext4+squashfs() {
- [[ -e "${airootfs_dir}" ]] || _msg_error "The path '${airootfs_dir}' does not exist" 1
+ [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1
_msg_info "Creating ext4 image of 32 GiB..."
if [[ "${quiet}" == "y" ]]; then
- mkfs.ext4 -q -O '^has_journal,^resize_inode' -E 'lazy_itable_init=0' -m 0 -F -- "${airootfs_dir}.img" 32G
+ mkfs.ext4 -q -O '^has_journal,^resize_inode' -E 'lazy_itable_init=0' -m 0 -F -- "${pacstrap_dir}.img" 32G
else
- mkfs.ext4 -O '^has_journal,^resize_inode' -E 'lazy_itable_init=0' -m 0 -F -- "${airootfs_dir}.img" 32G
+ mkfs.ext4 -O '^has_journal,^resize_inode' -E 'lazy_itable_init=0' -m 0 -F -- "${pacstrap_dir}.img" 32G
fi
- tune2fs -c 0 -i 0 -- "${airootfs_dir}.img" > /dev/null
+ tune2fs -c 0 -i 0 -- "${pacstrap_dir}.img" > /dev/null
_msg_info "Done!"
_mount_airootfs
- _msg_info "Copying '${airootfs_dir}/' to '${work_dir}/mnt/airootfs/'..."
- cp -aT -- "${airootfs_dir}/" "${work_dir}/mnt/airootfs/"
+ _msg_info "Copying '${pacstrap_dir}/' to '${work_dir}/mnt/airootfs/'..."
+ cp -aT -- "${pacstrap_dir}/" "${work_dir}/mnt/airootfs/"
chown -- 0:0 "${work_dir}/mnt/airootfs/"
_msg_info "Done!"
_umount_airootfs
install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}"
_msg_info "Creating SquashFS image, this may take some time..."
- _run_mksquashfs "${airootfs_dir}.img"
+ _run_mksquashfs "${pacstrap_dir}.img"
_msg_info "Done!"
- rm -- "${airootfs_dir}.img"
+ rm -- "${pacstrap_dir}.img"
}
# Makes a SquashFS filesystem from a source directory.
_mkairootfs_squashfs() {
- [[ -e "${airootfs_dir}" ]] || _msg_error "The path '${airootfs_dir}' does not exist" 1
+ [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1
install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}"
_msg_info "Creating SquashFS image, this may take some time..."
- _run_mksquashfs "${airootfs_dir}"
+ _run_mksquashfs "${pacstrap_dir}"
}
# Makes an EROFS file system from a source directory.
_mkairootfs_erofs() {
local fsuuid
- [[ -e "${airootfs_dir}" ]] || _msg_error "The path '${airootfs_dir}' does not exist" 1
+ [[ -e "${pacstrap_dir}" ]] || _msg_error "The path '${pacstrap_dir}' does not exist" 1
install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}"
local image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs"
# Generate reproducible file system UUID from SOURCE_DATE_EPOCH
fsuuid="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 --name "${SOURCE_DATE_EPOCH}")"
_msg_info "Creating EROFS image, this may take some time..."
- mkfs.erofs -U "${fsuuid}" "${airootfs_image_tool_options[@]}" -- "${image_path}" "${airootfs_dir}"
+ mkfs.erofs -U "${fsuuid}" "${airootfs_image_tool_options[@]}" -- "${image_path}" "${pacstrap_dir}"
_msg_info "Done!"
}
@@ -239,9 +247,9 @@ _mksignature() {
# Helper function to run functions only one time.
_run_once() {
- if [[ ! -e "${work_dir}/build.${1}" ]]; then
+ if [[ ! -e "${work_dir}/${run_once_mode}.${1}" ]]; then
"$1"
- touch "${work_dir}/build.${1}"
+ touch "${work_dir}/${run_once_mode}.${1}"
fi
}
@@ -267,7 +275,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 = ${airootfs_dir}/etc/pacman.d/hooks/" > "${work_dir}/pacman.conf"
+ /\[options\]/a HookDir = ${pacstrap_dir}/etc/pacman.d/hooks/" > "${work_dir}/${buildmode}.pacman.conf"
}
# Prepare working directory and copy custom airootfs files (airootfs)
@@ -275,27 +283,27 @@ _make_custom_airootfs() {
local passwd=()
local filename permissions
- install -d -m 0755 -o 0 -g 0 -- "${airootfs_dir}"
+ install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}"
if [[ -d "${profile}/airootfs" ]]; then
_msg_info "Copying custom airootfs files..."
- cp -af --no-preserve=ownership,mode -- "${profile}/airootfs/." "${airootfs_dir}"
+ cp -af --no-preserve=ownership,mode -- "${profile}/airootfs/." "${pacstrap_dir}"
# Set ownership and mode for files and directories
for filename in "${!file_permissions[@]}"; do
IFS=':' read -ra permissions <<< "${file_permissions["${filename}"]}"
- # Prevent file path traversal outside of $airootfs_dir
- if [[ "$(realpath -q -- "${airootfs_dir}${filename}")" != "${airootfs_dir}"* ]]; then
- _msg_error "Failed to set permissions on '${airootfs_dir}${filename}'. Outside of valid path." 1
+ # Prevent file path traversal outside of $pacstrap_dir
+ if [[ "$(realpath -q -- "${pacstrap_dir}${filename}")" != "${pacstrap_dir}"* ]]; then
+ _msg_error "Failed to set permissions on '${pacstrap_dir}${filename}'. Outside of valid path." 1
# Warn if the file does not exist
- elif [[ ! -e "${airootfs_dir}${filename}" ]]; then
- _msg_warning "Cannot change permissions of '${airootfs_dir}${filename}'. The file or directory does not exist."
+ elif [[ ! -e "${pacstrap_dir}${filename}" ]]; then
+ _msg_warning "Cannot change permissions of '${pacstrap_dir}${filename}'. The file or directory does not exist."
else
if [[ "${filename: -1}" == "/" ]]; then
- chown -fhR -- "${permissions[0]}:${permissions[1]}" "${airootfs_dir}${filename}"
- chmod -fR -- "${permissions[2]}" "${airootfs_dir}${filename}"
+ chown -fhR -- "${permissions[0]}:${permissions[1]}" "${pacstrap_dir}${filename}"
+ chmod -fR -- "${permissions[2]}" "${pacstrap_dir}${filename}"
else
- chown -fh -- "${permissions[0]}:${permissions[1]}" "${airootfs_dir}${filename}"
- chmod -f -- "${permissions[2]}" "${airootfs_dir}${filename}"
+ chown -fh -- "${permissions[0]}:${permissions[1]}" "${pacstrap_dir}${filename}"
+ chmod -f -- "${permissions[2]}" "${pacstrap_dir}${filename}"
fi
fi
done
@@ -305,7 +313,7 @@ _make_custom_airootfs() {
# Install desired packages to airootfs
_make_packages() {
- _msg_info "Installing packages to '${airootfs_dir}/'..."
+ _msg_info "Installing packages to '${pacstrap_dir}/'..."
if [[ -n "${gpg_key}" ]]; then
exec {ARCHISO_GNUPG_FD}<>"${work_dir}/pubkey.gpg"
@@ -313,9 +321,9 @@ _make_packages() {
fi
if [[ "${quiet}" = "y" ]]; then
- pacstrap -C "${work_dir}/pacman.conf" -c -G -M -- "${airootfs_dir}" "${pkg_list[@]}" &> /dev/null
+ pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}" &> /dev/null
else
- pacstrap -C "${work_dir}/pacman.conf" -c -G -M -- "${airootfs_dir}" "${pkg_list[@]}"
+ pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}"
fi
if [[ -n "${gpg_key}" ]]; then
@@ -338,27 +346,27 @@ _make_customize_airootfs() {
# Skip invalid home directories
[[ "${passwd[5]}" == '/' ]] && continue
[[ -z "${passwd[5]}" ]] && continue
- # Prevent path traversal outside of $airootfs_dir
- if [[ "$(realpath -q -- "${airootfs_dir}${passwd[5]}")" == "${airootfs_dir}"* ]]; then
- if [[ ! -d "${airootfs_dir}${passwd[5]}" ]]; then
- install -d -m 0750 -o "${passwd[2]}" -g "${passwd[3]}" -- "${airootfs_dir}${passwd[5]}"
+ # Prevent path traversal outside of $pacstrap_dir
+ if [[ "$(realpath -q -- "${pacstrap_dir}${passwd[5]}")" == "${pacstrap_dir}"* ]]; then
+ if [[ ! -d "${pacstrap_dir}${passwd[5]}" ]]; then
+ install -d -m 0750 -o "${passwd[2]}" -g "${passwd[3]}" -- "${pacstrap_dir}${passwd[5]}"
fi
- cp -dnRT --preserve=mode,timestamps,links -- "${airootfs_dir}/etc/skel/." "${airootfs_dir}${passwd[5]}"
- chmod -f 0750 -- "${airootfs_dir}${passwd[5]}"
- chown -hR -- "${passwd[2]}:${passwd[3]}" "${airootfs_dir}${passwd[5]}"
+ cp -dnRT --preserve=mode,timestamps,links -- "${pacstrap_dir}/etc/skel/." "${pacstrap_dir}${passwd[5]}"
+ chmod -f 0750 -- "${pacstrap_dir}${passwd[5]}"
+ chown -hR -- "${passwd[2]}:${passwd[3]}" "${pacstrap_dir}${passwd[5]}"
else
- _msg_error "Failed to set permissions on '${airootfs_dir}${passwd[5]}'. Outside of valid path." 1
+ _msg_error "Failed to set permissions on '${pacstrap_dir}${passwd[5]}'. Outside of valid path." 1
fi
done < "${profile}/airootfs/etc/passwd"
_msg_info "Done!"
fi
- if [[ -e "${airootfs_dir}/root/customize_airootfs.sh" ]]; then
- _msg_info "Running customize_airootfs.sh in '${airootfs_dir}' chroot..."
+ if [[ -e "${pacstrap_dir}/root/customize_airootfs.sh" ]]; then
+ _msg_info "Running customize_airootfs.sh in '${pacstrap_dir}' chroot..."
_msg_warning "customize_airootfs.sh is deprecated! Support for it will be removed in a future archiso version."
- chmod -f -- +x "${airootfs_dir}/root/customize_airootfs.sh"
- eval -- arch-chroot "${airootfs_dir}" "/root/customize_airootfs.sh"
- rm -- "${airootfs_dir}/root/customize_airootfs.sh"
+ chmod -f -- +x "${pacstrap_dir}/root/customize_airootfs.sh"
+ eval -- arch-chroot "${pacstrap_dir}" "/root/customize_airootfs.sh"
+ rm -- "${pacstrap_dir}/root/customize_airootfs.sh"
_msg_info "Done! customize_airootfs.sh run successfully."
fi
}
@@ -376,15 +384,15 @@ _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 -- "${airootfs_dir}/boot/initramfs-"*".img" "${isofs_dir}/${install_dir}/boot/${arch}/"
- install -m 0644 -- "${airootfs_dir}/boot/vmlinuz-"* "${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}/"
for ucode_image in {intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio}; do
- if [[ -e "${airootfs_dir}/boot/${ucode_image}" ]]; then
- install -m 0644 -- "${airootfs_dir}/boot/${ucode_image}" "${isofs_dir}/${install_dir}/boot/"
- if [[ -e "${airootfs_dir}/usr/share/licenses/${ucode_image%.*}/" ]]; then
+ 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 -- "${airootfs_dir}/usr/share/licenses/${ucode_image%.*}/"* \
+ install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/${ucode_image%.*}/"* \
"${isofs_dir}/${install_dir}/boot/licenses/${ucode_image%.*}/"
fi
fi
@@ -405,28 +413,28 @@ _make_bootmode_bios.syslinux.mbr() {
if [[ -e "${profile}/syslinux/splash.png" ]]; then
install -m 0644 -- "${profile}/syslinux/splash.png" "${isofs_dir}/syslinux/"
fi
- install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/"*.c32 "${isofs_dir}/syslinux/"
- install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${isofs_dir}/syslinux/"
- install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/memdisk" "${isofs_dir}/syslinux/"
+ 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/"
_run_once _make_boot_on_iso9660
if [[ -e "${isofs_dir}/syslinux/hdt.c32" ]]; then
install -d -m 0755 -- "${isofs_dir}/syslinux/hdt"
- if [[ -e "${airootfs_dir}/usr/share/hwdata/pci.ids" ]]; then
- gzip -cn9 "${airootfs_dir}/usr/share/hwdata/pci.ids" > \
+ 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"
fi
- find "${airootfs_dir}/usr/lib/modules" -name 'modules.alias' -print -exec gzip -cn9 '{}' ';' -quit > \
+ find "${pacstrap_dir}/usr/lib/modules" -name 'modules.alias' -print -exec gzip -cn9 '{}' ';' -quit > \
"${isofs_dir}/syslinux/hdt/modalias.gz"
fi
# Add other aditional/extra files to ${install_dir}/boot/
- if [[ -e "${airootfs_dir}/boot/memtest86+/memtest.bin" ]]; then
+ if [[ -e "${pacstrap_dir}/boot/memtest86+/memtest.bin" ]]; then
# rename for PXE: https://wiki.archlinux.org/index.php/Syslinux#Using_memtest
- install -m 0644 -- "${airootfs_dir}/boot/memtest86+/memtest.bin" "${isofs_dir}/${install_dir}/boot/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 -- "${airootfs_dir}/usr/share/licenses/common/GPL2/license.txt" \
+ install -m 0644 -- "${pacstrap_dir}/usr/share/licenses/common/GPL2/license.txt" \
"${isofs_dir}/${install_dir}/boot/licenses/memtest86+/"
fi
_msg_info "Done! SYSLINUX set up for BIOS booting from a disk successfully."
@@ -436,8 +444,8 @@ _make_bootmode_bios.syslinux.mbr() {
_make_bootmode_bios.syslinux.eltorito() {
_msg_info "Setting up SYSLINUX for BIOS booting from an optical disc..."
install -d -m 0755 -- "${isofs_dir}/syslinux"
- install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/isolinux.bin" "${isofs_dir}/syslinux/"
- install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${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/"
# ISOLINUX and SYSLINUX installation is shared
_run_once _make_bootmode_bios.syslinux.mbr
@@ -449,7 +457,7 @@ _make_bootmode_bios.syslinux.eltorito() {
_make_efi_dir_on_iso9660() {
_msg_info "Preparing an /EFI directory for the ISO 9660 file system..."
install -d -m 0755 -- "${isofs_dir}/EFI/BOOT"
- install -m 0644 -- "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
+ install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
"${isofs_dir}/EFI/BOOT/BOOTx64.EFI"
install -d -m 0755 -- "${isofs_dir}/loader/entries"
@@ -464,8 +472,8 @@ _make_efi_dir_on_iso9660() {
# edk2-shell based UEFI shell
# shellx64.efi is picked up automatically when on /
- if [[ -e "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then
- install -m 0644 -- "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${isofs_dir}/shellx64.efi"
+ if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then
+ install -m 0644 -- "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" "${isofs_dir}/shellx64.efi"
fi
_msg_info "Done!"
}
@@ -476,10 +484,10 @@ _make_boot_on_fat() {
_msg_info "Preparing kernel and initramfs for the FAT file system..."
mmd -i "${work_dir}/efiboot.img" \
"::/${install_dir}" "::/${install_dir}/boot" "::/${install_dir}/boot/${arch}"
- mcopy -i "${work_dir}/efiboot.img" "${airootfs_dir}/boot/vmlinuz-"* \
- "${airootfs_dir}/boot/initramfs-"*".img" "::/${install_dir}/boot/${arch}/"
+ mcopy -i "${work_dir}/efiboot.img" "${pacstrap_dir}/boot/vmlinuz-"* \
+ "${pacstrap_dir}/boot/initramfs-"*".img" "::/${install_dir}/boot/${arch}/"
for ucode_image in \
- "${airootfs_dir}/boot/"{intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio}
+ "${pacstrap_dir}/boot/"{intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio}
do
if [[ -e "${ucode_image}" ]]; then
all_ucode_images+=("${ucode_image}")
@@ -498,12 +506,12 @@ _make_bootmode_uefi-x64.systemd-boot.esp() {
# the required image size in KiB (rounded up to the next full MiB with an additional MiB for reserved sectors)
efiboot_imgsize="$(du -bc \
- "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
- "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" \
+ "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
+ "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" \
"${profile}/efiboot/" \
- "${airootfs_dir}/boot/vmlinuz-"* \
- "${airootfs_dir}/boot/initramfs-"*".img" \
- "${airootfs_dir}/boot/"{intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio} \
+ "${pacstrap_dir}/boot/vmlinuz-"* \
+ "${pacstrap_dir}/boot/initramfs-"*".img" \
+ "${pacstrap_dir}/boot/"{intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio} \
2>/dev/null | awk 'function ceil(x){return int(x)+(x>int(x))}
function byte_to_kib(x){return x/1024}
function mib_to_kib(x){return x*1024}
@@ -517,7 +525,7 @@ _make_bootmode_uefi-x64.systemd-boot.esp() {
mmd -i "${work_dir}/efiboot.img" ::/EFI ::/EFI/BOOT
mcopy -i "${work_dir}/efiboot.img" \
- "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI
+ "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI
mmd -i "${work_dir}/efiboot.img" ::/loader ::/loader/entries
mcopy -i "${work_dir}/efiboot.img" "${profile}/efiboot/loader/loader.conf" ::/loader/
@@ -529,9 +537,9 @@ _make_bootmode_uefi-x64.systemd-boot.esp() {
done
# shellx64.efi is picked up automatically when on /
- if [[ -e "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then
+ if [[ -e "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ]]; then
mcopy -i "${work_dir}/efiboot.img" \
- "${airootfs_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi
+ "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi" ::/shellx64.efi
fi
# Copy kernel and initramfs
@@ -664,6 +672,37 @@ _validate_requirements_airootfs_image_type_erofs() {
fi
}
+_validate_requirements_buildmode_all() {
+ if ! command -v pacman &> /dev/null; then
+ (( validation_error=validation_error+1 ))
+ _msg_error "Validating build mode '${_buildmode}': pacman is not available on this host. Install 'pacman'!" 0
+ fi
+ if ! command -v find &> /dev/null; then
+ (( validation_error=validation_error+1 ))
+ _msg_error "Validating build mode '${_buildmode}': find is not available on this host. Install 'findutils'!" 0
+ fi
+ if ! command -v gzip &> /dev/null; then
+ (( validation_error=validation_error+1 ))
+ _msg_error "Validating build mode '${_buildmode}': gzip is not available on this host. Install 'gzip'!" 0
+ fi
+}
+
+_validate_requirements_buildmode_bootstrap() {
+ _validate_requirements_buildmode_all
+ if ! command -v bsdtar &> /dev/null; then
+ (( validation_error=validation_error+1 ))
+ _msg_error "Validating build mode '${_buildmode}': bsdtar is not available on this host. Install 'libarchive'!" 0
+ fi
+}
+
+_validate_requirements_buildmode_iso() {
+ _validate_requirements_buildmode_all
+ if ! command -v awk &> /dev/null; then
+ (( validation_error=validation_error+1 ))
+ _msg_error "Validating build mode '${_buildmode}': awk is not available on this host. Install 'awk'!" 0
+ fi
+}
+
# SYSLINUX El Torito
_add_xorrisofs_options_bios.syslinux.eltorito() {
xorrisofs_options+=(
@@ -763,8 +802,24 @@ _add_xorrisofs_options_uefi-x64.systemd-boot.eltorito() {
[[ " ${bootmodes[*]} " =~ ' bios.' ]] || xorrisofs_options+=('-eltorito-catalog' 'EFI/boot.cat')
}
+# Build bootstrap image
+_build_bootstrap_image() {
+ local _bootstrap_parent
+ _bootstrap_parent="$(dirname -- "${pacstrap_dir}")"
+
+ [[ -d "${out_dir}" ]] || install -d -- "${out_dir}"
+
+ cd -- "${_bootstrap_parent}"
+
+ _msg_info "Creating bootstrap image..."
+ bsdtar -cf - "root.${arch}" | gzip -cn9 > "${out_dir}/${image_name}"
+ _msg_info "Done!"
+ du -h -- "${out_dir}/${image_name}"
+ cd -- "${OLDPWD}"
+}
+
# Build ISO
-_build_iso() {
+_build_iso_image() {
local xorrisofs_options=()
local bootmode
@@ -789,10 +844,10 @@ _build_iso() {
-publisher "${iso_publisher}" \
-preparer "prepared by ${app_name}" \
"${xorrisofs_options[@]}" \
- -output "${out_dir}/${img_name}" \
+ -output "${out_dir}/${image_name}" \
"${isofs_dir}/"
_msg_info "Done!"
- du -h -- "${out_dir}/${img_name}"
+ du -h -- "${out_dir}/${image_name}"
}
# Read profile's values from profiledef.sh
@@ -816,14 +871,23 @@ _read_profile() {
packages="$(realpath -- "${packages}")"
pacman_conf="$(realpath -- "${pacman_conf}")"
+ # Resolve paths of files that may reside in the profile's directory
+ if [[ -z "$bootstrap_packages" ]] && [[ -e "${profile}/bootstrap_packages.${arch}" ]]; then
+ bootstrap_packages="${profile}/bootstrap_packages.${arch}"
+ bootstrap_packages="$(realpath -- "${bootstrap_packages}")"
+ pacman_conf="$(realpath -- "${pacman_conf}")"
+ fi
+
cd -- "${OLDPWD}"
fi
}
# Validate set options
_validate_options() {
- local validation_error=0 bootmode
+ local validation_error=0 bootmode _buildmode
local pkg_list_from_file=()
+ local bootstrap_pkg_list_from_file=()
+
_msg_info "Validating options..."
# Check if the package list file exists and read packages from it
if [[ -e "${packages}" ]]; then
@@ -835,8 +899,23 @@ _validate_options() {
fi
else
(( validation_error=validation_error+1 ))
- _msg_error "File '${packages}' does not exist." 0
+ _msg_error "Packages file '${packages}' does not exist." 0
+ fi
+ # Check if packages for the bootstrap image are specified
+ if [[ "${buildmodes[*]}" == *bootstrap* ]]; then
+ if [[ -e "${bootstrap_packages}" ]]; then
+ mapfile -t bootstrap_pkg_list_from_file < \
+ <(sed '/^[[:blank:]]*#.*/d;s/#.*//;/^[[:blank:]]*$/d' "${bootstrap_packages}")
+ bootstrap_pkg_list+=("${bootstrap_pkg_list_from_file[@]}")
+ if (( ${#bootstrap_pkg_list_from_file} < 1 )); then
+ (( validation_error=validation_error+1 ))
+ _msg_error "No package specified in '${bootstrap_packages}'." 0
+ fi
+ else
+ (( validation_error=validation_error+1 ))
+ _msg_error "Bootstrap packages file '${bootstrap_packages}' does not exist." 0
+ fi
fi
# Check if pacman configuration file exists
@@ -844,6 +923,21 @@ _validate_options() {
(( validation_error=validation_error+1 ))
_msg_error "File '${pacman_conf}' does not exist." 0
fi
+
+ # Check if the specified buildmodes are supported
+ for _buildmode in "${buildmodes[@]}"; do
+ if typeset -f "_build_buildmode_${_buildmode}" &> /dev/null; then
+ if typeset -f "_validate_requirements_buildmode_${_buildmode}" &> /dev/null; then
+ "_validate_requirements_buildmode_${_buildmode}"
+ else
+ _msg_warning "Function '_validate_requirements_buildmode_${_buildmode}' does not exist. Validating the requirements of '${_buildmode}' build mode will not be possible."
+ fi
+ else
+ (( validation_error=validation_error+1 ))
+ _msg_error "${_buildmode} is not a valid build mode!" 0
+ fi
+ done
+
# Check if the specified bootmodes are supported
for bootmode in "${bootmodes[@]}"; do
if typeset -f "_make_bootmode_${bootmode}" &> /dev/null; then
@@ -868,6 +962,7 @@ _validate_options() {
(( validation_error=validation_error+1 ))
_msg_error "Unsupported image type: '${airootfs_image_type}'" 0
fi
+
if (( validation_error )); then
_msg_error "${validation_error} errors were encountered while validating the profile. Aborting." 1
fi
@@ -877,6 +972,10 @@ _validate_options() {
# Set defaults and, if present, overrides from mkarchiso command line option parameters
_set_overrides() {
# Set variables that have command line overrides
+ [[ ! -v override_buildmodes ]] || buildmodes=("${override_buildmodes[@]}")
+ if (( "${#buildmodes[@]}" < 1 )); then
+ buildmodes+=('iso')
+ fi
if [[ -v override_work_dir ]]; then
work_dir="$override_work_dir"
elif [[ -z "$work_dir" ]]; then
@@ -896,6 +995,7 @@ _set_overrides() {
fi
pacman_conf="$(realpath -- "$pacman_conf")"
[[ ! -v override_pkg_list ]] || pkg_list+=("${override_pkg_list[@]}")
+ # TODO: allow overriding bootstrap_pkg_list
if [[ -v override_iso_label ]]; then
iso_label="$override_iso_label"
elif [[ -z "$iso_label" ]]; then
@@ -927,7 +1027,6 @@ _set_overrides() {
[[ -n "$arch" ]] || arch="$(uname -m)"
[[ -n "$airootfs_image_type" ]] || airootfs_image_type="squashfs"
[[ -n "$iso_name" ]] || iso_name="${app_name}"
- [[ -n "$img_name" ]] || img_name="${iso_name}-${iso_version}-${arch}.iso"
}
_export_gpg_publickey() {
@@ -935,43 +1034,84 @@ _export_gpg_publickey() {
}
_make_version() {
- local osrelease
- install -d -m 0755 -- "${isofs_dir}/${install_dir}"
- _msg_info "Creating files with iso version..."
- # Write version file to airootfs
- rm -f -- "${airootfs_dir}/version"
- printf '%s\n' "${iso_version}" > "${airootfs_dir}/version"
- # Write version file to ISO 9660
- printf '%s\n' "${iso_version}" > "${isofs_dir}/${install_dir}/version"
- # Write grubenv with version information to ISO 9660
- printf '%.1024s' "$(printf '# GRUB Environment Block\nNAME=%s\nVERSION=%s\n%s' \
- "${iso_name}" "${iso_version}" "$(printf '%0.1s' "#"{1..1024})")" \
- > "${isofs_dir}/${install_dir}/grubenv"
+ local _os_release
+
+ _msg_info "Creating version files..."
+ # Write version file to system installation dir
+ rm -f -- "${pacstrap_dir}/version"
+ printf '%s\n' "${iso_version}" > "${pacstrap_dir}/version"
+
+ if [[ "${buildmode}" == "iso" ]]; then
+ install -d -m 0755 -- "${isofs_dir}/${install_dir}"
+ # Write version file to ISO 9660
+ printf '%s\n' "${iso_version}" > "${isofs_dir}/${install_dir}/version"
+ # Write grubenv with version information to ISO 9660
+ printf '%.1024s' "$(printf '# GRUB Environment Block\nNAME=%s\nVERSION=%s\n%s' \
+ "${iso_name}" "${iso_version}" "$(printf '%0.1s' "#"{1..1024})")" \
+ > "${isofs_dir}/${install_dir}/grubenv"
+ fi
+
# Append IMAGE_ID & IMAGE_VERSION to os-release
- osrelease="$(realpath -- "${airootfs_dir}/etc/os-release")"
- if [[ ! -e "${airootfs_dir}/etc/os-release" && -e "${airootfs_dir}/usr/lib/os-release" ]]; then
- osrelease="$(realpath -- "${airootfs_dir}/usr/lib/os-release")"
+ _os_release="$(realpath -- "${pacstrap_dir}/etc/os-release")"
+ if [[ ! -e "${pacstrap_dir}/etc/os-release" && -e "${pacstrap_dir}/usr/lib/os-release" ]]; then
+ _os_release="$(realpath -- "${pacstrap_dir}/usr/lib/os-release")"
fi
- if [[ "${osrelease}" != "${airootfs_dir}"* ]]; then
- _msg_warning "os-release file '${osrelease}' is outside of valid path."
+ if [[ "${_os_release}" != "${pacstrap_dir}"* ]]; then
+ _msg_warning "os-release file '${_os_release}' is outside of valid path."
else
- [[ ! -e "${osrelease}" ]] || sed -i '/^IMAGE_ID=/d;/^IMAGE_VERSION=/d' "${osrelease}"
- printf 'IMAGE_ID=%s\nIMAGE_VERSION=%s\n' "${iso_name}" "${iso_version}" >> "${osrelease}"
+ [[ ! -e "${_os_release}" ]] || sed -i '/^IMAGE_ID=/d;/^IMAGE_VERSION=/d' "${_os_release}"
+ printf 'IMAGE_ID=%s\nIMAGE_VERSION=%s\n' "${iso_name}" "${iso_version}" >> "${_os_release}"
fi
_msg_info "Done!"
}
_make_pkglist() {
- install -d -m 0755 -- "${isofs_dir}/${install_dir}"
_msg_info "Creating a list of installed packages on live-enviroment..."
- pacman -Q --sysroot "${airootfs_dir}" > "${isofs_dir}/${install_dir}/pkglist.${arch}.txt"
+ case "${buildmode}" in
+ "bootstrap")
+ pacman -Q --sysroot "${pacstrap_dir}" > "${pacstrap_dir}/pkglist.${arch}.txt"
+ ;;
+ "iso")
+ install -d -m 0755 -- "${isofs_dir}/${install_dir}"
+ pacman -Q --sysroot "${pacstrap_dir}" > "${isofs_dir}/${install_dir}/pkglist.${arch}.txt"
+ ;;
+ esac
_msg_info "Done!"
}
-_build_profile() {
+_build_buildmode_bootstrap() {
+ local image_name="${iso_name}-bootstrap-${iso_version}-${arch}.tar.gz"
+ local run_once_mode="${buildmode}"
+ local buildmode_packages="${bootstrap_packages}"
+ local buildmode_pkg_list=()
+
+ # Set the package list to use
+ buildmode_pkg_list=("${bootstrap_pkg_list[@]}")
+ # Set up essential directory paths
+ pacstrap_dir="${work_dir}/${arch}/bootstrap/root.${arch}"
+ [[ -d "${work_dir}" ]] || install -d -- "${work_dir}"
+ install -d -m 0755 -o 0 -g 0 -- "${pacstrap_dir}"
+
+ [[ "${quiet}" == "y" ]] || _show_config
+ _run_once _make_pacman_conf
+ _run_once _make_packages
+ _run_once _make_version
+ _run_once _make_pkglist
+ _run_once _cleanup_pacstrap_dir
+ _run_once _build_bootstrap_image
+}
+
+_build_buildmode_iso() {
+ local image_name="${iso_name}-${iso_version}-${arch}.iso"
+ local run_once_mode="${buildmode}"
+ local buildmode_packages="${packages}"
+ local buildmode_pkg_list=()
# Set up essential directory paths
- airootfs_dir="${work_dir}/${arch}/airootfs"
+ pacstrap_dir="${work_dir}/${arch}/airootfs"
isofs_dir="${work_dir}/iso"
+ # Set the package list to use
+ buildmode_pkg_list=("${pkg_list[@]}")
+
# Create working directory
[[ -d "${work_dir}" ]] || install -d -- "${work_dir}"
# Write build date to file or if the file exists, read it from there
@@ -990,12 +1130,22 @@ _build_profile() {
_run_once _make_customize_airootfs
_run_once _make_pkglist
_make_bootmodes
- _run_once _cleanup_airootfs
+ _run_once _cleanup_pacstrap_dir
_run_once _prepare_airootfs_image
- _run_once _build_iso
+ _run_once _build_iso_image
+}
+
+# build all buildmodes
+_build() {
+ local buildmode
+ local run_once_mode="build"
+
+ for buildmode in "${buildmodes[@]}"; do
+ _run_once "_build_buildmode_${buildmode}"
+ done
}
-while getopts 'p:C:L:P:A:D:w:o:g:vh?' arg; do
+while getopts 'p:C:L:P:A:D:w:m:o:g:vh?' arg; do
case "${arg}" in
p) read -r -a override_pkg_list <<< "${OPTARG}" ;;
C) override_pacman_conf="${OPTARG}" ;;
@@ -1004,6 +1154,7 @@ while getopts 'p:C:L:P:A:D:w:o:g:vh?' arg; do
A) override_iso_application="${OPTARG}" ;;
D) override_install_dir="${OPTARG}" ;;
w) override_work_dir="${OPTARG}" ;;
+ m) read -r -a override_buildmodes <<< "${OPTARG}" ;;
o) override_out_dir="${OPTARG}" ;;
g) override_gpg_key="${OPTARG}" ;;
v) override_quiet="n" ;;
@@ -1032,6 +1183,6 @@ profile="$(realpath -- "${1}")"
_read_profile
_set_overrides
_validate_options
-_build_profile
+_build
# vim:ts=4:sw=4:et: