Skip to content

Instantly share code, notes, and snippets.

@necrose99
Forked from prurigro/archroot.sh
Created May 18, 2016 02:37
Show Gist options
  • Save necrose99/cb0e38e23477cf6ca6ec4a1b84c57d4a to your computer and use it in GitHub Desktop.
Save necrose99/cb0e38e23477cf6ca6ec4a1b84c57d4a to your computer and use it in GitHub Desktop.

Revisions

  1. @prurigro prurigro revised this gist Mar 26, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions archroot.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.17
    # Version 1.18
    #
    # Written by Kevin MacMartin
    # Released under the MIT license
    @@ -409,7 +409,7 @@ function build_package {
    fi

    # Set the source directory permissions to that of the $build_user
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - -c "chown -R $build_user:users '/home/$build_user/$build_pkgname'"
    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" ]] \
  2. @prurigro prurigro revised this gist Mar 26, 2015. 1 changed file with 8 additions and 5 deletions.
    13 changes: 8 additions & 5 deletions archroot.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.16
    # Version 1.17
    #
    # Written by Kevin MacMartin
    # Released under the MIT license
    @@ -436,10 +436,10 @@ function build_package {
    # 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'"

    # Copy the built package to the current directory with the current directory's user:group
    # 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 $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/home/$build_user/$build_pkgname/${pkg/*\/}"
    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
    @@ -452,14 +452,17 @@ function install_pkg {

    # Install the list of packages passed in the arguments list
    for pkg in "${install_pkglist[@]}"; do
    install --owner=root --group=root "$pkg" "$ARCHROOT/root/tmp/${pkg/*\/}"
    if TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/tmp/${pkg/*\/}"; then
    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
  3. @prurigro prurigro revised this gist Mar 20, 2015. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion archroot.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.15
    # Version 1.16
    #
    # Written by Kevin MacMartin
    # Released under the MIT license
    @@ -513,6 +513,9 @@ 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

  4. @prurigro prurigro revised this gist Mar 20, 2015. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions archroot.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.14
    # Version 1.15
    #
    # Written by Kevin MacMartin
    # Released under the MIT license
    @@ -293,13 +293,13 @@ function umount_chroot {

    # Check each mount point and exit with an error if are in use
    for mntpoint in "${mntpoint_list[@]}"; do
    [[ $(fuser -u "$mntpoint" 2>&1) ]] \
    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"
    umount -R "$mntpoint" >/dev/null
    done

    # Free the memory used by the mount point list
  5. @prurigro prurigro revised this gist Mar 20, 2015. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions archroot.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.13
    # Version 1.14
    #
    # Written by Kevin MacMartin
    # Released under the MIT license
    @@ -71,17 +71,19 @@ done < "$mtab"
    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
    (( $2 == 0 )) \
    [[ -n "$2" ]] && (( $2 == 0 )) \
    || exit 1
    }

    # Display a formatted message
    function msg {
    printf '%s %s\n' "$c_b==>" "$c_w$1$c_c"
    }
  6. @prurigro prurigro revised this gist Feb 27, 2015. 1 changed file with 18 additions and 19 deletions.
    37 changes: 18 additions & 19 deletions archroot.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.12
    # Version 1.13
    #
    # Written by Kevin MacMartin
    # Released under the MIT license
    @@ -76,18 +76,18 @@ done < "$mtab"
    }

    # Send an error to stderr and exit unless 0 is passed as an argument
    function error() {
    function error {
    printf "%s %s\n" "$c_r==> ERROR:" "$c_w$1$c_c" >&2
    (( $2 == 0 )) \
    || exit 1
    }

    function msg() {
    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() {
    function overlaymnt_check {
    while read -r; do
    [[ "$REPLY" =~ overlay\ $ARCHROOT\ overlay ]] \
    && return 0
    @@ -96,7 +96,7 @@ function overlaymnt_check() {
    }

    # overlaymod_check: return true if the overlay module is loaded, otherwise return false
    function overlaymod_check() {
    function overlaymod_check {
    while read -r; do
    [[ "$REPLY" =~ ^overlay\ ]] \
    && return 0
    @@ -105,7 +105,7 @@ function overlaymod_check() {
    }

    # pacmanpkg_check: return true if the pacman package is installed, otherwise return false
    function pacmanpkg_check() {
    function pacmanpkg_check {
    for pkg in /var/lib/pacman/local/*; do
    pkg="${pkg%-*-*}"
    [[ "${pkg/*\/}" = "$1" ]] \
    @@ -115,7 +115,7 @@ function pacmanpkg_check() {
    }

    # copy_to: copy a text file from one location to another
    function copy_to() {
    function copy_to {
    while read -r; do
    printf '%s\n' "$REPLY"
    done \
    @@ -124,12 +124,12 @@ function copy_to() {
    }

    # Output ArchAssault Repo line for pacman.conf
    function aarepo() {
    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() {
    function read_pkgbuild {
    # Read in variables from the PKGBUILD
    local printing=1
    eval "$(while read -r; do
    @@ -151,7 +151,7 @@ function read_pkgbuild() {
    }

    # setup_overlay: create/recreate the lowerdir of the overlay
    function setup_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
    @@ -224,7 +224,7 @@ function setup_overlay() {
    }

    # mount_chroot: mounts the overlay @ $ARCHROOT
    function mount_chroot() {
    function mount_chroot {
    # Return successfully if the chroot is already mounted
    overlaymnt_check \
    && return 0
    @@ -271,7 +271,7 @@ function mount_chroot() {
    }

    # umount_chroot: unmounts the currently mounted overlay (first unmounting the chroot if necessary)
    function umount_chroot() {
    function umount_chroot {
    # Set the $_chroot_type to the currently mounted type or return if nothing is mounted
    declare -a mntpoint_list=()

    @@ -310,7 +310,7 @@ function umount_chroot() {
    }

    # update_overlay: updates packages in the lowerdir of the overlay
    function update_overlay() {
    function update_overlay {
    # Unmount the chroot if it's already mounted
    umount_chroot

    @@ -328,7 +328,7 @@ function update_overlay() {
    }

    # reset_chroot: deletes then recreates the upperdir, resetting any changes made on top of lowerdir
    function reset_chroot() {
    function reset_chroot {
    # Unmount if mounted
    umount_chroot

    @@ -340,7 +340,7 @@ function reset_chroot() {
    }

    # status_info: displays chroot status information
    function status_info() {
    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 ]] && {
    @@ -357,7 +357,7 @@ function status_info() {
    }

    # build_package: builds a source package
    function build_package() {
    function build_package {
    # Mount if not already mounted
    mount_chroot

    @@ -444,7 +444,7 @@ function build_package() {
    }

    # install_pkg: installs binary packages in the chroot
    function install_pkg() {
    function install_pkg {
    # Mount if not already mounted
    mount_chroot

    @@ -461,7 +461,7 @@ function install_pkg() {
    }

    # help: display usage information and available commands
    function help() {
    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) "
    @@ -488,7 +488,6 @@ function help() {
    [[ -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
  7. @prurigro prurigro revised this gist Feb 27, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion archroot.sh
    Original file line number Diff line number Diff line change
    @@ -470,7 +470,7 @@ function help() {
    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-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'
  8. @prurigro prurigro revised this gist Feb 27, 2015. 1 changed file with 260 additions and 166 deletions.
    426 changes: 260 additions & 166 deletions archroot.sh
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.10
    # Version 1.12
    #
    # Written by Kevin MacMartin
    # Released under the MIT license
    @@ -17,9 +17,9 @@

    # Unset variables we don't expect
    while read -r; do
    [[ "$REPLY" =~ ^(ARCHROOT|ARCHROOT_LOWER|ARCHROOT_UPPER|PATH|SHELL|TERM|PWD|SHLVL|_)= ]] \
    || unset "${REPLY/=*}"
    done < <(env)
    [[ ! "$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"}
    @@ -30,42 +30,97 @@ 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_v=$'\e[1;35m' # VIOLET
    c_m=$'\e[1;35m' # VIOLET
    c_w=$'\e[1;37m' # WHITE
    c_c=$'\e[0m' # DISABLES COLOUR
    }

    # Set a compatible termcap
    export chroot_term=xterm-256color
    # 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
    (( $2 == 0 )) \
    || exit 1
    }

    # Select the chroot method based on whether a session is already active
    if mount | egrep -q "$ARCHROOT/root/(sys|dev|run)"; then
    chroot_cmd='chroot'
    else
    chroot_cmd='arch-chroot'
    fi
    nspawn_cmd='arch-nspawn'
    function msg() {
    printf '%s %s\n' "$c_b==>" "$c_w$1$c_c"
    }

    # Send an error to stderr
    function error() {
    printf "$c_b%s$c_c $c_r%s$c_c%s\n" '==>' 'ERROR' ": $1" >&2
    exit 1
    # 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
    @@ -75,24 +130,35 @@ function aarepo() {

    # read_pkgbuild: safely read in unset non-array variables
    function read_pkgbuild() {
    # Read in currently-unset non-array variables and the source array from the PKGBUILD
    pkgbuild=$(sed '/^.*\(\).*{[^}]*$/,/^[^{]]*}/d;s|^\s*||' "$1")
    while read -r var; do
    egrep -q "^${var/=*}=" < <(env) \
    || eval "$var"
    done < <(egrep '^[a-zA-Z_][[:alnum:]_]*\s*=\s*[^(]' <<< "$pkgbuild")
    eval "$(egrep -o ' ((make)?depends|source)\s*=\s*\([^)]*\)' <<< "$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"
    local pacman_tmpconf=/tmp/pacman.archroot.conf
    local makepkg_tmpconf=/tmp/makepkg.archroot.conf

    # Error and exit if the chroot is mounted
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && error "Unmount the $c_v$chroot_type$c_c chroot before recreating the overlay"
    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" ]] \
    @@ -110,17 +176,24 @@ function setup_overlay() {
    # Create temp pacman.conf and makepkg.conf based on $chroot_type
    case "$chroot_type" in
    default)
    cp /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
    cp /usr/share/devtools/pacman-extra.conf "$pacman_tmpconf"
    copy_to /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
    copy_to /usr/share/devtools/pacman-extra.conf "$pacman_tmpconf"
    ;;
    multilib)
    cp /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
    cp /usr/share/devtools/pacman-multilib.conf "$pacman_tmpconf"
    copy_to /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
    copy_to /usr/share/devtools/pacman-multilib.conf "$pacman_tmpconf"
    ;;
    i686)
    cp /usr/share/devtools/makepkg-i686.conf "$makepkg_tmpconf"
    cp /usr/share/devtools/pacman-extra.conf "$pacman_tmpconf"
    sed -i 's|Architecture = auto|Architecture = i686|' "$pacman_tmpconf"
    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

    @@ -129,30 +202,32 @@ function setup_overlay() {

    # 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"
    [[ -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"
    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
    printf '%s\n' "$c_b==>$c_c Finished creating the $c_v$chroot_type$c_c chroot"
    msg "Finished creating the $c_m$chroot_type$c_w chroot"
    }

    # mount_chroot: mounts the overlay @ $ARCHROOT
    function mount_chroot() {
    # Mount the overlay for the requested chroot if not already mounted
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && return
    # Return successfully if the chroot is already mounted
    overlaymnt_check \
    && return 0

    # Create $ARCHROOT, $ARCHROOT_UPPER/upperdir and $ARCHROOT_UPPER/workdir
    [[ -d "$ARCHROOT" ]] \
    @@ -164,89 +239,92 @@ function mount_chroot() {

    # 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
    if [[ "$chroot_type" = multilib ]]; then
    [[ -d "$ARCHROOT_LOWER/lowerdir.default/root" ]] && {
    echo -e "$c_b==>$c_c Converting ${c_v}default$c_c to ${c_v}multilib$c_c"
    msg "Converting ${c_m}default$c_w to ${c_m}multilib"
    mv "$ARCHROOT_LOWER/lowerdir.default" "$ARCHROOT_LOWER/lowerdir.multilib"
    cp /usr/share/devtools/pacman-multilib.conf "$ARCHROOT_LOWER/lowerdir.multilib/root/etc/pacman.conf"
    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
    elif [[ "$chroot_type" = default ]]; then
    [[ -d "$ARCHROOT_LOWER/lowerdir.multilib/root" ]] && {
    echo -e "$c_b==>$c_c Converting ${c_v}multilib$c_c to ${c_v}default$c_c"
    msg "Converting ${c_m}multilib$c_w to ${c_m}default"
    mv "$ARCHROOT_LOWER/lowerdir.multilib" "$ARCHROOT_LOWER/lowerdir.default"
    cp /usr/share/devtools/pacman-extra.conf "$ARCHROOT_LOWER/lowerdir.default/root/etc/pacman.conf"
    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_v$chroot_type$c_c chroot needs to be setup before it can be used"
    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 provided it's not already mounted
    mount | egrep -q "^overlay on $ARCHROOT " \
    || mount -t overlay -o "lowerdir=$ARCHROOT_LOWER/lowerdir.$chroot_type,upperdir=$ARCHROOT_UPPER/upperdir.$chroot_type,workdir=$ARCHROOT_UPPER/workdir.$chroot_type" overlay "$ARCHROOT"

    # Display an error if the chroot isn't mounted
    mount | egrep -q "^overlay on $ARCHROOT " \
    || error "Unable to mount the $c_v$chroot_type$c_c chroot @ $c_w$ARCHROOT$c_c"
    # 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"

    # Display a notification stating that the chroot has been mounted
    echo -e "$c_b==>$c_c Successfully mounted the $c_v$chroot_type$c_c chroot @ $c_w$ARCHROOT$c_c"
    # 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
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && local _chroot_type="$(mount | egrep -m 1 "^overlay on $ARCHROOT" | sed 's|^.*lowerdir||;s|^\.||;s|,.*$||')" \
    || return 0

    # The error message displayed under numerous conditions for when something is blocking the umount operation
    local umnt_errortext="Log out and stop accessing the $c_v$_chroot_type$c_c chroot before unmounting"

    # Exit with an error if the root filesystem is in use
    [[ $(fuser -u "$ARCHROOT"/root 2>&1) ]] \
    && error "$umnt_errortext"
    declare -a mntpoint_list=()

    # If the overlay is mounted, begin unmounting each part
    mount | egrep -q "^overlay on $ARCHROOT " && {
    # Unmount directories other than the overlay provided none of them are being accessed
    local mntpoint_list=$(mount | egrep "^[^ ]* on $ARCHROOT" | cut -d ' ' -f 3 | sort --sort=general-numeric | sort -ur | egrep -v "^$ARCHROOT(|/root)$")
    [[ -n "$mntpoint_list" ]] && {
    for mntpoint in "${mntpoint_list[@]}"; do
    [[ $(fuser -u "$mntpoint" 2>&1) ]] \
    && error "$umnt_errortext"
    done
    for mntpoint in "${mntpoint_list[@]}"; do
    umount "$mntpoint"
    done
    while read -r; do
    [[ -z "$_chroot_type" && "$REPLY" =~ overlay\ $ARCHROOT\ overlay ]] && {
    local _chroot_type="${REPLY/*lowerdir\.}"
    _chroot_type="${_chroot_type/,*}"
    }
    umount -R "$ARCHROOT"
    [[ "$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" 2>&1) ]] \
    && error "Log out and stop accessing the $c_m$_chroot_type$c_w chroot before unmounting"
    done

    # Notify about status of the unmount and exit with an error if it was unsuccessful
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && error "Couldn't unmount the $c_v$_chroot_type$c_c chroot"
    echo -e "$c_b==>$c_c Successfully unmounted the $c_v$_chroot_type$c_c chroot"
    }
    # Unmount each mount point
    for mntpoint in "${mntpoint_list[@]}"; do
    umount -R "$mntpoint"
    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

    # Error and exit if the chroot is mounted
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && error "Unmount the $c_v$chroot_type$c_c chroot before updating it"

    # Update the chroot in lowerdir
    # 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
    echo -e "$c_b==>$c_c Finished updating the $c_v$chroot_type$c_c chroot"
    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
    @@ -258,19 +336,24 @@ function reset_chroot() {
    [[ -d "$ARCHROOT_UPPER/upperdir.$chroot_type" ]] \
    && rm -rf "$ARCHROOT_UPPER/upperdir.$chroot_type"
    install -d "$ARCHROOT_UPPER/upperdir.$chroot_type"
    echo -e "$c_b==>$c_c The $c_v$chroot_type$c_c chroot filesystem has been reset"
    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
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && local _chroot_type="$c_v$(mount | egrep -m 1 "^overlay on $ARCHROOT" | sed 's|^.*lowerdir||;s|^\.||;s|,.*$||')$c_c"
    while read -r; do
    [[ -z "$_chroot_type" && "$REPLY" =~ overlay\ $ARCHROOT\ overlay ]] && {
    local _chroot_type="${REPLY/*lowerdir\.}"
    _chroot_type="${_chroot_type/,*}"
    }
    done < "$mtab"

    echo -en "$c_b==>$c_c "
    [[ -n "$_chroot_type" ]] \
    && echo -e "The $_chroot_type chroot is currently: ${c_g}mounted$c_c @ $c_w$ARCHROOT$c_c" \
    || echo -e "The chroot is currently: ${c_r}unmounted$c_c"
    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
    @@ -279,14 +362,14 @@ function build_package() {
    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
    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_w}PKGBUILD$c_c (contains no ${c_v}pkgname$c_c)"
    && error "Invalid ${c_y}PKGBUILD$c_w (contains no pkgname)"
    build_pkgname="$pkgname"

    # Copy the PKGBUILD into the build directory
    @@ -309,9 +392,12 @@ function build_package() {
    && 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>&1 | egrep -o -m 1 '^[^/]*/PKGBUILD' | sed 's|/PKGBUILD||')
    [[ -z "$build_pkgname" ]] \
    && error "$build_srcpkg is not a valid 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.*"
    @@ -322,25 +408,25 @@ function build_package() {

    # Set the source directory permissions to that of the $build_user
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - -c "chown -R $build_user:users '/home/$build_user/$build_pkgname'"
    elif [ -n "$build_srcdir" ]; then
    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_w}PKGBUILD$c_c, ${c_w}source package$c_c or ${c_w}build directory name$c_c"
    && 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 "$build_srcdir does not contain a 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 won't be built"
    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"
    egrep -q '( java-environment |^java-environment | java-environment$|^java-environment$)' <<< "${depends[*]} ${makedepends[*]}" && {
    [[ "${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'
    }
    @@ -349,12 +435,11 @@ function build_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'"

    # Copy the built package to the current directory with the current directory's user:group
    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 $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/home/$build_user/$build_pkgname/$(basename "$pkg")"
    printf '%s\n' "$c_b==>$c_c Copying $pkg"
    local build_pkguser=$(ls -al | egrep ' \.$' | sed 's| *| |g' | cut -d ' ' -f 3)
    local build_pkggroup=$(ls -al | egrep ' \.$' | sed 's| *| |g' | cut -d ' ' -f 4)
    install --owner="$build_pkguser" --group="$build_pkggroup" "$pkg" .
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/home/$build_user/$build_pkgname/${pkg/*\/}"
    msg "Copying $c_y$pkg"
    install --owner="$localuser" --group="$localgroup" "$pkg" .
    done
    }

    @@ -365,70 +450,78 @@ function install_pkg() {

    # Install the list of packages passed in the arguments list
    for pkg in "${install_pkglist[@]}"; do
    install --owner=root --group=root "$pkg" "$ARCHROOT/root/tmp/$(basename "$pkg")"
    if TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/tmp/$(basename "$pkg")"; then
    printf '%s %s %s' "$c_b==>$c_c The package" "$pkg" 'was installed successfully'
    install --owner=root --group=root "$pkg" "$ARCHROOT/root/tmp/${pkg/*\/}"
    if TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/tmp/${pkg/*\/}"; then
    msg "The package $c_y$pkg$c_w was installed successfully"
    else
    printf '%s %s %s' "$c_b==>$c_c ${c_r}ERROR$c_c: The package" "$pkg" 'failed to install' >&2
    error "The package $c_y$pkg$c_w failed to install" 0
    fi
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - -c "rm '/tmp/$(basename "$pkg")'"
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - -c "rm '/tmp/${pkg/*\/}'"
    done
    }

    # help_function: display usage information and available commands
    function help_function() {
    printf '\n%s\n\n' "${c_b}USAGE$c_c: $c_y$script_name $c_d[${c_r}chroot_type$c_d] $c_d[${c_r}OPTION$c_d] $c_d[${c_r}ARGS$c_d]$c_c"
    printf '%s\n' "${c_b}OPTIONS$c_c:"
    printf ' %-47s%s\n' "$c_w--setup-overlay$c_c" 'setup/reset the overlay filesystem'
    printf ' %-47s%s\n\n' "$c_w--update-overlay$c_c" 'update the overlay filesystem'
    printf ' %-61s%s\n' "$c_w-m$c_d|${c_w}--mount-chroot$c_c" 'mount the chroot'
    printf ' %-61s%s\n' "$c_w-u$c_d|${c_w}--umount-chroot$c_c" 'unmount the chroot'
    printf ' %-61s%s\n\n' "$c_w-r$c_d|${c_w}--reset-chroot$c_c" 'reset the chroot'
    printf ' %-110s%s\n' "$c_w-b$c_d|${c_w}--build $c_w[${c_r}srcpkg$c_d|${c_r}PKGDIR$c_d|${c_r}PKGBUILD$c_w]$c_c" 'build a source package or dir in the chroot'
    printf ' %-82s%s\n\n' "$c_w-i$c_d|${c_w}--install $c_w[${c_r}pkglist$c_w]$c_c" 'install a list of packages in the chroot'
    printf ' %-61s%s\n' "$c_w-s$c_d|${c_w}--status$c_c" 'view current chroot status information'
    printf ' %-61s%s\n\n' "$c_w-h$c_d|${c_w}--help$c_c" 'display this usage information and exit'
    printf '%s\n' "${c_b}chroot_typeS$c_c:"
    printf ' %-47s%s\n' "${c_w}default$c_c" "vanilla configuration (${c_v}default$c_c)"
    printf ' %-47s%s\n' "${c_w}multilib$c_c" 'includes the multilib repository'
    printf ' %-47s%s\n\n' "${c_w}i686$c_c" 'uses the i686 architecture'
    exit "$1"
    # 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
    }

    # Check for root and ensure the required files exist
    [[ "$UID" = 0 ]] \
    || error "This script must be run as ${c_w}root$c_c"
    # 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
    if [ -z "$ARCHROOT" ] || [ -z "$ARCHROOT_LOWER" ] || [ -z "$ARCHROOT_UPPER" ]; then
    error "Something went wrong with the mount point variables"
    fi
    [[ -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 the arch-install-scripts package is missing
    [[ $(pacman -Qs arch-install-scripts) ]] \
    || error "The ${c_w}arch-install-scripts$c_c package is missing (run: ${c_v}pacman -S arch-install-scripts$c_c)"

    # Exit with an error if the devtools package is missing
    [[ $(pacman -Qs devtools) ]] \
    || error "The ${c_w}devtools$c_c package is missing (run: ${c_v}pacman -S devtools$c_c)"
    # 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
    lsmod | egrep -q '^overlay' || {
    overlaymod_check || {
    modprobe overlay
    lsmod | egrep -q '^overlay' \
    || error "The ${c_w}overlay$c_c module needs to be loaded"
    overlaymod_check \
    || error "The ${c_y}overlay$c_w module needs to be loaded"
    }

    # Set the default $chroot_type
    chroot_type='default'
    chroot_type=default

    # Parse for command-line arguments
    while (( "$#" )); do
    case "$1" in
    -b|--build)
    archroot_action=build_package
    shift
    if [ -f "$1" ]; then
    if [[ -f "$1" ]]; then
    build_srcpkg="$(readlink -f "$1")"
    else
    build_srcdir="$1"
    @@ -438,9 +531,9 @@ while (( "$#" )); do
    -i|--install)
    archroot_action=install_pkg
    shift
    while [[ -n "$1" ]] && [[ ! "$1" =~ ^- ]]; do
    while [[ -n "$1" && ! "$1" =~ ^- ]]; do
    if [[ -f "$1" ]]; then
    install_pkglist=(${install_pkglist[@]} "$1")
    install_pkglist=( "${install_pkglist[@]}" "$1")
    else
    printf '%s\n' "$1 is not a file"
    fi
    @@ -474,24 +567,25 @@ while (( "$#" )); do
    shift
    ;;
    -h|--help)
    help_function 0
    help
    ;;
    *)
    # Set the type of equal to a member of ${chroot_types[@]}
    if egrep -q "^$(sed 's|-|\\-|g' <<< "$1")$" < <(sed 's| |\n|g' <<< "${chroot_types[@]}"); then
    chroot_type="$1"
    shift
    else
    error "Invalid argument $1"
    fi
    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 0
    exit
    }

    # Mount the overlay for the requested chroot if not already mounted
  9. @prurigro prurigro created this gist Feb 21, 2015.
    501 changes: 501 additions & 0 deletions archroot.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,501 @@
    #!/usr/bin/env bash

    #
    # archroot
    # An overlayfs chroot management script for deployable arch build environments
    #
    # Version 1.10
    #
    # 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|PATH|SHELL|TERM|PWD|SHLVL|_)= ]] \
    || unset "${REPLY/=*}"
    done < <(env)

    # 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 valid chroot types
    chroot_types=('default' 'multilib' 'i686')

    # Name of the main user with passwordless sudo
    build_user=build

    # Set the name of the script
    script_name="${0//*\/}"

    # 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_v=$'\e[1;35m' # VIOLET
    c_w=$'\e[1;37m' # WHITE
    c_c=$'\e[0m' # DISABLES COLOUR
    }

    # Set a compatible termcap
    export chroot_term=xterm-256color

    # Select the chroot method based on whether a session is already active
    if mount | egrep -q "$ARCHROOT/root/(sys|dev|run)"; then
    chroot_cmd='chroot'
    else
    chroot_cmd='arch-chroot'
    fi
    nspawn_cmd='arch-nspawn'

    # Send an error to stderr
    function error() {
    printf "$c_b%s$c_c $c_r%s$c_c%s\n" '==>' 'ERROR' ": $1" >&2
    exit 1
    }

    # 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 currently-unset non-array variables and the source array from the PKGBUILD
    pkgbuild=$(sed '/^.*\(\).*{[^}]*$/,/^[^{]]*}/d;s|^\s*||' "$1")
    while read -r var; do
    egrep -q "^${var/=*}=" < <(env) \
    || eval "$var"
    done < <(egrep '^[a-zA-Z_][[:alnum:]_]*\s*=\s*[^(]' <<< "$pkgbuild")
    eval "$(egrep -o ' ((make)?depends|source)\s*=\s*\([^)]*\)' <<< "$pkgbuild")"
    }

    # 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
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && error "Unmount the $c_v$chroot_type$c_c 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)
    cp /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
    cp /usr/share/devtools/pacman-extra.conf "$pacman_tmpconf"
    ;;
    multilib)
    cp /usr/share/devtools/makepkg-x86_64.conf "$makepkg_tmpconf"
    cp /usr/share/devtools/pacman-multilib.conf "$pacman_tmpconf"
    ;;
    i686)
    cp /usr/share/devtools/makepkg-i686.conf "$makepkg_tmpconf"
    cp /usr/share/devtools/pacman-extra.conf "$pacman_tmpconf"
    sed -i 's|Architecture = auto|Architecture = i686|' "$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
    printf '%s\n' "$c_b==>$c_c Finished creating the $c_v$chroot_type$c_c chroot"
    }

    # mount_chroot: mounts the overlay @ $ARCHROOT
    function mount_chroot() {
    # Mount the overlay for the requested chroot if not already mounted
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && return

    # 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" ]] && {
    echo -e "$c_b==>$c_c Converting ${c_v}default$c_c to ${c_v}multilib$c_c"
    mv "$ARCHROOT_LOWER/lowerdir.default" "$ARCHROOT_LOWER/lowerdir.multilib"
    cp /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" ]] && {
    echo -e "$c_b==>$c_c Converting ${c_v}multilib$c_c to ${c_v}default$c_c"
    mv "$ARCHROOT_LOWER/lowerdir.multilib" "$ARCHROOT_LOWER/lowerdir.default"
    cp /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_v$chroot_type$c_c 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 provided it's not already mounted
    mount | egrep -q "^overlay on $ARCHROOT " \
    || mount -t overlay -o "lowerdir=$ARCHROOT_LOWER/lowerdir.$chroot_type,upperdir=$ARCHROOT_UPPER/upperdir.$chroot_type,workdir=$ARCHROOT_UPPER/workdir.$chroot_type" overlay "$ARCHROOT"

    # Display an error if the chroot isn't mounted
    mount | egrep -q "^overlay on $ARCHROOT " \
    || error "Unable to mount the $c_v$chroot_type$c_c chroot @ $c_w$ARCHROOT$c_c"

    # Display a notification stating that the chroot has been mounted
    echo -e "$c_b==>$c_c Successfully mounted the $c_v$chroot_type$c_c chroot @ $c_w$ARCHROOT$c_c"
    }

    # 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
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && local _chroot_type="$(mount | egrep -m 1 "^overlay on $ARCHROOT" | sed 's|^.*lowerdir||;s|^\.||;s|,.*$||')" \
    || return 0

    # The error message displayed under numerous conditions for when something is blocking the umount operation
    local umnt_errortext="Log out and stop accessing the $c_v$_chroot_type$c_c chroot before unmounting"

    # Exit with an error if the root filesystem is in use
    [[ $(fuser -u "$ARCHROOT"/root 2>&1) ]] \
    && error "$umnt_errortext"

    # If the overlay is mounted, begin unmounting each part
    mount | egrep -q "^overlay on $ARCHROOT " && {
    # Unmount directories other than the overlay provided none of them are being accessed
    local mntpoint_list=$(mount | egrep "^[^ ]* on $ARCHROOT" | cut -d ' ' -f 3 | sort --sort=general-numeric | sort -ur | egrep -v "^$ARCHROOT(|/root)$")
    [[ -n "$mntpoint_list" ]] && {
    for mntpoint in "${mntpoint_list[@]}"; do
    [[ $(fuser -u "$mntpoint" 2>&1) ]] \
    && error "$umnt_errortext"
    done
    for mntpoint in "${mntpoint_list[@]}"; do
    umount "$mntpoint"
    done
    }
    umount -R "$ARCHROOT"

    # Notify about status of the unmount and exit with an error if it was unsuccessful
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && error "Couldn't unmount the $c_v$_chroot_type$c_c chroot"
    echo -e "$c_b==>$c_c Successfully unmounted the $c_v$_chroot_type$c_c chroot"
    }
    }

    # update_overlay: updates packages in the lowerdir of the overlay
    function update_overlay() {
    # Unmount the chroot if it's already mounted
    umount_chroot

    # Error and exit if the chroot is mounted
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && error "Unmount the $c_v$chroot_type$c_c chroot before updating it"

    # Update the chroot in lowerdir
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Syu
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT_LOWER/lowerdir.$chroot_type/root" pacman --noconfirm -Scc

    # Alert the user to let them know the update has completed
    echo -e "$c_b==>$c_c Finished updating the $c_v$chroot_type$c_c 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"
    echo -e "$c_b==>$c_c The $c_v$chroot_type$c_c 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
    mount | egrep -q "^overlay on $ARCHROOT type overlay" \
    && local _chroot_type="$c_v$(mount | egrep -m 1 "^overlay on $ARCHROOT" | sed 's|^.*lowerdir||;s|^\.||;s|,.*$||')$c_c"

    echo -en "$c_b==>$c_c "
    [[ -n "$_chroot_type" ]] \
    && echo -e "The $_chroot_type chroot is currently: ${c_g}mounted$c_c @ $c_w$ARCHROOT$c_c" \
    || echo -e "The chroot is currently: ${c_r}unmounted$c_c"
    }

    # 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_w}PKGBUILD$c_c (contains no ${c_v}pkgname$c_c)"
    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>&1 | egrep -o -m 1 '^[^/]*/PKGBUILD' | sed 's|/PKGBUILD||')
    [[ -z "$build_pkgname" ]] \
    && error "$build_srcpkg is not a valid source package"

    # 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 $nspawn_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_w}PKGBUILD$c_c, ${c_w}source package$c_c or ${c_w}build directory name$c_c"
    [[ ! -f "$ARCHROOT/root/home/$build_user/$build_srcdir/PKGBUILD" ]] \
    && error "$build_srcdir 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 won't 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"
    egrep -q '( java-environment |^java-environment | java-environment$|^java-environment$)' <<< "${depends[*]} ${makedepends[*]}" && {
    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'"

    # Copy the built package to the current directory with the current directory's user:group
    for pkg in "$ARCHROOT/root/home/$build_user/$build_pkgname/"*.pkg.tar*; do
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/home/$build_user/$build_pkgname/$(basename "$pkg")"
    printf '%s\n' "$c_b==>$c_c Copying $pkg"
    local build_pkguser=$(ls -al | egrep ' \.$' | sed 's| *| |g' | cut -d ' ' -f 3)
    local build_pkggroup=$(ls -al | egrep ' \.$' | sed 's| *| |g' | cut -d ' ' -f 4)
    install --owner="$build_pkguser" --group="$build_pkggroup" "$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
    install --owner=root --group=root "$pkg" "$ARCHROOT/root/tmp/$(basename "$pkg")"
    if TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" pacman --noconfirm -U "/tmp/$(basename "$pkg")"; then
    printf '%s %s %s' "$c_b==>$c_c The package" "$pkg" 'was installed successfully'
    else
    printf '%s %s %s' "$c_b==>$c_c ${c_r}ERROR$c_c: The package" "$pkg" 'failed to install' >&2
    fi
    TERM=$chroot_term $nspawn_cmd "$ARCHROOT/root" su - -c "rm '/tmp/$(basename "$pkg")'"
    done
    }

    # help_function: display usage information and available commands
    function help_function() {
    printf '\n%s\n\n' "${c_b}USAGE$c_c: $c_y$script_name $c_d[${c_r}chroot_type$c_d] $c_d[${c_r}OPTION$c_d] $c_d[${c_r}ARGS$c_d]$c_c"
    printf '%s\n' "${c_b}OPTIONS$c_c:"
    printf ' %-47s%s\n' "$c_w--setup-overlay$c_c" 'setup/reset the overlay filesystem'
    printf ' %-47s%s\n\n' "$c_w--update-overlay$c_c" 'update the overlay filesystem'
    printf ' %-61s%s\n' "$c_w-m$c_d|${c_w}--mount-chroot$c_c" 'mount the chroot'
    printf ' %-61s%s\n' "$c_w-u$c_d|${c_w}--umount-chroot$c_c" 'unmount the chroot'
    printf ' %-61s%s\n\n' "$c_w-r$c_d|${c_w}--reset-chroot$c_c" 'reset the chroot'
    printf ' %-110s%s\n' "$c_w-b$c_d|${c_w}--build $c_w[${c_r}srcpkg$c_d|${c_r}PKGDIR$c_d|${c_r}PKGBUILD$c_w]$c_c" 'build a source package or dir in the chroot'
    printf ' %-82s%s\n\n' "$c_w-i$c_d|${c_w}--install $c_w[${c_r}pkglist$c_w]$c_c" 'install a list of packages in the chroot'
    printf ' %-61s%s\n' "$c_w-s$c_d|${c_w}--status$c_c" 'view current chroot status information'
    printf ' %-61s%s\n\n' "$c_w-h$c_d|${c_w}--help$c_c" 'display this usage information and exit'
    printf '%s\n' "${c_b}chroot_typeS$c_c:"
    printf ' %-47s%s\n' "${c_w}default$c_c" "vanilla configuration (${c_v}default$c_c)"
    printf ' %-47s%s\n' "${c_w}multilib$c_c" 'includes the multilib repository'
    printf ' %-47s%s\n\n' "${c_w}i686$c_c" 'uses the i686 architecture'
    exit "$1"
    }

    # Check for root and ensure the required files exist
    [[ "$UID" = 0 ]] \
    || error "This script must be run as ${c_w}root$c_c"

    # Exit with an error if any of the variables aren't defined
    if [ -z "$ARCHROOT" ] || [ -z "$ARCHROOT_LOWER" ] || [ -z "$ARCHROOT_UPPER" ]; then
    error "Something went wrong with the mount point variables"
    fi

    # Exit with an error if the arch-install-scripts package is missing
    [[ $(pacman -Qs arch-install-scripts) ]] \
    || error "The ${c_w}arch-install-scripts$c_c package is missing (run: ${c_v}pacman -S arch-install-scripts$c_c)"

    # Exit with an error if the devtools package is missing
    [[ $(pacman -Qs devtools) ]] \
    || error "The ${c_w}devtools$c_c package is missing (run: ${c_v}pacman -S devtools$c_c)"

    # Try to load the overlay module if it's not loaded, and fail if this is unsuccessful
    lsmod | egrep -q '^overlay' || {
    modprobe overlay
    lsmod | egrep -q '^overlay' \
    || error "The ${c_w}overlay$c_c module needs to be loaded"
    }

    # 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_function 0
    ;;
    *)
    # Set the type of equal to a member of ${chroot_types[@]}
    if egrep -q "^$(sed 's|-|\\-|g' <<< "$1")$" < <(sed 's| |\n|g' <<< "${chroot_types[@]}"); then
    chroot_type="$1"
    shift
    else
    error "Invalid argument $1"
    fi
    ;;
    esac
    done

    # Run the command in $archroot_action if one has been defined
    [[ -n "$archroot_action" ]] && {
    $archroot_action
    exit 0
    }

    # 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