Skip to content

Instantly share code, notes, and snippets.

@prurigro
Last active June 17, 2021 22:31
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save prurigro/e9d105a91f5424a89d26 to your computer and use it in GitHub Desktop.
Save prurigro/e9d105a91f5424a89d26 to your computer and use it in GitHub Desktop.
An overlayfs-based chroot management script for deployable arch build environments
#!/usr/bin/env bash
#
# archroot
# An overlayfs chroot management script for deployable arch build environments
#
# Version 1.18
#
# Written by Kevin MacMartin
# Released under the MIT license
#
# Requirements:
# linux>=3.18
# arch-install-scripts
# devtools
#
# Unset variables we don't expect
while read -r; do
[[ ! "$REPLY" =~ ^(ARCHROOT|ARCHROOT_LOWER|ARCHROOT_UPPER|BASH[^=]*|EUID|PATH|PPID|PWD|SHELL|SHELLOPTS|SHLVL|TERM|UID|_)= && "$REPLY" =~ ^[^=\ ][^=\ ]*= ]] \
&& unset "${BASH_REMATCH[0]%=*}"
done < <(set -o posix ; set)
# The location of the mount point for overlay chroots
ARCHROOT=${ARCHROOT:="$HOME/archroot"}
# The location of the filesystems that contain the clean chroot environments
ARCHROOT_LOWER=${ARCHROOT_LOWER:="$ARCHROOT-overlay"}
# The location of the filesystems that mount ontop of the lowerdir filesystems
ARCHROOT_UPPER=${ARCHROOT_UPPER:="$ARCHROOT-overlay"}
# List of packages required to run archroot
required_packages=('arch-install-scripts' 'coreutils' 'devtools' 'kmod' 'psmisc' 'tar' 'util-linux')
# List of valid chroot types
chroot_types=('default' 'multilib' 'i686')
# Name of the main user with passwordless sudo
build_user=build
# Location of the mtab file
mtab=/etc/mtab
# Location of the modules file
modules=/proc/modules
# Set the name of the script
script_name="${0//*\/}"
# Set a compatible termcap
chroot_term=xterm-256color
# Set the nspawn command
nspawn_cmd=arch-nspawn
# Set the chroot command based on whether a session is active
chroot_cmd=arch-chroot
while read -r; do
[[ "$REPLY" =~ $ARCHROOT/root/(sys|dev|run) ]] && {
chroot_cmd=chroot
break
}
done < "$mtab"
# Colour scheme
[[ -t 1 ]] && {
c_d=$'\e[1;30m' # DARK GREY
c_r=$'\e[1;31m' # RED
c_g=$'\e[1;32m' # GREEN
c_y=$'\e[1;33m' # YELLOW
c_b=$'\e[1;34m' # BLUE
c_m=$'\e[1;35m' # VIOLET
c_t=$'\e[1;36m' # TEAL
c_w=$'\e[1;37m' # WHITE
c_c=$'\e[0m' # DISABLES COLOUR
}
# Send an error to stderr and exit unless 0 is passed as an argument
function error {
printf "%s %s\n" "$c_r==> ERROR:" "$c_w$1$c_c" >&2
[[ -n "$2" ]] && (( $2 == 0 )) \
|| exit 1
}
# Display a formatted message
function msg {
printf '%s %s\n' "$c_b==>" "$c_w$1$c_c"
}
# overlaymnt_check: eturn true if the overlay is mounted and false if it is not
function overlaymnt_check {
while read -r; do
[[ "$REPLY" =~ overlay\ $ARCHROOT\ overlay ]] \
&& return 0
done < $mtab
return 1
}
# overlaymod_check: return true if the overlay module is loaded, otherwise return false
function overlaymod_check {
while read -r; do
[[ "$REPLY" =~ ^overlay\ ]] \
&& return 0
done < $modules
return 1
}
# pacmanpkg_check: return true if the pacman package is installed, otherwise return false
function pacmanpkg_check {
for pkg in /var/lib/pacman/local/*; do
pkg="${pkg%-*-*}"
[[ "${pkg/*\/}" = "$1" ]] \
&& return 0
done
return 1
}
# copy_to: copy a text file from one location to another
function copy_to {
while read -r; do
printf '%s\n' "$REPLY"
done \
< "$1" \
> "$2"
}
# Output ArchAssault Repo line for pacman.conf
function aarepo {
printf '\n%s\n%s\n' '[archassault]' 'Server = https://repo.archassault.org/$repo/$repo/os/$arch'
}
# read_pkgbuild: safely read in unset non-array variables
function read_pkgbuild {
# Read in variables from the PKGBUILD
local printing=1
eval "$(while read -r; do
case "$printing" in
1)
if [[ "$REPLY" =~ ^\ *[a-zA-Z]*\(\)\ *\{ ]]; then
printing=0
else
[[ ! "$REPLY" =~ ^\ *$ ]] \
&& printf '%s\n' "$REPLY"
fi
;;
0)
[[ "$REPLY" =~ ^[^\{\}]*\} ]] \
&& printing=1
;;
esac
done < "$1")"
}
# setup_overlay: create/recreate the lowerdir of the overlay
function setup_overlay {
# Define locations for the temporary config files
local pacman_tmpconf=/tmp/pacman.archroot.conf
local makepkg_tmpconf=/tmp/makepkg.archroot.conf
# Error and exit if the chroot is mounted
overlaymnt_check \
&& error "Unmount the $c_m$chroot_type$c_w chroot before recreating the overlay"
# Remove any overlay directories that exist and create fresh ones
[[ -d "$ARCHROOT_LOWER/lowerdir.$chroot_type" ]] \
&& rm -rf "$ARCHROOT_LOWER/lowerdir.$chroot_type"
install -d "$ARCHROOT_LOWER/lowerdir.$chroot_type"
[[ -d "$ARCHROOT_UPPER/upperdir.$chroot_type" ]] \
&& rm -rf "$ARCHROOT_UPPER/upperdir.$chroot_type"
install -d "$ARCHROOT_UPPER/upperdir.$chroot_type"
[[ -d "$ARCHROOT_UPPER/workdir.$chroot_type" ]] \
&& rm -rf "$ARCHROOT_UPPER/workdir.$chroot_type"
install -d "$ARCHROOT_UPPER/workdir.$chroot_type"
# Create temp pacman.conf and makepkg.conf based on $chroot_type
case "$chroot_type" in
default)
copy_to /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
copy_to /usr/share/devtools/pacman-extra.conf "$pacman_tmpconf"
;;
multilib)
copy_to /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
copy_to /usr/share/devtools/pacman-multilib.conf "$pacman_tmpconf"
;;
i686)
copy_to /usr/share/devtools/makepkg-i686.conf "$makepkg_tmpconf"
while read -r; do
[[ "$REPLY" =~ ^Architecture[^=]*= ]] && {
printf '%s %s\n' "${BASH_REMATCH[0]}" 'i686'
continue
}
printf '%s\n' "$REPLY"
done \
< /usr/share/devtools/pacman-extra.conf \
> "$pacman_tmpconf"
;;
esac
# Add the ArchAssault repo to the temp pacman.conf
aarepo >> "$pacman_tmpconf"
# Run mkarchroot with temp pacman.conf and makepkg.conf configs
mkarchroot -C "$pacman_tmpconf" -M "$makepkg_tmpconf" "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" base-devel
[[ -f "$pacman_tmpconf" ]] \
&& rm "$pacman_tmpconf"
[[ -f "$makepkg_tmpconf" ]] \
&& rm "$makepkg_tmpconf"
# Download and install the chroot packages
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Syyu
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Scc
# Create the $build_user and configure it for passwordless sudo
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" useradd -m -g users -s /bin/bash build
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" sh -c "printf '%s\n' '$build_user ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/$build_user-nopasswd"
# Add hacks so java-environments work for packages that depend on it
printf '%s\n' '/usr/lib/jvm/default/lib/amd64/jli' > "$ARCHROOT_LOWER/lowerdir.$chroot_type/root/etc/ld.so.conf.d/jvm.conf"
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" ldconfig
# Announce setup completion
msg "Finished creating the $c_m$chroot_type$c_w chroot"
}
# mount_chroot: mounts the overlay @ $ARCHROOT
function mount_chroot {
# Return successfully if the chroot is already mounted
overlaymnt_check \
&& return 0
# Create $ARCHROOT, $ARCHROOT_UPPER/upperdir and $ARCHROOT_UPPER/workdir
[[ -d "$ARCHROOT" ]] \
|| install -d "$ARCHROOT"
[[ -d "$ARCHROOT_UPPER/upperdir.$chroot_type" ]] \
|| install -d "$ARCHROOT_UPPER/upperdir.$chroot_type"
[[ -d "$ARCHROOT_UPPER/workdir.$chroot_type" ]] \
|| install -d "$ARCHROOT_UPPER/workdir.$chroot_type"
# If only default or multilib exists and the other is being mounted, convert one to the other, otherwise alert the user that lowerdir needs to be setup
[[ -d "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" ]] || {
if [[ "$chroot_type" = multilib ]]; then
[[ -d "$ARCHROOT_LOWER/lowerdir.default/root" ]] && {
msg "Converting ${c_m}default$c_w to ${c_m}multilib"
mv "$ARCHROOT_LOWER/lowerdir.default" "$ARCHROOT_LOWER/lowerdir.multilib"
printf '%s\n' "$(</usr/share/devtools/pacman-multilib.conf)" > "$ARCHROOT_LOWER/lowerdir.multilib/root/etc/pacman.conf"
aarepo >> "$ARCHROOT_LOWER/lowerdir.multilib/root/etc/pacman.conf"
}
elif [[ "$chroot_type" = default ]]; then
[[ -d "$ARCHROOT_LOWER/lowerdir.multilib/root" ]] && {
msg "Converting ${c_m}multilib$c_w to ${c_m}default"
mv "$ARCHROOT_LOWER/lowerdir.multilib" "$ARCHROOT_LOWER/lowerdir.default"
printf '%s\n' "$(</usr/share/devtools/pacman-extra.conf)" > "$ARCHROOT_LOWER/lowerdir.default/root/etc/pacman.conf"
aarepo >> "$ARCHROOT_LOWER/lowerdir.default/root/etc/pacman.conf"
}
else
error "The overlay for the $c_m$chroot_type$c_w chroot needs to be setup before it can be used"
fi
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Syy
}
# Mount the overlay
mount -t overlay -o "lowerdir=$ARCHROOT_LOWER/lowerdir.$chroot_type,upperdir=$ARCHROOT_UPPER/upperdir.$chroot_type,workdir=$ARCHROOT_UPPER/workdir.$chroot_type" overlay "$ARCHROOT"
# Check that the chroot is mounted and announce success or failure
overlaymnt_check && {
msg "Successfully mounted the $c_m$chroot_type$c_w chroot @ $c_y$ARCHROOT"
return 0
}
error "Unable to mount the $c_m$chroot_type$c_w chroot @ $c_y$ARCHROOT"
}
# umount_chroot: unmounts the currently mounted overlay (first unmounting the chroot if necessary)
function umount_chroot {
# Set the $_chroot_type to the currently mounted type or return if nothing is mounted
declare -a mntpoint_list=()
# If the overlay is mounted, begin unmounting each part
while read -r; do
[[ -z "$_chroot_type" && "$REPLY" =~ overlay\ $ARCHROOT\ overlay ]] && {
local _chroot_type="${REPLY/*lowerdir\.}"
_chroot_type="${_chroot_type/,*}"
}
[[ "$REPLY" =~ ^overlay\ $ARCHROOT[^\ ]* && "${BASH_REMATCH[0]}" =~ $ARCHROOT[^\ ]* ]] \
&& mntpoint_list=( "${BASH_REMATCH[0]}" "${mntpoint_list[@]}" )
done < "$mtab"
# Return successfully if the chroot is already unmounted
[[ -z "${mntpoint_list[*]}" ]] \
&& return 0
# Check each mount point and exit with an error if are in use
for mntpoint in "${mntpoint_list[@]}"; do
fuser -u "$mntpoint" >/dev/null 2>&1 \
&& error "Log out and stop accessing the $c_m$_chroot_type$c_w chroot before unmounting"
done
# Unmount each mount point
for mntpoint in "${mntpoint_list[@]}"; do
umount -R "$mntpoint" >/dev/null
done
# Free the memory used by the mount point list
unset mntpoint_list
# Exit with an error if any mount points are still mounted
overlaymnt_check \
&& error "Couldn't unmount the $c_m$_chroot_type$c_w chroot"
msg "Successfully unmounted the $c_m$_chroot_type$c_w chroot"
}
# update_overlay: updates packages in the lowerdir of the overlay
function update_overlay {
# Unmount the chroot if it's already mounted
umount_chroot
# Update packages in the chroot
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Syu
# Delete the pacman download cache in the chroot
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Scc
# Update any new config files in the chroot
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" bash -c 'while read -r; do mv "$REPLY" "${REPLY%\.pacnew}"; done < <(find /etc -type f -regextype posix-egrep -regex ".*\.pacnew$")'
# Update the pacman package database in the chroot
TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Syy
# Alert the user to let them know the update has completed
msg "Finished updating the $c_m$chroot_type$c_w chroot"
}
# reset_chroot: deletes then recreates the upperdir, resetting any changes made on top of lowerdir
function reset_chroot {
# Unmount if mounted
umount_chroot
# Delete $ARCHROOT_UPPER/upperdir and create a fresh copy
[[ -d "$ARCHROOT_UPPER/upperdir.$chroot_type" ]] \
&& rm -rf "$ARCHROOT_UPPER/upperdir.$chroot_type"
install -d "$ARCHROOT_UPPER/upperdir.$chroot_type"
msg "The $c_m$chroot_type$c_w chroot filesystem has been reset"
}
# status_info: displays chroot status information
function status_info {
# Set the $_chroot_type to the currently mounted type or null if the chroot isn't mounted
while read -r; do
[[ -z "$_chroot_type" && "$REPLY" =~ overlay\ $ARCHROOT\ overlay ]] && {
local _chroot_type="${REPLY/*lowerdir\.}"
_chroot_type="${_chroot_type/,*}"
}
done < "$mtab"
if [[ -n "$_chroot_type" ]]; then
msg "The $c_m$_chroot_type$c_w chroot is currently: ${c_g}mounted$c_w @ $c_w$ARCHROOT"
else
msg "The chroot is currently: ${c_y}unmounted"
fi
}
# build_package: builds a source package
function build_package {
# Mount if not already mounted
mount_chroot
# Initialize the build environment depending on whether a source package or build directory was passed
if [[ -n "$build_srcpkg" ]]; then
if [[ "${build_srcpkg//*\/}" = 'PKGBUILD' ]]; then
# Load the PKGBUILD variables
read_pkgbuild "$build_srcpkg"
# Set $build_pkgname to $pkgname or fail if unset
[[ -z "$pkgname" ]] \
&& error "Invalid ${c_y}PKGBUILD$c_w (contains no pkgname)"
build_pkgname="$pkgname"
# Copy the PKGBUILD into the build directory
install -Dm644 "$build_srcpkg" "$ARCHROOT/root/home/$build_user/$build_pkgname/PKGBUILD"
# Copy any local sources into the chroot package directory
for source_path in "${source[@]}"; do
source_name="${source_path/*\/}"
if [[ -f "${build_srcpkg%\/*}/$source_name" ]]; then
install -Dm644 "${build_srcpkg%\/*}/$source_name" "$ARCHROOT/root/home/$build_user/$build_pkgname/${source_path/*\/}"
elif [[ "$source_path" =~ ^(bzr|csv|git|hg|darcs|svn)(\+|:) ]] && [[ -d "${build_srcpkg%\/*}/${source_name/[\.#]*}" ]]; then
[[ -d "$ARCHROOT/root/home/$build_user/$build_pkgname/${source_name/[\.#]*}" ]] \
&& TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - -c "rm -rf '/home/$build_user/$build_pkgname/${source_name/[\.#]*}'"
cp -r "${build_srcpkg%\/*}/${source_name/[\.#]*}" "$ARCHROOT/root/home/$build_user/$build_pkgname/"
fi
done
# Copy the .install file if one exists
[[ -n "$install" ]] && [[ -f "${build_srcpkg%\/*}/$install" ]] \
&& install -Dm644 "${build_srcpkg%\/*}/$install" "$ARCHROOT/root/home/$build_user/$build_pkgname/$install"
else
# Set $build_pkgname to the root directory in the archive and error + exit if $build_srcpkg is not a source package
local build_pkgname=$(tar ztf "$build_srcpkg" 2>/dev/null)
if [[ "$build_pkgname" =~ /PKGBUILD ]]; then
build_pkgname="${build_pkgname/\/*}"
else
error "$c_y$build_srcpkg$c_w is not a valid source package"
fi
# Remove any src + pkg folders and source + binary packages if they exist
TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - $build_user -c "rm -rf '/home/$build_user/$build_pkgname/'{pkg,src} '/home/$build_user/$build_pkgname/'*.{pkg,src}.tar.*"
# Extract the source package to the $build_user's home
tar xzf "$build_srcpkg" -C "$ARCHROOT/root/home/$build_user"
fi
# Set the source directory permissions to that of the $build_user
TERM=$chroot_term $chroot_cmd "$ARCHROOT/root" su - -c "chown -R $build_user:users '/home/$build_user/$build_pkgname'"
elif [[ -n "$build_srcdir" ]]; then
# Exit with an error if the build director orthe PKGBUILD it should contain are missing
[[ ! -d "$ARCHROOT/root/home/$build_user/$build_srcdir" ]] \
&& error "The build flag requires a ${c_y}PKGBUILD$c_w, ${c_y}source package$c_w or ${c_y}build directory"
[[ ! -f "$ARCHROOT/root/home/$build_user/$build_srcdir/PKGBUILD" ]] \
&& error "$c_y$build_srcdir$c_w does not contain a PKGBUILD"
# Set $build_pkgname to $build_srcdir and ensure the directory contains a valid package
local build_pkgname="$build_srcdir"
# Remove any src = pkg folders and source + binary packages
TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - $build_user -c "rm -rf '/home/$build_user/$build_pkgname/'{pkg,src} '/home/$build_user/$build_pkgname/'*.{pkg,src}.tar.*"
else
error 'An input error occurred and the package will not be built'
fi
# Load PKGBUILD variables and set the pre/post build hooks for java if java-environment is in depends or makedepends
read_pkgbuild "$ARCHROOT/root/home/$build_user/$build_pkgname/PKGBUILD"
[[ "${depends[*]} ${makedepends[*]}" =~ ( java-environment |^java-environment | java-environment$|^java-environment$) ]] && {
local pre_build='sudo umount /proc; sudo install -d /proc-tmp; sudo mount -t proc proc /proc-tmp; sudo install -d /proc/self; sudo ln -s /proc-tmp/self/fd /proc/self/; '
local post_build='; sudo rm /proc/self/fd; sudo rmdir /proc/self; sudo umount /proc-tmp; sudo rmdir /proc-tmp; sudo mount -t proc proc /proc'
}
# Build the source package
TERM=$chroot_term $chroot_cmd "$ARCHROOT/root" bash --init-file /etc/profile -c "su - $build_user -c '${pre_build}cd ~/$build_pkgname && makepkg -s -f --noconfirm -L --holdver 2>&1$post_build'"
# Install then copy the built package to the current directory
local localuser=$(stat -c %u .) localgroup=$(stat -c %g .)
for pkg in "$ARCHROOT/root/home/$build_user/$build_pkgname/"*.pkg.tar*; do
TERM=$chroot_term $chroot_cmd "$ARCHROOT/root" pacman --noconfirm -U "/home/$build_user/$build_pkgname/${pkg/*\/}"
msg "Copying $c_y$pkg"
install --owner="$localuser" --group="$localgroup" "$pkg" .
done
}
# install_pkg: installs binary packages in the chroot
function install_pkg {
# Mount if not already mounted
mount_chroot
# Install the list of packages passed in the arguments list
for pkg in "${install_pkglist[@]}"; do
package="${pkg/*\/}"
install --owner=root --group=root "$pkg" "$ARCHROOT/root/tmp/$package"
TERM=$chroot_term $chroot_cmd "$ARCHROOT/root" pacman --noconfirm -U "/tmp/$package"
if (( ! $? )); then
msg "The package $c_y$pkg$c_w was installed successfully"
else
error "The package $c_y$pkg$c_w failed to install" 0
fi
TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - -c "rm '/tmp/${pkg/*\/}'"
done
unset package
}
# help: display usage information and available commands
function help {
printf '\n%s\n\n' "USAGE: $c_y$script_name $c_d[${c_m}CHROOT_TYPE$c_d] $c_d[${c_b}OPTION$c_d] $c_d[${c_r}ARGS$c_d]$c_c"
printf '%s\n' "${c_m}CHROOT_TYPES$c_c"
printf ' %-35s%s\n' "${c_w}default$c_c" "vanilla configuration (${c_m}default$c_c) "
printf ' %-35s%s\n' "${c_w}multilib$c_c" 'includes the multilib repository'
printf ' %-35s%s\n\n' "${c_w}i686$c_c" 'uses the i686 architecture'
printf '%s\n' "${c_b}OPTIONS$c_c"
printf ' %-35s%s\n' "$c_w--setup-overlay$c_c" 'setup/reset the overlay filesystem'
printf ' %-35s%s\n' "$c_w--update-overlay$c_c" 'update the overlay filesystem'
printf ' %-70s%s\n' "$c_w-b$c_d|$c_w--build $c_d[${c_r}SRCPKG$c_d]$c_c" 'build from a pkg dir, src.pkg, or PKGBUILD'
printf ' %-70s%s\n' "$c_w-i$c_d|$c_w--install $c_d[${c_r}PKGLIST$c_d]$c_c" 'install a list of packages in the chroot'
printf ' %-49s%s\n' "$c_w-m$c_d|$c_w--mount-chroot$c_c" 'mount the chroot'
printf ' %-49s%s\n' "$c_w-u$c_d|$c_w--umount-chroot$c_c" 'unmount the chroot'
printf ' %-49s%s\n' "$c_w-r$c_d|$c_w--reset-chroot$c_c" 'reset the chroot'
printf ' %-49s%s\n' "$c_w-s$c_d|$c_w--status$c_c" 'view current chroot status information'
printf ' %-49s%s\n\n' "$c_w-h$c_d|$c_w--help$c_c" 'display this usage information and exit'
exit
}
# Exit with an error if the user isn't root
(( UID == 0 )) \
|| error "This script must be run as ${c_y}root"
# Exit with an error if any of the variables aren't defined
[[ -z "$ARCHROOT" || -z "$ARCHROOT_LOWER" || -z "$ARCHROOT_UPPER" ]] \
&& error "$c_y\$ARCHROOT$c_w, \$ARCHROOT_LOWER$c_w and/or $c_y\$ARCHROOT_UPPER are not set"
# Exit with an error if any of the required pacman packages are missing
declare -a missing_packages=()
for dep in "${required_packages[@]}"; do
pacmanpkg_check "$dep" \
|| missing_packages=( ${missing_packages[@]} "$dep" )
done
[[ -n "${missing_packages[*]}" ]] && {
error "the following required packages are missing: $(
for (( x=0; x < ${#missing_packages[@]}; x++ )); do
printf '%s' "$c_m${missing_packages[$x]}$c_c"
(( (( x + 1 )) < ${#missing_packages[@]} )) \
&& printf '%s' ', '
done
)" 1
}
# Try to load the overlay module if it's not loaded, and fail if this is unsuccessful
overlaymod_check || {
modprobe overlay
overlaymod_check \
|| error "The ${c_y}overlay$c_w module needs to be loaded"
}
# Trap kill signals and exit
trap 'exit 1' SIGINT SIGQUIT
# Set the default $chroot_type
chroot_type=default
# Parse for command-line arguments
while (( "$#" )); do
case "$1" in
-b|--build)
archroot_action=build_package
shift
if [[ -f "$1" ]]; then
build_srcpkg="$(readlink -f "$1")"
else
build_srcdir="$1"
fi
shift
;;
-i|--install)
archroot_action=install_pkg
shift
while [[ -n "$1" && ! "$1" =~ ^- ]]; do
if [[ -f "$1" ]]; then
install_pkglist=( "${install_pkglist[@]}" "$1")
else
printf '%s\n' "$1 is not a file"
fi
shift
done
(( ${#install_pkglist[@]} < 0 )) \
&& error "The install flag must be followed by a series of package files"
;;
-s|--status)
archroot_action=status_info
shift
;;
-m|--mount-chroot)
archroot_action=mount_chroot
shift
;;
-u|--umount-chroot)
archroot_action=umount_chroot
shift
;;
-r|--reset-chroot)
archroot_action=reset_chroot
shift
;;
--setup-overlay)
archroot_action=setup_overlay
shift
;;
--update-overlay)
archroot_action=update_overlay
shift
;;
-h|--help)
help
;;
*)
for type in "${chroot_types[@]}"; do
[[ "$1" = "$type" ]] && {
chroot_type="$1"
shift
}
done
[[ -z "$chroot_type" ]] \
&& error "$1 is not a valid argument"
;;
esac
done
# Run the command in $archroot_action if one has been defined
[[ -n "$archroot_action" ]] && {
$archroot_action
exit
}
# Mount the overlay for the requested chroot if not already mounted
mount_chroot
# Enter the chroot
TERM=$chroot_term $chroot_cmd "$ARCHROOT/root" bash --init-file /etc/profile -c "su - $build_user" 2>&1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment