|
|
@@ -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 |
|
|
|