Last active
June 17, 2021 22:31
-
-
Save prurigro/e9d105a91f5424a89d26 to your computer and use it in GitHub Desktop.
An overlayfs-based chroot management script for deployable arch build environments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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