#!/bin/bash # # SPDX-License-Identifier: GPL-3.0-or-later LIBDIR=${LIBDIR:-'/usr/share/artools/lib'} DATADIR=${DATADIR:-'/usr/share/artools'} SYSCONFDIR=${SYSCONFDIR:-'/etc/artools'} # shellcheck source=src/lib/iso/util.sh source "${LIBDIR}"/iso/util.sh # shellcheck source=src/lib/base/message.sh source "${LIBDIR}"/base/message.sh # shellcheck source=src/lib/base/chroot.sh source "${LIBDIR}"/base/chroot.sh # shellcheck source=src/lib/iso/mount.sh source "${LIBDIR}"/iso/mount.sh # shellcheck source=src/lib/iso/services.sh source "${LIBDIR}"/iso/services.sh # shellcheck source=src/lib/iso/calamares.sh source "${LIBDIR}"/iso/calamares.sh # shellcheck source=src/lib/iso/config.sh source "${LIBDIR}"/iso/config.sh # shellcheck source=src/lib/iso/firmware.sh source "${LIBDIR}"/iso/firmware.sh # shellcheck source=src/lib/iso/dracut.sh source "${LIBDIR}"/iso/dracut.sh # shellcheck source=src/lib/iso/initcpio.sh source "${LIBDIR}"/iso/initcpio.sh # shellcheck source=src/lib/iso/grub.sh source "${LIBDIR}"/iso/grub.sh # shellcheck source=src/lib/iso/squash.sh source "${LIBDIR}"/iso/squash.sh # shellcheck source=src/lib/iso/iso.sh source "${LIBDIR}"/iso/iso.sh # shellcheck source=src/lib/iso/profile.sh source "${LIBDIR}"/iso/profile.sh # shellcheck source=src/lib/iso/trap.sh source "${LIBDIR}"/iso/trap.sh clean_up_chroot(){ local path mnt="$1" msg2 "Cleaning [%s]" "${mnt##*/}" path=$mnt/boot if [[ -d "$path" ]]; then find "$path" -name 'initramfs*.img' -delete &> /dev/null fi path=$mnt/var/lib/pacman/sync if [[ -d $path ]];then find "$path" -type f -delete &> /dev/null fi path=$mnt/var/cache/pacman/pkg if [[ -d $path ]]; then find "$path" -type f -delete &> /dev/null fi path=$mnt/var/log if [[ -d $path ]]; then find "$path" -type f -delete &> /dev/null fi path=$mnt/var/tmp if [[ -d $path ]];then find "$path" -mindepth 1 -delete &> /dev/null fi path=$mnt/tmp if [[ -d $path ]];then find "$path" -mindepth 1 -delete &> /dev/null fi # shellcheck disable=2035 find "$mnt" -name '*.pacnew' -name '*.pacsave' -name '*.pacorig' -delete if [[ -f "$mnt/boot/grub/grub.cfg" ]]; then rm "$mnt"/boot/grub/grub.cfg fi if [[ -f "$mnt/etc/machine-id" ]]; then rm "$mnt"/etc/machine-id fi } copy_overlay(){ local src="$1" dest="$2" if [[ -e "$src" ]];then msg2 "Copying [%s] ..." "${src##*/}" cp -LR "$src"/* "$dest" fi } make_rootfs() { if [[ ! -e "${work_dir}"/rootfs.lock ]]; then msg "Prepare [Base installation] (rootfs)" local rootfs="${work_dir}/rootfs" load_pkgs "rootfs" prepare_dir "${rootfs}" local args=() if "${copy_pacconf}"; then args+=(-P) fi basestrap "${basestrap_args[@]}" "${args[@]}" "${rootfs}" "${packages[@]}" --overwrite='*' copy_overlay "${root_overlay}" "${rootfs}" if ! "${HAS_LIVE}"; then configure_chroot "${rootfs}" fi clean_up_chroot "${rootfs}" : > "${work_dir}"/rootfs.lock msg "Done [Base installation] (rootfs)" fi } make_livefs() { if [[ ! -e ${work_dir}/livefs.lock ]]; then msg "Prepare [Live installation] (livefs)" local livefs="${work_dir}/livefs" load_pkgs "livefs" prepare_dir "${livefs}" mount_overlayfs "${livefs}" "${work_dir}" basestrap "${basestrap_args[@]}" "${livefs}" "${packages[@]}" --overwrite='*' copy_overlay "${live_overlay}" "${livefs}" configure_chroot "${livefs}" umount_overlayfs clean_up_chroot "${livefs}" : > "${work_dir}"/livefs.lock msg "Done [Live installation] (livefs)" fi } make_bootfs() { if [[ ! -e ${work_dir}/bootfs.lock ]]; then msg "Prepare [/iso/boot]" load_pkgs "bootfs" prepare_dir "${iso_root}/boot" cp "${work_dir}"/rootfs/boot/vmlinuz* "${iso_root}"/boot/vmlinuz-"${arch}" local bootfs="${work_dir}/bootfs" mount_overlayfs "${bootfs}" "${work_dir}" if "${use_dracut}"; then prepare_initramfs_dracut "${bootfs}" else basestrap "${basestrap_args[@]}" "${bootfs}" "${packages[@]}" prepare_initramfs_mkinitcpio "${bootfs}" fi umount_overlayfs rm -R "${bootfs}" : > "${work_dir}"/bootfs.lock msg "Done [/iso/boot]" fi } make_grub(){ if [[ ! -e ${work_dir}/grub.lock ]]; then msg "Prepare [/iso/boot/grub]" local layer=${work_dir}/rootfs if "${HAS_LIVE}"; then layer=${work_dir}/livefs fi # Ensure artix theme dir exists (prepare_grub hardcodes it) if [[ -d "${work_dir}/rootfs/usr/share/grub/themes/euri" ]] && [[ ! -d "${work_dir}/rootfs/usr/share/grub/themes/artix" ]]; then cp -r "${work_dir}/rootfs/usr/share/grub/themes/euri" "${work_dir}/rootfs/usr/share/grub/themes/artix" fi prepare_grub "${work_dir}/rootfs" "$layer" # Also copy as euri for the installed system if [[ -d "${work_dir}/livefs/usr/share/grub/themes/euri" ]]; then cp -r "${work_dir}/livefs/usr/share/grub/themes/euri" "${iso_root}/boot/grub/themes/" elif [[ -d "${work_dir}/rootfs/usr/share/grub/themes/euri" ]]; then cp -r "${work_dir}/rootfs/usr/share/grub/themes/euri" "${iso_root}/boot/grub/themes/" fi if ${use_dracut}; then configure_grub_dracut else configure_grub_mkinitcpio fi : > "${work_dir}"/grub.lock msg "Done [/iso/boot/grub]" fi } gen_iso_fn(){ local vars=("euri") name vars+=("${INITSYS}") case "${STABILITY}" in gremlins|goblins) vars+=("${STABILITY}") ;; esac vars+=("${ISO_VERSION}") vars+=("${arch}") for n in "${vars[@]}"; do name=${name:-}${name:+-}${n} done printf "%s\n" "$name" } export_gpg_publickey() { key_export="${WORKSPACE_DIR}"/pubkey.gpg gpg --batch --no-armor --output "${key_export}" --export "${GPG_KEY}" } prepare_build(){ load_profile local pac_conf pac_conf=iso-${arch}.conf if [[ "${STABILITY}" != 'stable' ]]; then pac_conf=iso-${STABILITY}-${arch}.conf fi pacman_conf="${DATADIR}/pacman.conf.d/${pac_conf}" if [[ -f "${USER_CONF_DIR}/pacman.conf.d/${pac_conf}" ]]; then pacman_conf="${USER_CONF_DIR}/pacman.conf.d/${pac_conf}" fi iso_file=$(gen_iso_fn).iso iso_label="EURI_$(date +%Y%m)" basestrap_args+=(-C "${pacman_conf}") work_dir=${chroots_iso}/${profile}/artix iso_dir="${ISO_POOL}/${profile}" iso_root=${chroots_iso}/${profile}/iso live_dir=/LiveOS mnt_dir=${chroots_iso}/${profile}/mnt if [[ -n "${GPG_KEY}" ]]; then ${use_dracut} || export_gpg_publickey fi } display_settings(){ msg "OPTIONS:" msg2 "profile: %s" "${profile}" msg2 "INITSYS: %s" "${INITSYS}" [[ -n ${GPG_KEY} ]] && msg2 "GPG_KEY: %s" "${GPG_KEY}" msg "ISO SETTINGS:" msg2 "ISO_VERSION: %s" "${ISO_VERSION}" msg2 "COMPRESSION: %s" "${COMPRESSION}" [[ "${COMPRESSION}" == 'zstd' ]] && msg2 "COMPRESSION_LEVEL: %s" "${COMPRESSION_LEVEL}" msg "BUILD:" show_profile } mk_squash(){ make_sfs "${work_dir}/rootfs" if [[ -d "${work_dir}/livefs" ]]; then make_sfs "${work_dir}/livefs" fi } mk_iso(){ touch "${iso_root}/.artix" msg "Making bootable image" # Sanity checks [[ ! -d "${iso_root}" ]] && return 1 if [[ -f "${iso_dir}/${iso_file}" ]]; then msg2 "Removing existing bootable image..." rm -rf "${iso_dir:?}/${iso_file}" fi assemble_iso chown -R "${owner}:$(id --group "${owner}")" "${iso_dir}" } mk_boot(){ run_safe "make_bootfs" run_safe "make_grub" } mk_chroots(){ run_safe "make_rootfs" if "${HAS_LIVE}"; then run_safe "make_livefs" fi } build(){ msg "Start building [%s]" "${profile}" if ${clean_first};then for copy in "${work_dir}"/*; do [[ -d $copy ]] || continue msg2 "Deleting chroot copy '%s'..." "$(basename "${copy}")" lock 9 "$copy.lock" "Locking chroot copy '%s'" "$copy" subvolume_delete_recursive "${copy}" rm -rf --one-file-system "${copy}" done lock_close 9 rm -rf --one-file-system "${work_dir}" msg "Deleting isoroot [%s] ..." "${iso_root##*/}" rm -rf --one-file-system "${iso_root}" fi if ${chroot_only}; then mk_chroots warning "Continue squash: %s -p %s -sc ..." "${cmd}" "${profile}" exit 1 elif ${boot_only}; then mk_boot warning "Continue iso: %s -p %s -zc ..." "${cmd}" "${profile}" exit 1 elif ${squash_only}; then mk_squash warning "Continue boot: %s -p %s -bc ..." "${cmd}" "${profile}" exit 1 elif ${iso_only}; then [[ ! -d ${work_dir} ]] && die "Create chroot: %s -p %s -x" "${cmd}" "${profile}" mk_iso else mk_chroots mk_boot mk_squash mk_iso fi msg "Finished building [%s]" "${profile}" } clean_first=true pretend=false chroot_only=false iso_only=false persist=false use_dracut=false squash_only=false boot_only=false copy_pacconf=false INITSYS='dinit' basestrap_args=(-GMc) cmd=${0##*/} owner=${SUDO_USER:-$USER} profile='base' chroots_iso="${CHROOTS_DIR}/buildiso" arch=${ARCH} usage() { printf 'Usage: %s [options]\n' "${cmd}" printf ' -p Profile [default: %s]\n' "${profile}" printf ' -r Chroots directory\n' printf ' [default: %s]\n' "${chroots_iso}" printf ' -R Build stability\n' printf ' [default: %s]\n' "${STABILITY}" printf ' -a Build arch\n' printf ' [default: %s]\n' "${arch}" printf ' -t Target directory\n' printf ' [default: %s]\n' "${ISO_POOL}" printf ' -i Init system to use\n' printf ' [default: %s]\n' "${INITSYS}" printf ' -g The gpg key for img signing\n' printf ' [default: none]\n' printf ' -m Set SquashFS image mode to persistence\n' printf ' -c Disable clean work dir\n' printf ' -x Build chroot only\n' printf ' -s Squash chroot only\n' printf ' -b Generate iso boot only\n' printf ' -z Generate iso only\n' printf ' Requires pre built images (-x)\n' printf ' -d Use dracut instead of mkinitcpio for iso initramfs\n' printf ' -w Copy the pacman.conf used to the rootfs\n' printf ' -q Query settings and pretend build\n' printf ' -h This help\n' printf '\n' printf '\n' exit "$1" } orig_args=("$@") opts='p:r:R:t:i:g:a:czsbxwmdqh' while getopts "${opts}" arg; do case "${arg}" in p) profile="$OPTARG" ;; a) arch="$OPTARG" ;; R) STABILITY="$OPTARG" ;; r) chroots_iso="$OPTARG" ;; t) ISO_POOL="$OPTARG" ;; i) INITSYS="$OPTARG" ;; g) GPG_KEY="$OPTARG" ;; c) clean_first=false ;; x) chroot_only=true ;; z) iso_only=true ;; s) squash_only=true ;; b) boot_only=true ;; m) persist=true ;; d) use_dracut=true ;; w) copy_pacconf=true ;; q) pretend=true ;; h|?) usage 0 ;; esac done shift $(( OPTIND - 1 )) prepare_build ${pretend} && display_settings && exit 1 check_root "" "${BASH_SOURCE[0]}" "${orig_args[@]}" prepare_dir "${mnt_dir}" prepare_dir "${iso_dir}" prepare_dir "${iso_root}" prepare_traps build