#!/usr/bin/env bash # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. ## Common functions # # Cleanup and quit if error cleanup_and_quit () { # If any paramters are passed we will assume it to be an error [[ -n $1 ]] && printf "\e[1;31m<#>\e[0m $*\e[0m\n" >&2 if [[ $ARKDEP_NO_CLEANUP -eq 1 ]]; then printf 'Cleanup disabled, not running cleanup\n' exit 1 fi umount -Rl $build_image_mountpoint rm $build_image rm -rf $build_image_mountpoint # Quit program if argument provided to function if [[ -n $1 ]]; then exit 1 fi # Otherwise just quit, there is no error exit 0 } ## Set common variables # declare -r build_image='/var/tmp/arkdep-build.img' declare -r build_image_mountpoint='/var/tmp/arkdep-build' declare -r workdir="$build_image_mountpoint/rootfs" declare -r variant="$1" declare -r build_image_size='15G' # Minimum required storage in KiB declare -r minimum_available_root_storage='31457280' # 30G declare -r minimum_available_var_storage='20971520' # 20G if [[ -v ARKDEP_CONFIGS ]]; then declare -r configsdir="$ARKDEP_CONFIGS" else declare -r configsdir="$(readlink -m ./arkdep-build.d/)" fi # Before we continue setting variables, lets first ensure the configsdir actually exist # We do this now to give better error reporting to the user if [[ ! -d $configsdir ]]; then printf "\e[1;31m<#>\e[0m\e[1m $configsdir does not exist, are you located inside of the configuration directory's parent directory?\n\e[0m" exit 1 fi declare -r variantdir="$configsdir/$variant" declare -r type="$(cat $(readlink -m $variantdir/type) 2> /dev/null || (printf '\e[1;31m<#>\e[0m\e[1m Failed to get build type\n\e[0m'; exit 1))" if [[ -v ARKDEP_OUTPUT_TARGET ]]; then declare -r output_target="$ARKDEP_OUTPUT_TARGET" else declare -r output_target="$(pwd)/target" fi ## Set common functions # # Generate a 42 character long random string, used for generating psuedo-random image names # Unless overwritten with $ARKDEP_CUSTOM_NAME gen_random_string () { if [[ -v ARKDEP_CUSTOM_NAME ]]; then random=$ARKDEP_CUSTOM_NAME else random=$(openssl rand -hex 100 | head -c 42) fi printf "${random}\n" } # Generate image name # If name template exists, use it, otherwise generate random string if [[ -f $variantdir/name.sh ]]; then declare -r image_name=$(source $variantdir/name.sh) else declare -r image_name=$(gen_random_string) fi ## Error checking # # Quit if not root if [[ ! $EUID -eq 0 ]]; then printf '\e[1;31m<#>\e[0m\e[1m This program has to be run as root\n\e[0m' exit 1 fi # Check if all dependencies are installed, quit if not for prog in btrfs pacstrap; do if ! command -v $prog > /dev/null; then printf "\e[1;31m<#>\e[0m\e[1m Failed to locate $prog, ensure it is installed\e[0m\n" exit 1 fi done # Check if requested variant exists if [[ ! -d $variantdir ]]; then printf '\e[1;31m<#>\e[0m\e[1m The requested variant does not exist\e[0m\n' exit 1 fi # Run the storage check only if we are not building a migration if [[ $type != 'migration' ]]; then # Ensure we have the required storage available on both /var/tmp and root declare root_storage_available=($(df --output=avail /)) root_storage_available=${root_storage_available[1]} declare var_storage_available=($(df --output=avail /var/tmp)) var_storage_available=${var_storage_available[1]} if [[ $root_storage_available -lt $minimum_available_root_storage ]]; then printf 'Not enough storage available on root to export image\n' exit 1 fi if [[ $var_storage_available -lt $minimum_available_var_storage ]]; then printf 'Not enough storage available on var to create image\n' exit 1 fi fi ## Variants # # Build migration type image if [[ $type == 'migration' ]]; then printf '\e[1;34m-->\e[0m\e[1m Started migration image build\e[0m\n' # Create output directory structure mkdir -p $output_target/$image_name # Copy migration contents to compression target dir cp -v $variantdir/migration.sh $output_target/$image_name/$image_name-migration.sh || cleanup_and_quit 'No primary migration script found' # Copy migration related files if they are provided if [[ -d $variantdir/migration ]]; then cp -rv $variantdir/migration $output_target/$image_name/$image_name-migration fi # Compress migration files tar -cv -I 'zstd -12 -T0 ' -f $output_target/$image_name.tar.zst -C $output_target/$image_name . # We can just exit, no need to do a cleanup exit 0 fi # Build archlinux type image if [[ $type == 'archlinux' ]]; then # Ensure bootstrap.list exists, if not error and quit # This is the mimimum requirement to perform a build and this checked first if [[ ! -e $variantdir/bootstrap.list ]]; then printf "\e[1;31m<#>\e[0m\e[1m The required file 'bootstrap.list' is not preset in $variantdir\e[0m\n" exit 1 fi printf '\e[1;34m-->\e[0m\e[1m Started Arch linux image build\e[0m\n' printf '\e[1;34m-->\e[0m\e[1m Creating disk image\e[0m\n' fallocate -l $build_image_size $build_image || cleanup_and_quit "Failed to create disk image at $build_image" mkfs.btrfs -f $build_image || cleanup_and_quit "Failed to partition $build_image" printf "\e[1;34m-->\e[0m\e[1m Mounting $build_image at $workdir\e[0m\n" # The data is compressed to minimize writes to the disk, the actual export does not maintain this compression mount -m -t btrfs -o loop,compress=zstd $build_image $build_image_mountpoint || cleanup_and_quit "Failed to mount disk image to $workdir" # Create temporary Btrfs subvolume printf "\e[1;34m-->\e[0m\e[1m Creating temporary Btrfs subvolumes at $workdir\e[0m\n" btrfs subvolume create $workdir/ || cleanup_and_quit "Failed to create btrfs subvolume $workdir" mount --bind $workdir $workdir || cleanup_and_exit "Failed to bind mount disk $workdir" btrfs subvolume create $workdir/etc || cleanup_and_quit "Failed to create btrfs subvolume $workdir/etc" btrfs subvolume create $workdir/var || cleanup_and_quit "Failed to create btrfs subvolume $workdir/var" # Read base package list and install base system readarray bootstrap_packages < $variantdir/bootstrap.list # Stores package lists from dependency variants declare bootstrap_packages_depends=() # Load depends lists if present if [[ -e $variantdir/depends.list ]]; then # We only have to set depends_variants once, it is later not set again in other # tasks utilizing dependencies readarray depends_variants < $variantdir/depends.list # Depends list without code comments declare depends_variants_clean=() for depend in ${depends_variants[@]}; do # If line starts with escape character, ignore it [[ $depend == \#* ]] && continue # If line is whitespace, ignore it [[ ${depend//[$'\t\r\n']} == '' ]] && continue # Append to depends clean, so we can use it again later depends_variants_clean+=(${depend%%#*}) done # Validate if all depends actually exist for depend in ${depends_variants_clean[@]}; do if [[ ! -d $configsdir/$depend ]]; then printf "\e[1;31m<#>\e[0m\e[1m $depend is defined as a dependency in depends.list but it could not be found\n\e[0m" [[ ! depends_error -eq 1 ]] && declare -r depends_error=1 fi done # If one of the defined depends is missing, error and quit if [[ $depends_error -eq 1 ]]; then cleanup_and_quit 'One or more variant dependencies could not be found in arkdep-build.d' fi # Loop dependency list and generate package list for depend in ${depends_variants_clean[@]}; do # Only run if bootstrap.list exists [[ ! -f $configsdir/${depend%%#*}/bootstrap.list ]] && continue readarray -O${#bootstrap_packages_depends[@]} bootstrap_packages_depends < $configsdir/${depend%%#*}/bootstrap.list done fi # Used to store bootstrap packages list without escape characters and whitespaces declare bootstrap_packages_clean=() # Process bootstrap package lists, remove code comments for bootstrap_package in "${bootstrap_packages[@]}" "${bootstrap_packages_depends[@]}"; do # If line starts with escape character, ignore it [[ $bootstrap_package == \#* ]] && continue # If line is whitespace, ignore it [[ ${bootstrap_package//[$'\t\r\n']} == '' ]] && continue # Remove escape character at end of line and add to bootstrap_packages_clean bootstrap_packages_clean+=(${bootstrap_package%%#*}) done printf '\e[1;34m-->\e[0m\e[1m Installing base packages\e[0m\n' # If pacman.conf is available in overlay, use it if [[ -f $variantdir/pacman.conf ]]; then pacstrap -c -C $variantdir/pacman.conf $workdir ${bootstrap_packages_clean[@]} || cleanup_and_quit 'Failed to install secondary package list' cp -v $variantdir/pacman.conf $workdir/etc/pacman.conf else pacstrap -c $workdir ${bootstrap_packages_clean[@]} || cleanup_and_quit 'Failed to bootstrap system' fi # If overlay directory exists in variant copy it's contents to the temporary subvolume if [[ -d $variantdir/overlay/post_bootstrap ]]; then printf '\e[1;34m-->\e[0m\e[1m Copying overlay/post_bootstrap to root\e[0m\n' cp -rv $variantdir/overlay/post_bootstrap/* $workdir/ fi # If we have a depends list, copy overlays from these dependencies, also handle code comments if [[ -e $variantdir/depends.list ]]; then for depend in ${depends_variants_clean[@]}; do # Only run if post_bootstrap exists [[ ! -d $configsdir/$depend/overlay/post_bootstrap ]] && continue printf "\e[1;34m-->\e[0m\e[1m Copying $depend/overlay/post_bootstrap to root\e[0m\n" cp -rv $configsdir/$depend/overlay/post_bootstrap/* $workdir/ done fi # Run post_bootstrap script if exists if [[ -f $variantdir/extensions/post_bootstrap.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Running post_bootstrap extension\e[0m\n' (source $variantdir/extensions/post_bootstrap.sh) fi # Read package list and install secondary system components, skip if not used if [[ -e $variantdir/package.list ]]; then printf '\e[1;34m-->\e[0m\e[1m Installing secondary packages\e[0m\n' # Mount the pacman cache mount --bind /var/cache/pacman/pkg $workdir/var/cache/pacman/pkg # Read package list and install readarray packages < $variantdir/package.list # Used to store packages list without escape characters and whitespaces declare packages_clean=() # Stores package lists from dependency variants declare packages_depends=() # Load dependency package lists if present, also handle code comments if [[ -e $variantdir/depends.list ]]; then for depend in ${depends_variants_clean[@]}; do # Only run if package.list exists [[ ! -f $configsdir/$depend/package.list ]] && continue readarray -O${#packages_depends[@]} packages_depends < $configsdir/$depend/package.list done fi # Used to store bootstrap packages list without escape characters and whitespaces declare packages_clean=() # Process package lists, remove code comments for package in "${packages[@]}" "${packages_depends[@]}"; do # If line starts with escape character, ignore it [[ $package == \#* ]] && continue # If line is whitespace, ignore it [[ ${package//[$'\t\r\n']} == '' ]] && continue # Remove escape character at end of line and add to packages_clean packages_clean+=(${package%%#*}) done # Install packages to new root arch-chroot $workdir pacman -S --noconfirm ${packages_clean[@]} || cleanup_and_quit 'Failed to install packages' # Unmount pacman cache umount -l $workdir/var/cache/pacman/pkg fi # If postinstall overlay directory exists in variant copy it's contents to the temporary subvolume if [[ -d $variantdir/overlay/post_install ]]; then printf '\e[1;34m-->\e[0m\e[1m Copying overlay/post_install to root\e[0m\n' cp -rv $variantdir/overlay/post_install/* $workdir/ fi # If we have a depends list, copy overlays from these dependencies if [[ -e $variantdir/depends.list ]]; then for depend in ${depends_variants_clean[@]}; do # Only run if post_install exists [[ ! -d $configsdir/$depend/overlay/post_install ]] && continue printf "\e[1;34m-->\e[0m\e[1m Copying $depend/overlay/post_install to root\e[0m\n" cp -rv $configsdir/$depend/overlay/post_install/* $workdir/ done fi # Run post_install script if exists if [[ -f $variantdir/extensions/post_install.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Running post_install extension\e[0m\n' (source $variantdir/extensions/post_install.sh) fi # Remove subvolumes created by systemd [[ -d $workdir/var/lib/portables ]] && printf '\e[1;34m-->\e[0m\e[1m Removing systemd subvolume var/lib/portables\e[0m\n' btrfs subvolume delete $workdir/var/lib/portables [[ -d $workdir/var/lib/machines ]] && printf '\e[1;34m-->\e[0m\e[1m Removing systemd subvolume var/lib/machines\e[0m\n' btrfs subvolume delete $workdir/var/lib/machines # Make /usr/local symlink in var printf '\e[1;34m-->\e[0m\e[1m Moving dirs to var and creating symlinks\e[0m\n' mv $workdir/usr/local $workdir/var/usrlocal || cleanup_and_quit 'Failed to move usr/local to var/usrlocal' ln -sv ../var/usrlocal $workdir/usr/local || cleanup_and_quit 'Failed to create usrlocal symlink' # Opt symlink mv $workdir/opt $workdir/var/ || cleanup_and_quit 'Failed to move opt to var/opt' ln -sv var/opt $workdir/opt || cleanup_and_quit 'Failed to create opt symlink' # srv symlink mv $workdir/srv $workdir/var/srv || cleanup_and_quit 'Failed to move srv to var/srv' ln -sv var/srv $workdir/srv || cleanup_and_quit 'Failed to create srv symlink' # mnt symlink mv $workdir/mnt $workdir/var/mnt || cleanup_and_quit 'Failed to move mnt to var/mnt' ln -sv var/mnt $workdir/mnt || cleanup_and_quit 'Failed to create mnt symlink' printf '\e[1;34m-->\e[0m\e[1m Creating mountpoints for shared subvolumes\e[0m\n' # Remove the folders to ensure they are empty rm -rf $workdir/root rm -rf $workdir/var/lib/flatpak # Ensure these folder exist mkdir -pv $workdir/root mkdir -pv $workdir/arkdep mkdir -pv $workdir/var/lib/flatpak printf '\e[1;34m-->\e[0m\e[1m Moving passwd, shadow and group files to usr/lib\e[0m\n' # Create second passwd, group and shadow file in usr/lib and configure for file in passwd group shadow; do grep -v "^root:" $workdir/etc/$file > $workdir/usr/lib/$file done # Remove all users except for root, is typically overwritten by user overlay but # may be used during os installation as a template for file in passwd group shadow; do grep "^root:" $workdir/etc/$file > $workdir/etc/$file-tmp mv $workdir/etc/$file-tmp $workdir/etc/$file done # Ensure passwd/group/shadow permissions are set properly chmod 600 $workdir/etc/shadow $workdir/usr/lib/shadow chmod 644 $workdir/etc/{passwd,group} $workdir/usr/lib/{passwd,group} # # nss-switch.conf is added using the overlay # # Remove passwd/group/shadow backup files rm $workdir/etc/{passwd-,shadow-,group-} printf '\e[1;34m-->\e[0m\e[1m Moving CPU microcode to usr/lib\e[0m\n' # Move CPU firmware to /usr/lib if present mv $workdir/boot/*-ucode.img $workdir/usr/lib/ # Make subvolume read-only printf '\e[1;34m-->\e[0m\e[1m Adding read-only property to subvolumes\e[0m\n' btrfs property set -ts $workdir ro true || cleanup_and_quit 'Failed to set root to read-only' btrfs property set -ts $workdir/etc ro true || cleanup_and_quit 'Failed to set etc to read-only' btrfs property set -ts $workdir/var ro true || cleanup_and_quit 'Failed to set var to read-only' # Create dir for storing the images mkdir -p $output_target/$image_name # Add update script, utilized to perform minor system changes and updates if [[ -f $variantdir/update.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Including update script\e[0m\n' cp -v $variantdir/update.sh $output_target/$image_name/$image_name-update.sh || cleanup_and_quit 'Failed copying update script to image' fi # Generate package list pacman -Q --root=$workdir > $output_target/$image_name.pkgs # Write subvolume to image printf '\e[1;34m-->\e[0m\e[1m Creating images\e[0m\n' btrfs send -f $output_target/$image_name/$image_name-rootfs.img $workdir btrfs send -f $output_target/$image_name/$image_name-etc.img $workdir/etc btrfs send -f $output_target/$image_name/$image_name-var.img $workdir/var if [[ ! -v ARKDEP_NO_TAR ]]; then printf '\e[1;34m-->\e[0m\e[1m Compressing images\e[0m\n' tar -cv -I 'zstd -12 -T0 ' -f $output_target/$image_name.tar.zst -C $output_target/$image_name . fi if [[ -f $variantdir/extensions/post_build.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Running post_build extension\e[0m\n' (source $variantdir/extensions/post_build.sh) fi cleanup_and_quit fi # Build debian type image if [[ $type == 'debian' ]]; then # Get repo configuration if [[ ! -s $variant_dir/apt.conf ]]; then cleanup_and_quite 'apt.conf expected but is empty or not found' else declare -r apt_conf=($(cat $variantdir/apt.conf 2> /dev/null)) # 0. Repo URL (http://deb.debian.org/debian) # 1. Suite (focal, sid, unstable etc..) declare -r deb_repo=${apt_conf[0]} declare -r deb_suite=${apt_conf[1]} fi printf '\e[1;34m-->\e[0m\e[1m Started Debian image build\e[0m\n' printf '\e[1;34m-->\e[0m\e[1m Creating disk image\e[0m\n' fallocate -l $build_image_size $build_image || cleanup_and_quit "Failed to create disk image at $build_image" mkfs.btrfs -f $build_image || cleanup_and_quit "Failed to partition $build_image" printf "\e[1;34m-->\e[0m\e[1m Mounting $build_image at $workdir\e[0m\n" # The data is compressed to minimize writes to the disk, the actual export does not maintain this compression mount -m -t btrfs -o loop,compress=zstd $build_image $build_image_mountpoint || cleanup_and_quit "Failed to mount disk image to $workdir" # Create temporary Btrfs subvolume printf "\e[1;34m-->\e[0m\e[1m Creating temporary Btrfs subvolumes at $workdir\e[0m\n" btrfs subvolume create $workdir/ || cleanup_and_quit "Failed to create btrfs subvolume $workdir)" mount --bind $workdir $workdir || cleanup_and_exit "Failed to bind mount disk $workdir" btrfs subvolume create $workdir/etc || cleanup_and_quit "Failed to create btrfs subvolume $workdir/etc)" btrfs subvolume create $workdir/var || cleanup_and_quit "Failed to create btrfs subvolume $workdir/var)" printf '\e[1;34m-->\e[0m\e[1m Installing base packages\e[0m\n' # TODO: Do not hard code arch [[ ! -d /var/cache/arkdep-debootstrap ]] && mkdir -p /var/cache/apt/archives DEBIAN_FRONTEND=noninteractive debootstrap \ --cache-dir=/var/cache/apt/archives \ $deb_suite \ $workdir \ $deb_repo || cleanup_and_quit 'Failed to bootstrap' # If overlay directory exists in variant copy it's contents to the temporary subvolume if [[ -d $variantdir/overlay/post_bootstrap ]]; then printf '\e[1;34m-->\e[0m\e[1m Copying overlay/post_bootstrap to root\e[0m\n' cp -rv $variantdir/overlay/post_bootstrap/* $workdir/ fi # Load dependency package lists if present if [[ -e $variantdir/depends.list ]]; then # We only have to set depends_variants once, it is later not set again in other # tasks utilizing dependencies readarray depends_variants < $variantdir/depends.list # Depends list without code comments declare depends_variants_clean=() # If we have a depends list, copy overlays from these dependencies for depend in ${depends_variants[@]}; do # If line starts with escape character, ignore it [[ $bootstrap_package == \#* ]] && continue # If line is whitespace, ignore it [[ ${bootstrap_package//[$'\t\r\n']} == '' ]] && continue # Append to depends clean, so we can use it again later depends_variants_clean+=(${depend%%#*}) # Only run if bootstrap.list exists [[ ! -d $configsdir/${depend%%#*}/post_bootstrap ]] && continue printf "\e[1;34m-->\e[0m\e[1m Copying ${depend%%#*}/overlay/post_bootstrap to root\e[0m\n" cp -rv $configsdir/${depend%%#*}/overlay/post_bootstrap/* $workdir/ done fi # Run post_bootstrap script if exists if [[ -f $variantdir/extensions/post_bootstrap.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Running post_bootstrap extension\e[0m\n' (source $variantdir/extensions/post_bootstrap.sh) fi # Read package list and install secondary system components, skip if not used if [[ -f $variantdir/package.list ]]; then printf '\e[1;34m-->\e[0m\e[1m Installing secondary packages\e[0m\n' # Mount deb package cache inside of new root mount --bind /var/cache/apt/archives $workdir/var/cache/apt/archives # Read package list and install readarray packages < $variantdir/package.list # Used to store packages list without escape characters and whitespaces declare packages_clean=() # Stores package lists from dependency variants declare packages_depends=() # Load dependency package lists if present if [[ -e $variantdir/depends.list ]]; then # We only have to set depends_variants once, it is later not set again in other # tasks utilizing dependencies readarray depends_variants < $variantdir/depends.list for depend in ${depends_variants_clean[@]}; do [[ ! -f $configsdir/$depend/package.list ]] && continue # If line starts with escape character, ignore it [[ $depend == \#* ]] && continue # If line is whitespace, ignore it [[ ${depend//[$'\t\r\n']} == '' ]] && continue readarray -O${#packages_depends[@]} packages_depends < $configsdir/$depend/package.list done fi # Process package lists, remove code comments for package in "${packages[@]}" "${packages_depends}"; do # If line starts with escape character, ignore it [[ $package == \#* ]] && continue # If line is whitespace, ignore it [[ ${package//[$'\t\r\n']} == '' ]] && continue # Remove escape character at end of line and add to packages_clean packages_clean+=(${package%%#*}) done # Install packages to new root # TODO: Keep using arch-chroot?` DEBIAN_FRONTEND=noninteractive arch-chroot $workdir apt-get update || cleanup_and_quit 'Failed to apt update' DEBIAN_FRONTEND=noninteractive arch-chroot $workdir apt-get install -y ${packages_clean[@]} || cleanup_and_quit 'Failed to install packages' umount -l $workdir/var/cache/apt/archives fi # If postinstall overlay directory exists in variant copy it's contents to the temporary subvolume if [[ -d $variantdir/overlay/post_install ]]; then printf '\e[1;34m-->\e[0m\e[1m Copying overlay/post_install to root\e[0m\n' cp -rv $variantdir/overlay/post_install/* $workdir/ fi # If we have a depends list, copy overlays from these dependencies if [[ -e $variantdir/depends.list ]]; then for depend in ${depends_variants_clean[@]}; do [[ ! -d $configsdir/$depend/overlay/post_install ]] && continue printf "\e[1;34m-->\e[0m\e[1m Copying $depend/overlay/post_install to root\e[0m\n" cp -rv $variantdir/overlay/post_install/* $workdir/ done fi # Run post_install script if exists if [[ -f $variantdir/extensions/post_install.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Running post_install extension\e[0m\n' (source $variantdir/extensions/post_install.sh) fi # Remove subvolumes created by systemd [[ -d $workdir/var/lib/portables ]] && printf '\e[1;34m-->\e[0m\e[1m Removing systemd subvolume var/lib/portables\e[0m\n' btrfs subvolume delete $workdir/var/lib/portables [[ -d $workdir/var/lib/machines ]] && printf '\e[1;34m-->\e[0m\e[1m Removing systemd subvolume var/lib/machines\e[0m\n' btrfs subvolume delete $workdir/var/lib/machines # Make /usr/local symlink in var printf '\e[1;34m-->\e[0m\e[1m Moving dirs to var and creating symlinks\e[0m\n' mv $workdir/usr/local $workdir/var/usrlocal || cleanup_and_quit 'Failed to move usr/local to var/usrlocal' ln -sv ../var/usrlocal $workdir/usr/local || cleanup_and_quit 'Failed to create usrlocal symlink' # Opt symlink mv $workdir/opt $workdir/var/ || cleanup_and_quit 'Failed to move opt to var/opt' ln -sv var/opt $workdir/opt || cleanup_and_quit 'Failed to create opt symlink' # srv symlink mv $workdir/srv $workdir/var/srv || cleanup_and_quit 'Failed to move srv to var/srv' ln -sv var/srv $workdir/srv || cleanup_and_quit 'Failed to create srv symlink' # mnt symlink mv $workdir/mnt $workdir/var/mnt || cleanup_and_quit 'Failed to move mnt to var/mnt' ln -sv var/mnt $workdir/mnt || cleanup_and_quit 'Failed to create mnt symlink' printf '\e[1;34m-->\e[0m\e[1m Creating mountpoints for shared subvolumes\e[0m\n' # Remove the folders to ensure they are empty rm -rf $workdir/root rm -rf $workdir/var/lib/flatpak # Ensure these folder exist mkdir -pv $workdir/root mkdir -pv $workdir/arkdep mkdir -pv $workdir/var/lib/flatpak printf '\e[1;34m-->\e[0m\e[1m Moving passwd, shadow and group files to usr/lib\e[0m\n' # Create second passwd, group and shadow file in usr/lib and configure for file in passwd group shadow; do grep -v "^root:" $workdir/etc/$file > $workdir/usr/lib/$file done # Remove all users except for root, is typically overwritten by user overlay but # may be used during os installation as a template for file in passwd group shadow; do grep "^root:" $workdir/etc/$file > $workdir/etc/$file-tmp mv $workdir/etc/$file-tmp $workdir/etc/$file done # Ensure passwd/group/shadow permissions are set properly chmod 600 $workdir/etc/shadow $workdir/usr/lib/shadow chmod 644 $workdir/etc/{passwd,group} $workdir/usr/lib/{passwd,group} # # nss-switch.conf is added using the overlay # # Remove passwd/group/shadow backup files rm $workdir/etc/{passwd-,shadow-,group-} printf '\e[1;34m-->\e[0m\e[1m Moving kernel to usr/lib/modules/\e[0m\n' # Move vmlinuz from boot to modules # Get kernel version and vmlinuz location declare vmlinuz_path=$(readlink -f $workdir/vmlinuz) echo $vmlinuz_path vmlinuz_path=${vmlinuz_path//$workdir} echo $vmlinuz_path declare vmlinuz_version=${vmlinuz_path//\/boot\/vmlinuz-} echo $vmlinuz_version mv $workdir/$vmlinuz_path $workdir/usr/lib/modules/$vmlinuz_version/vmlinuz || cleanup_and_quit 'Failed to move kernel to modules' #printf '\e[1;34m-->\e[0m\e[1m Moving CPU microcode to usr/lib\e[0m\n' # Move CPU firmware to /usr/lib if present # TODO: Figure out how to properly handle this #mv $workdir/boot/*-ucode.img $workdir/usr/lib/ # Make subvolume read-only printf '\e[1;34m-->\e[0m\e[1m Adding read-only property to subvolumes\e[0m\n' btrfs property set -ts $workdir ro true || cleanup_and_quit 'Failed to set root to read-only' btrfs property set -ts $workdir/etc ro true || cleanup_and_quit 'Failed to set etc to read-only' btrfs property set -ts $workdir/var ro true || cleanup_and_quit 'Failed to set var to read-only' # Create dir for storing the images mkdir -p $output_target/$image_name # Add update script, utilized to perform minor system changes and updates if [[ -f $variantdir/update.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Including update script\e[0m\n' cp -v $variantdir/update.sh $output_target/$image_name/$image_name-update.sh || cleanup_and_quit 'Failed copying update script to image' fi # TODO: Generate package list # Write subvolume to image printf '\e[1;34m-->\e[0m\e[1m Creating images\e[0m\n' btrfs send -f $output_target/$image_name/$image_name-rootfs.img $workdir btrfs send -f $output_target/$image_name/$image_name-etc.img $workdir/etc btrfs send -f $output_target/$image_name/$image_name-var.img $workdir/var if [[ ! -v ARKDEP_NO_TAR ]]; then printf '\e[1;34m-->\e[0m\e[1m Compressing images\e[0m\n' tar -cv -I 'zstd -12 -T0 ' -f $output_target/$image_name.tar.zst -C $output_target/$image_name . fi if [[ -f $variantdir/extensions/post_build.sh ]]; then printf '\e[1;34m-->\e[0m\e[1m Running post_build extension\e[0m\n' (source $variantdir/extensions/post_build.sh) fi cleanup_and_quit fi # No valid variant was found printf 'No valid type set in configuration\n' exit 2