summaryrefslogtreecommitdiff
path: root/src/chroot-tools/librechroot
diff options
context:
space:
mode:
Diffstat (limited to 'src/chroot-tools/librechroot')
-rwxr-xr-xsrc/chroot-tools/librechroot915
1 files changed, 455 insertions, 460 deletions
diff --git a/src/chroot-tools/librechroot b/src/chroot-tools/librechroot
index ae01e51..f7921bf 100755
--- a/src/chroot-tools/librechroot
+++ b/src/chroot-tools/librechroot
@@ -47,66 +47,66 @@ umask 0022
# Usage: detect_chroot_arch $makepkg_conf
detect_chroot_arch()
{
- local makepkg_conf="$1"
- local chroot_arch
+ local makepkg_conf="$1"
+ local chroot_arch
- chroot_arch=$(grep -a '^CARCH=' "$makepkg_conf" 2> /dev/null | cut -d '=' -f 2 | tr -d '"')
- [[ ${chroot_arch} =~ x86_64|i686|armv7h ]] || chroot_arch=$(uname -m)
+ chroot_arch=$(grep -a '^CARCH=' "$makepkg_conf" 2> /dev/null | cut -d '=' -f 2 | tr -d '"')
+ [[ ${chroot_arch} =~ x86_64|i686|armv7h ]] || chroot_arch=$(uname -m)
- echo ${chroot_arch}
+ echo ${chroot_arch}
}
# Usage: make_empty_repo $copydir
make_empty_repo() {
- local copydir=$1
- mkdir -p "${copydir}/repo"
- bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null
- ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db"
+ local copydir=$1
+ mkdir -p "${copydir}/repo"
+ bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null
+ ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db"
}
# Usage: chroot_add_to_local_repo $copydir $pkgfiles...
chroot_add_to_local_repo() {
- local copydir=$1; shift
- mkdir -p "$copydir/repo"
- local pkgfile
- for pkgfile in "$@"; do
- cp "$pkgfile" "$copydir/repo"
- pushd "$copydir/repo" >/dev/null
- repo-add repo.db.tar.gz "${pkgfile##*/}"
- popd >/dev/null
- done
+ local copydir=$1; shift
+ mkdir -p "$copydir/repo"
+ local pkgfile
+ for pkgfile in "$@"; do
+ cp "$pkgfile" "$copydir/repo"
+ pushd "$copydir/repo" >/dev/null
+ repo-add repo.db.tar.gz "${pkgfile##*/}"
+ popd >/dev/null
+ done
}
# Print code to set $rootdir and $copydir; blank them on error
calculate_directories() {
- # Don't assume that CHROOTDIR or CHROOT are set,
- # but assume that COPY is set.
- local rootdir copydir
-
- if [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then
- rootdir="${CHROOTDIR}/${CHROOT}/root"
- else
- rootdir=''
- fi
-
- if [[ ${COPY:0:1} = / ]]; then
- copydir=$COPY
- elif [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then
- copydir="${CHROOTDIR}/${CHROOT}/${COPY}"
- else
- copydir=''
- fi
-
- declare -p rootdir
- declare -p copydir
+ # Don't assume that CHROOTDIR or CHROOT are set,
+ # but assume that COPY is set.
+ local rootdir copydir
+
+ if [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then
+ rootdir="${CHROOTDIR}/${CHROOT}/root"
+ else
+ rootdir=''
+ fi
+
+ if [[ ${COPY:0:1} = / ]]; then
+ copydir=$COPY
+ elif [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then
+ copydir="${CHROOTDIR}/${CHROOT}/${COPY}"
+ else
+ copydir=''
+ fi
+
+ declare -p rootdir
+ declare -p copydir
}
check_mountpoint() {
- local file=$1
- local mountpoint mountopts
- mountpoint="$(df -P "$file"|sed '1d;s/.*\s//')"
- mountopts=($(LC_ALL=C mount|awk "{ if (\$3==\"$mountpoint\") { gsub(/[(,)]/, \" \", \$6); print \$6 } }"))
- ! in_array nosuid "${mountopts[@]}" && ! in_array noexec "${mountopts[@]}"
+ local file=$1
+ local mountpoint mountopts
+ mountpoint="$(df -P "$file"|sed '1d;s/.*\s//')"
+ mountopts=($(LC_ALL=C mount|awk "{ if (\$3==\"$mountpoint\") { gsub(/[(,)]/, \" \", \$6); print \$6 } }"))
+ ! in_array nosuid "${mountopts[@]}" && ! in_array noexec "${mountopts[@]}"
}
@@ -122,87 +122,87 @@ sysd_nspawn_flags=()
hack_arch_nspawn_flags() {
- local copydir="$1"
- local makepkg_conf="$copydir/etc/makepkg.conf"
-
- OPTIND=1
- set -- "${arch_nspawn_flags[@]}"
- while getopts 'hC:M:c:f:s' arg; do
- case "$arg" in
- M) makepkg_conf="$OPTARG" ;;
- *) :;;
- esac
- done
-
- local CARCH=$(detect_chroot_arch "$makepkg_conf")
- local setarch interpreter
-
- case $CARCH in
- armv7h|armv7l) setarch=armv7l; interpreter=/usr/bin/qemu-arm-static ;;
- *) setarch=$CARCH; interpreter=/usr/bin/qemu-$CARCH-static ;;
- esac
- if ! setarch $setarch /bin/true 2>/dev/null; then
- # We're running a cross-arch chroot
-
- # Make sure that qemu-static is set up with binfmt_misc
- if [[ -z $(grep -l -xF \
- -e "interpreter $interpreter" \
- -r -- /proc/sys/fs/binfmt_misc 2>/dev/null \
- | xargs -r grep -xF 'enabled') ]]
- then
- error 'Cannot cross-compile for %s on %s' "$CARCH" "$(uname -m)"
- plain 'This requires a binfmt_misc entry for %s.' "$interpreter"
- prose 'Such a binfmt_misc entry is provided by the %s
- package. If you have it installed, but still see
- this message, you may need to restart %s.' \
- qemu-user-static-binfmt systemd-binfmt.service
- return $EXIT_NOTINSTALLED
- fi
-
- # Let qemu/binfmt_misc do its thing
- arch_nspawn_flags+=(-f "$interpreter" -s)
- fi
+ local copydir="$1"
+ local makepkg_conf="$copydir/etc/makepkg.conf"
+
+ OPTIND=1
+ set -- "${arch_nspawn_flags[@]}"
+ while getopts 'hC:M:c:f:s' arg; do
+ case "$arg" in
+ M) makepkg_conf="$OPTARG" ;;
+ *) :;;
+ esac
+ done
+
+ local CARCH=$(detect_chroot_arch "$makepkg_conf")
+ local setarch interpreter
+
+ case $CARCH in
+ armv7h|armv7l) setarch=armv7l; interpreter=/usr/bin/qemu-arm-static ;;
+ *) setarch=$CARCH; interpreter=/usr/bin/qemu-$CARCH-static ;;
+ esac
+ if ! setarch $setarch /bin/true 2>/dev/null; then
+ # We're running a cross-arch chroot
+
+ # Make sure that qemu-static is set up with binfmt_misc
+ if [[ -z $(grep -l -xF \
+ -e "interpreter $interpreter" \
+ -r -- /proc/sys/fs/binfmt_misc 2>/dev/null \
+ | xargs -r grep -xF 'enabled') ]]
+ then
+ error 'Cannot cross-compile for %s on %s' "$CARCH" "$(uname -m)"
+ plain 'This requires a binfmt_misc entry for %s.' "$interpreter"
+ prose 'Such a binfmt_misc entry is provided by the %s
+ package. If you have it installed, but still see
+ this message, you may need to restart %s.' \
+ qemu-user-static-binfmt systemd-binfmt.service
+ return $EXIT_NOTINSTALLED
+ fi
+
+ # Let qemu/binfmt_misc do its thing
+ arch_nspawn_flags+=(-f "$interpreter" -s)
+ fi
}
# Usage: arch-nspawn $copydir $cmd...
arch-nspawn() {
- local copydir=$1; shift
- local cmd=("$@")
-
- local arch_nspawn_flags=("${arch_nspawn_flags[@]}")
- hack_arch_nspawn_flags "$copydir"
-
- "$_arch_nspawn" \
- "${arch_nspawn_flags[@]}" \
- "$copydir" \
- "${sysd_nspawn_flags[@]}" \
- -- \
- "${cmd[@]}"
+ local copydir=$1; shift
+ local cmd=("$@")
+
+ local arch_nspawn_flags=("${arch_nspawn_flags[@]}")
+ hack_arch_nspawn_flags "$copydir"
+
+ "$_arch_nspawn" \
+ "${arch_nspawn_flags[@]}" \
+ "$copydir" \
+ "${sysd_nspawn_flags[@]}" \
+ -- \
+ "${cmd[@]}"
}
# Usage: mkarchroot $copydir $pkgs...
mkarchroot() {
- local copydir=$1; shift
- local pkgs=("$@")
-
- local arch_nspawn_flags=("${arch_nspawn_flags[@]}")
- hack_arch_nspawn_flags "$copydir"
-
- local cmd=(
- unshare -m "$_mkarchroot"
- # mkarchroot flags: (flags are very similar to arch-nspawn)
- "${arch_nspawn_flags[@]}"
- # chroot directory:
- -- "$copydir"
- # pacman flags:
- # * hack around https://bugs.archlinux.org/task/49347
- --hookdir="$copydir/etc/pacman.d/hooks"
- # packages: (and maybe more flags... pacstrap injects
- # flags at the end, so we can't turn of flag parsing
- # with '--')
- "${pkgs[@]}"
- )
- "${cmd[@]}"
+ local copydir=$1; shift
+ local pkgs=("$@")
+
+ local arch_nspawn_flags=("${arch_nspawn_flags[@]}")
+ hack_arch_nspawn_flags "$copydir"
+
+ local cmd=(
+ unshare -m "$_mkarchroot"
+ # mkarchroot flags: (flags are very similar to arch-nspawn)
+ "${arch_nspawn_flags[@]}"
+ # chroot directory:
+ -- "$copydir"
+ # pacman flags:
+ # * hack around https://bugs.archlinux.org/task/49347
+ --hookdir="$copydir/etc/pacman.d/hooks"
+ # packages: (and maybe more flags... pacstrap injects
+ # flags at the end, so we can't turn of flag parsing
+ # with '--')
+ "${pkgs[@]}"
+ )
+ "${cmd[@]}"
}
@@ -214,360 +214,355 @@ readonly DEF_PACMANCONF_DIR=/usr/share/pacman/defaults/
usage() {
- eval "$(calculate_directories)"
- print "Usage: %s [OPTIONS] COMMAND [ARGS...]" "${0##*/}"
- print 'Interacts with an archroot (arch chroot).'
- echo
- prose 'This is configured with `chroot.conf`, either in
- `/etc/libretools.d/`, or `$XDG_CONFIG_HOME/libretools/`.
- The variables you may set are $CHROOTDIR, $CHROOT, and
- $CHROOTEXTRAPKG.'
- echo
- prose 'There may be multiple chroots; they are stored in $CHROOTDIR.'
- echo
- prose 'Each chroot is named; the default is configured with $CHROOT.'
- echo
- prose 'Each named chroot has a master clean copy (named `root`), and any
- number of other named copies; the copy used by default is the
- current username (or $SUDO_USER, or `copy` if root).'
- echo
- prose 'The full path to the chroot copy is "$CHROOTDIR/$CHROOT/$COPY",
- unless the copy name is manually specified as an absolute path,
- in which case, that path is used.'
- echo
- prose 'The current settings for the above variables are:'
- printf ' CHROOTDIR : %s\n' "${CHROOTDIR:-$(_ 'ERROR: NO SETTING')}"
- printf ' CHROOT : %s\n' "${CHROOT:-$(_ 'ERROR: NO SETTING')}"
- printf ' COPY : %s\n' "$COPY"
- printf ' rootdir : %s\n' "${rootdir:-$(_ 'ERROR')}"
- printf ' copydir : %s\n' "${copydir:-$(_ 'ERROR')}"
- echo
- prose 'If the chroot or copy does not exist, it will be created
- automatically. A chroot by default contains the packages in the
- group "base-devel" and any packages named in $CHROOTEXTRAPKG.
- Unless the `-C` or `-M` flags are used, the configuration files
- that this program installs are the stock versions supplied in the
- packages, not the versions from your host system. Other tools
- (such as libremakepkg) may alter the configuration.'
- echo
- prose 'This command will make the following configuration changes in the
- chroot:'
- bullet 'overwrite `/etc/libretools.d/chroot.conf`' # libretools/librechroot
- bullet 'overwrite `/etc/pacman.d/mirrorlist`' # devtools/arch-nspawn
- bullet 'set `CacheDir` in `/etc/pacman.conf`' # devtools/arch-nspawn
- prose 'If a new `pacman.conf` is inserted with the `-C` flag, the change
- is made after the file is copied in; the `-C` flag doesn'"'"'t
- stop the change from being effective.'
- echo
- prose 'The processor architecture of the chroot is determined
- by the by `CARCH` variable in the `/etc/makepkg.conf`
- file inside of the chroot.'
- echo
+ eval "$(calculate_directories)"
+ print "Usage: %s [OPTIONS] COMMAND [ARGS...]" "${0##*/}"
+ print 'Interacts with an archroot (arch chroot).'
+ echo
+ prose 'This is configured with `chroot.conf`, either in
+ `/etc/libretools.d/`, or `$XDG_CONFIG_HOME/libretools/`.
+ The variables you may set are $CHROOTDIR, $CHROOT, and
+ $CHROOTEXTRAPKG.'
+ echo
+ prose 'There may be multiple chroots; they are stored in $CHROOTDIR.'
+ echo
+ prose 'Each chroot is named; the default is configured with $CHROOT.'
+ echo
+ prose 'Each named chroot has a master clean copy (named `root`), and any
+ number of other named copies; the copy used by default is the
+ current username (or $SUDO_USER, or `copy` if root).'
+ echo
+ prose 'The full path to the chroot copy is "$CHROOTDIR/$CHROOT/$COPY",
+ unless the copy name is manually specified as an absolute path,
+ in which case, that path is used.'
+ echo
+ prose 'The current settings for the above variables are:'
+ printf ' CHROOTDIR : %s\n' "${CHROOTDIR:-$(_ 'ERROR: NO SETTING')}"
+ printf ' CHROOT : %s\n' "${CHROOT:-$(_ 'ERROR: NO SETTING')}"
+ printf ' COPY : %s\n' "$COPY"
+ printf ' rootdir : %s\n' "${rootdir:-$(_ 'ERROR')}"
+ printf ' copydir : %s\n' "${copydir:-$(_ 'ERROR')}"
+ echo
+ prose 'If the chroot or copy does not exist, it will be created
+ automatically. A chroot by default contains the packages in the
+ group "base-devel" and any packages named in $CHROOTEXTRAPKG.
+ Unless the `-C` or `-M` flags are used, the configuration files
+ that this program installs are the stock versions supplied in the
+ packages, not the versions from your host system. Other tools
+ (such as libremakepkg) may alter the configuration.'
+ echo
+ prose 'This command will make the following configuration changes in the
+ chroot:'
+ bullet 'overwrite `/etc/libretools.d/chroot.conf`' # libretools/librechroot
+ bullet 'overwrite `/etc/pacman.d/mirrorlist`' # devtools/arch-nspawn
+ bullet 'set `CacheDir` in `/etc/pacman.conf`' # devtools/arch-nspawn
+ prose 'If a new `pacman.conf` is inserted with the `-C` flag, the change
+ is made after the file is copied in; the `-C` flag doesn'"'"'t
+ stop the change from being effective.'
+ echo
+ prose 'The processor architecture of the chroot is determined
+ by the by `CARCH` variable in the `/etc/makepkg.conf`
+ file inside of the chroot.'
+ echo
prose 'The `-A CARCH` flag is *almost* simply an alias for'
printf ' %s\n' \
"-C \"${DEF_PACMAN_CONF_DIR}pacman.conf.\$CARCH\" \\" \
"-M \"${DEF_PACMAN_CONF_DIR}makepkg.conf.\$CARCH\""
- prose 'However, before doing that, it actually makes a temporary copy of
- `pacman.conf`, and modifies it to:'
- bullet 'set `Architecture` to match the `CARCH` line in `makepkg.conf`'
- bullet 'comment out any `Include = /etc/pacman.d/*.conf` lines'
- echo
- prose 'Creating a copy, deleting a copy, or syncing a copy can be fairly
- slow; but are very fast if $CHROOTDIR is on a btrfs partition.'
- echo
- print 'Options:'
- flag "-n <$(_ CHROOT)>" 'Name of the chroot to use'
- flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the copy to use'
- flag '-N' 'Disable networking in the chroot'
- flag "-C <$(_ FILE)>" 'Copy this file to `$copydir/etc/pacman.conf`'
- flag "-M <$(_ FILE)>" 'Copy this file to `$copydir/etc/makepkg.conf`'
- flag "-A <$(_ CARCH)>" 'Set the architecture of the copy; simply an
- alias for the `-C` and `-M` flags, see above.'
- flag "-w <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read/write'
- flag "-r <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read-only'
- echo
- print 'Commands:'
- print ' Create/copy/delete:'
- flag 'noop|make' 'Do not do anything, but still creates the chroot
- copy if it does not exist'
- flag 'sync' 'Sync the copy with the clean (`root`) copy'
- flag 'delete' 'Delete the chroot copy'
- print ' Dealing with packages:'
- flag "install-file $(_ FILES...)" 'Like `pacman -U FILES...`'
- flag "install-name $(_ NAMES...)" 'Like `pacman -S NAMES...`'
- flag 'update' 'Like `pacman -Syu`'
- flag 'clean-pkgs' 'Remove all packages from the chroot copy that
- are not in base-devel, $CHROOTEXTRAPKG, or named
- as a dependency in the file `/startdir/PKGBUILD`
- in the chroot copy; and install all packages
- that are.'
- print ' Other:'
- flag "run $(_ CMD...)" 'Run CMD in the chroot copy'
- flag 'enter' 'Enter an interactive shell in the chroot copy'
- flag 'clean-repo' 'Clean /repo in the chroot copy'
- flag 'help' 'Show this message'
+ prose 'However, before doing that, it actually makes a temporary copy of
+ `pacman.conf`, and modifies it to:'
+ bullet 'set `Architecture` to match the `CARCH` line in `makepkg.conf`'
+ bullet 'comment out any `Include = /etc/pacman.d/*.conf` lines'
+ echo
+ prose 'Creating a copy, deleting a copy, or syncing a copy can be fairly
+ slow; but are very fast if $CHROOTDIR is on a btrfs partition.'
+ echo
+ print 'Options:'
+ flag "-n <$(_ CHROOT)>" 'Name of the chroot to use'
+ flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the copy to use'
+ flag '-N' 'Disable networking in the chroot'
+ flag "-C <$(_ FILE)>" 'Copy this file to `$copydir/etc/pacman.conf`'
+ flag "-M <$(_ FILE)>" 'Copy this file to `$copydir/etc/makepkg.conf`'
+ flag "-A <$(_ CARCH)>" 'Set the architecture of the copy; simply an
+ alias for the `-C` and `-M` flags, see above.'
+ flag "-w <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read/write'
+ flag "-r <$(_ 'PATH[:INSIDE_PATH[:OPTIONS]]')>" 'Bind mount a file or directory, read-only'
+ echo
+ print 'Commands:'
+ print ' Create/copy/delete:'
+ flag 'noop|make' 'Do not do anything, but still creates the chroot
+ copy if it does not exist'
+ flag 'sync' 'Sync the copy with the clean (`root`) copy'
+ flag 'delete' 'Delete the chroot copy'
+ print ' Dealing with packages:'
+ flag "install-file $(_ FILES...)" 'Like `pacman -U FILES...`'
+ flag "install-name $(_ NAMES...)" 'Like `pacman -S NAMES...`'
+ flag 'update' 'Like `pacman -Syu`'
+ flag 'clean-pkgs' 'Remove all packages from the chroot copy that
+ are not in base-devel, $CHROOTEXTRAPKG, or named
+ as a dependency in the file `/startdir/PKGBUILD`
+ in the chroot copy; and install all packages
+ that are.'
+ print ' Other:'
+ flag "run $(_ CMD...)" 'Run CMD in the chroot copy'
+ flag 'enter' 'Enter an interactive shell in the chroot copy'
+ flag 'clean-repo' 'Clean /repo in the chroot copy'
+ flag 'help' 'Show this message'
}
readonly commands=(
- noop make sync delete
- install-file install-name update clean-pkgs
- run enter clean-repo help
+ noop make sync delete
+ install-file install-name update clean-pkgs
+ run enter clean-repo help
)
# Globals: $CHROOTDIR, $CHROOT, $COPY, $rootdir and $copydir
main() {
- COPY=$LIBREUSER
- [[ $COPY != root ]] || COPY=copy
-
- declare -i retconf=0
- load_conf chroot.conf CHROOTDIR CHROOT || retconf=$?
-
- local target_arch=$(uname -m)
- local mode=enter opt
- declare -Ai used_opts
-
- local tmp_pacmanconf="$(mktemp --tmpdir ${tmp_pacmanconf_prefix}.XXXXXXXXXX)"
- local has_tmp_pacmanconf=0
- local def_pacmanconf
- local def_makepkgconf
-
- trap 'rm -f -- "$tmp_pacmanconf"' EXIT
-
-
- ## parse CLI options ##
-
- while getopts 'n:l:NC:M:A:w:r:' opt; do
- case $opt in
- n ) CHROOT=$OPTARG ;;
- l ) COPY=$OPTARG ;;
- N ) sysd_nspawn_flags+=(--private-network) ;;
- C|M) target_arch=$(detect_chroot_arch "$OPTARG")
- arch_nspawn_flags+=(-$opt "$OPTARG") ;;
- A ) target_arch=$OPTARG
- def_pacmanconf="${DEF_PACMANCONF_DIR}"pacman.conf.${target_arch}
- def_makepkgconf="${DEF_PACMANCONF_DIR}"makepkg.conf.${target_arch}
- arch_nspawn_flags+=( -C "${tmp_pacmanconf}"
- -M "${def_makepkgconf}" )
- has_tmp_pacmanconf=1 ;;
- w ) sysd_nspawn_flags+=("--bind=$OPTARG") ;;
- r ) sysd_nspawn_flags+=("--bind-ro=$OPTARG") ;;
- * ) usage >&2; return $EXIT_INVALIDARGUMENT ;;
- esac
- used_opts[$opt]+=1
- done
-
-
- ## validate CLI options ##
-
- for opt in n l C M A; do
- if (( ${used_opts[$opt]:-0} > 1 )); then
- error "Option -%s may only be given once" "$opt"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- fi
- done
- if (( ${used_opts[A]:-0} && ( ${used_opts[C]:-0} || ${used_opts[M]:-0} ) )); then
- error "Option -A may not be used together with -C or -M"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- fi
- shift $((OPTIND - 1))
- if [[ $# -lt 1 ]]; then
- error "Must specify a command"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- fi
- mode=$1
- if ! in_array "$mode" "${commands[@]}"; then
- error "Unrecognized command: %s" "$mode"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- fi
- shift
- case "$mode" in
- help)
- usage
- return $EXIT_SUCCESS
- :;;
- noop|make|sync|delete|update|enter|clean-pkgs|clean-repo)
- if [[ $# -gt 0 ]]; then
- error 'Command `%s` does not take any arguments: %s' "$mode" "$*"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- fi
- :;;
- install-file)
- if [[ $# -lt 1 ]]; then
- error 'Command `%s` requires at least one file' "$mode"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- else
- local missing=()
- local file
- for file in "$@"; do
- if ! [[ -f $file ]]; then
- missing+=("$file")
- fi
- done
- if [[ ${#missing[@]} -gt 0 ]]; then
- error "%s: file(s) not found: %s" "$mode" "${missing[*]}"
- return $EXIT_INVALIDARGUMENT
- fi
- fi
- :;;
- install-name)
- if [[ $# -lt 1 ]]; then
- error 'Command `%s` requires at least one package name' "$mode"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- fi
- :;;
- run)
- if [[ $# -lt 1 ]]; then
- error 'Command `%s` requires at least one argument' "$mode"
- usage >&2
- return $EXIT_INVALIDARGUMENT
- fi
- :;;
- esac
- if (( has_tmp_pacmanconf )) && \
- ! [[ -f "${def_pacmanconf}" && -f "${def_makepkgconf}" ]]; then
- error 'Unsupported architecture: %s' "${target_arch}"
- plain 'See the files in %q for valid architectures.' "${DEF_PACMANCONF_DIR}"
- return $EXIT_INVALIDARGUMENT;
- fi
-
-
- ## process CLI options ##
-
- if (( has_tmp_pacmanconf )); then
- sed -r \
- -e "s|^#?\\s*Architecture.+|Architecture = ${target_arch}|g" \
- -e "s|^.*Include\s*=\s*/etc/pacman.d/.*\.conf|#&|" \
- < "${def_pacmanconf}" \
- > "$tmp_pacmanconf"
- echo -e '\n\n# Enable the volatile i686 [build-support] repo only as needed.' \
- '\n#[build-support]\n#Server = http://mirror.archlinux32.org/$arch/$repo/' \
- '\n\n# Enable the volatile arm [aur] repo only as needed.' \
- '\n#[aur]\n#Server = https://mirror.archlinuxarm.org/$arch/$repo/' \
- >> "$tmp_pacmanconf"
- fi
-
-
- ## finalize state ##
-
- [[ $retconf = 0 ]] || exit $retconf
- eval "$(calculate_directories)"
-
- readonly LIBREUSER LIBREHOME
- readonly CHROOTDIR CHROOT COPY
- readonly rootdir copydir
- readonly mode
-
-
- ## business ##
-
- if (( EUID )); then
- error "This program must be run as root."
- return $EXIT_NOPERMISSION
- fi
-
- umask 0022
-
- # Keep this lock for as long as we are running
- # Note that '9' is the same FD number as in mkarchroot et al.
- lock 9 "$copydir.lock" \
- "Waiting for existing lock on chroot copy to be released: [%s]" "$COPY"
-
- if [[ $mode != delete ]]; then
- if ! check_mountpoint "$copydir.lock"; then
- error "Chroot copy is mounted with nosuid or noexec options: [%s]" "$COPY"
- return $EXIT_FAILURE
- fi
-
- if [[ ! -d $rootdir ]]; then
- msg "Creating 'root' copy for chroot [%s]" "$CHROOT"
- mkarchroot "$rootdir" base-devel </dev/null
- make_empty_repo "$rootdir"
- fi
-
- if [[ ! -d $copydir ]] || [[ $mode == sync ]]; then
- msg "Syncing copy [%s] with root copy" "$COPY"
- sync_chroot "$CHROOTDIR/$CHROOT/root" "$copydir" "$COPY"
- fi
-
- # Note: the in-chroot pkgconfdir is non-configurable, this is
- # intentionally hard-coded.
- mkdir -p "$copydir/etc/libretools.d"
- {
- if [[ ${#CHROOTEXTRAPKG[*]} -eq 0 ]]; then
- echo 'CHROOTEXTRAPKG=()'
- else
- printf 'CHROOTEXTRAPKG=('
- printf '%q ' "${CHROOTEXTRAPKG[@]}"
- printf ')\n'
- fi
- } > "$copydir"/etc/libretools.d/chroot.conf
-
- # "touch" the chroot first
- # this will
- # - overwrite '/etc/pacman.d/mirrorlist'"
- # - set 'CacheDir' in \`/etc/pacman.conf'"
- # - apply -C or -M flags
- arch-nspawn "$copydir" true </dev/null
- if [[ -n ${tmp_pacmanconf:-} ]]; then
- rm -f -- "$tmp_pacmanconf"
- fi
- trap EXIT # clear the trap to remove the tmp pacman.conf from -A
- arch_nspawn_flags=() # XXX dirty hack, don't apply -C or -M again
- fi
-
- ########################################################################
-
- case "$mode" in
- # Create/copy/delete
- noop|make|sync) :;;
- delete)
- if [[ -d $copydir ]]; then
- delete_chroot "$copydir"
- fi
- ;;
-
- # Dealing with packages
- install-file)
- install_packages "$copydir" "$@" </dev/null
- chroot_add_to_local_repo "$copydir" "$@"
- ;;
- install-name)
- arch-nspawn "$copydir" pacman -Sy --noconfirm -- "$@" </dev/null
- ;;
- update)
- arch-nspawn "$copydir" pacman -Syu --noconfirm </dev/null
- ;;
- clean-pkgs)
- trap "rm -f -- ${copydir@Q}/{chcleanup,chrootexec}" EXIT
- install -m755 "$(librelib chroot/chcleanup)" "$copydir/chcleanup"
- printf '%s\n' \
- '#!/bin/bash' \
- 'mkdir -p /startdir' \
- 'cd /startdir' \
- '/chcleanup' \
- > "$copydir/chrootexec"
- chmod 755 "$copydir/chrootexec"
- arch-nspawn "$copydir" /chrootexec </dev/null
- ;;
-
- # Other
- run)
- arch-nspawn "$copydir" "$@"
- ;;
- enter)
- arch-nspawn "$copydir" bash
- ;;
- clean-repo)
- rm -rf "${copydir}"/repo/*
- make_empty_repo "$copydir"
- ;;
- esac
+ COPY=$LIBREUSER
+ [[ $COPY != root ]] || COPY=copy
+
+ declare -i retconf=0
+ load_conf chroot.conf CHROOTDIR CHROOT || retconf=$?
+
+ local target_arch=$(uname -m)
+ local mode=enter opt
+ declare -Ai used_opts
+
+ local tmp_pacmanconf="$(mktemp --tmpdir ${tmp_pacmanconf_prefix}.XXXXXXXXXX)"
+ local has_tmp_pacmanconf=0
+ local def_pacmanconf
+ local def_makepkgconf
+
+ trap 'rm -f -- "$tmp_pacmanconf"' EXIT
+
+
+ ## parse CLI options ##
+
+ while getopts 'n:l:NC:M:A:w:r:' opt; do
+ case $opt in
+ n ) CHROOT=$OPTARG ;;
+ l ) COPY=$OPTARG ;;
+ N ) sysd_nspawn_flags+=(--private-network) ;;
+ C|M) target_arch=$(detect_chroot_arch "$OPTARG")
+ arch_nspawn_flags+=(-$opt "$OPTARG") ;;
+ A ) target_arch=$OPTARG
+ def_pacmanconf="${DEF_PACMANCONF_DIR}"pacman.conf.${target_arch}
+ def_makepkgconf="${DEF_PACMANCONF_DIR}"makepkg.conf.${target_arch}
+ arch_nspawn_flags+=( -C "${tmp_pacmanconf}"
+ -M "${def_makepkgconf}" )
+ has_tmp_pacmanconf=1 ;;
+ w ) sysd_nspawn_flags+=("--bind=$OPTARG") ;;
+ r ) sysd_nspawn_flags+=("--bind-ro=$OPTARG") ;;
+ * ) usage >&2; return $EXIT_INVALIDARGUMENT ;;
+ esac
+ used_opts[$opt]+=1
+ done
+
+
+ ## validate CLI options ##
+
+ for opt in n l C M A; do
+ if (( ${used_opts[$opt]:-0} > 1 )); then
+ error "Option -%s may only be given once" "$opt"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ fi
+ done
+ if (( ${used_opts[A]:-0} && ( ${used_opts[C]:-0} || ${used_opts[M]:-0} ) )); then
+ error "Option -A may not be used together with -C or -M"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ fi
+ shift $((OPTIND - 1))
+ if [[ $# -lt 1 ]]; then
+ error "Must specify a command"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ fi
+ mode=$1
+ if ! in_array "$mode" "${commands[@]}"; then
+ error "Unrecognized command: %s" "$mode"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ fi
+ shift
+ case "$mode" in
+ help)
+ usage
+ return $EXIT_SUCCESS
+ :;;
+ noop|make|sync|delete|update|enter|clean-pkgs|clean-repo)
+ if [[ $# -gt 0 ]]; then
+ error 'Command `%s` does not take any arguments: %s' "$mode" "$*"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ fi
+ :;;
+ install-file)
+ if [[ $# -lt 1 ]]; then
+ error 'Command `%s` requires at least one file' "$mode"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ else
+ local missing=()
+ local file
+ for file in "$@"; do
+ if ! [[ -f $file ]]; then
+ missing+=("$file")
+ fi
+ done
+ if [[ ${#missing[@]} -gt 0 ]]; then
+ error "%s: file(s) not found: %s" "$mode" "${missing[*]}"
+ return $EXIT_INVALIDARGUMENT
+ fi
+ fi
+ :;;
+ install-name)
+ if [[ $# -lt 1 ]]; then
+ error 'Command `%s` requires at least one package name' "$mode"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ fi
+ :;;
+ run)
+ if [[ $# -lt 1 ]]; then
+ error 'Command `%s` requires at least one argument' "$mode"
+ usage >&2
+ return $EXIT_INVALIDARGUMENT
+ fi
+ :;;
+ esac
+ if (( has_tmp_pacmanconf )) && \
+ ! [[ -f "${def_pacmanconf}" && -f "${def_makepkgconf}" ]]; then
+ error 'Unsupported architecture: %s' "${target_arch}"
+ plain 'See the files in %q for valid architectures.' "${DEF_PACMANCONF_DIR}"
+ return $EXIT_INVALIDARGUMENT;
+ fi
+
+
+ ## process CLI options ##
+
+ if (( has_tmp_pacmanconf )); then
+ sed -r \
+ -e "s|^#?\\s*Architecture.+|Architecture = ${target_arch}|g" \
+ -e "s|^.*Include\s*=\s*/etc/pacman.d/.*\.conf|#&|" \
+ < "${def_pacmanconf}" \
+ > "${tmp_pacmanconf}"
+ fi
+
+
+ ## finalize state ##
+
+ [[ $retconf = 0 ]] || exit $retconf
+ eval "$(calculate_directories)"
+
+ readonly LIBREUSER LIBREHOME
+ readonly CHROOTDIR CHROOT COPY
+ readonly rootdir copydir
+ readonly mode
+
+
+ ## business ##
+
+ if (( EUID )); then
+ error "This program must be run as root."
+ return $EXIT_NOPERMISSION
+ fi
+
+ umask 0022
+
+ # Keep this lock for as long as we are running
+ # Note that '9' is the same FD number as in mkarchroot et al.
+ lock 9 "$copydir.lock" \
+ "Waiting for existing lock on chroot copy to be released: [%s]" "$COPY"
+
+ if [[ $mode != delete ]]; then
+ if ! check_mountpoint "$copydir.lock"; then
+ error "Chroot copy is mounted with nosuid or noexec options: [%s]" "$COPY"
+ return $EXIT_FAILURE
+ fi
+
+ if [[ ! -d $rootdir ]]; then
+ msg "Creating 'root' copy for chroot [%s]" "$CHROOT"
+ mkarchroot "$rootdir" base-devel </dev/null
+ make_empty_repo "$rootdir"
+ fi
+
+ if [[ ! -d $copydir ]] || [[ $mode == sync ]]; then
+ msg "Syncing copy [%s] with root copy" "$COPY"
+ sync_chroot "$CHROOTDIR/$CHROOT/root" "$copydir" "$COPY"
+ fi
+
+ # Note: the in-chroot pkgconfdir is non-configurable, this is
+ # intentionally hard-coded.
+ mkdir -p "$copydir/etc/libretools.d"
+ {
+ if [[ ${#CHROOTEXTRAPKG[*]} -eq 0 ]]; then
+ echo 'CHROOTEXTRAPKG=()'
+ else
+ printf 'CHROOTEXTRAPKG=('
+ printf '%q ' "${CHROOTEXTRAPKG[@]}"
+ printf ')\n'
+ fi
+ } > "$copydir"/etc/libretools.d/chroot.conf
+
+ # "touch" the chroot first
+ # this will
+ # - overwrite '/etc/pacman.d/mirrorlist'"
+ # - set 'CacheDir' in \`/etc/pacman.conf'"
+ # - apply -C or -M flags
+ arch-nspawn "$copydir" true </dev/null
+ if [[ -n ${tmp_pacmanconf:-} ]]; then
+ rm -f -- "$tmp_pacmanconf"
+ fi
+ trap EXIT # clear the trap to remove the tmp pacman.conf from -A
+ arch_nspawn_flags=() # XXX dirty hack, don't apply -C or -M again
+ fi
+
+ ########################################################################
+
+ case "$mode" in
+ # Create/copy/delete
+ noop|make|sync) :;;
+ delete)
+ if [[ -d $copydir ]]; then
+ delete_chroot "$copydir"
+ fi
+ ;;
+
+ # Dealing with packages
+ install-file)
+ install_packages "$copydir" "$@" </dev/null
+ chroot_add_to_local_repo "$copydir" "$@"
+ ;;
+ install-name)
+ arch-nspawn "$copydir" pacman -Sy --noconfirm -- "$@" </dev/null
+ ;;
+ update)
+ arch-nspawn "$copydir" pacman -Syu --noconfirm </dev/null
+ ;;
+ clean-pkgs)
+ trap "rm -f -- ${copydir@Q}/{chcleanup,chrootexec}" EXIT
+ install -m755 "$(librelib chroot/chcleanup)" "$copydir/chcleanup"
+ printf '%s\n' \
+ '#!/bin/bash' \
+ 'mkdir -p /startdir' \
+ 'cd /startdir' \
+ '/chcleanup' \
+ > "$copydir/chrootexec"
+ chmod 755 "$copydir/chrootexec"
+ arch-nspawn "$copydir" /chrootexec </dev/null
+ ;;
+
+ # Other
+ run)
+ arch-nspawn "$copydir" "$@"
+ ;;
+ enter)
+ arch-nspawn "$copydir" bash
+ ;;
+ clean-repo)
+ rm -rf "${copydir}"/repo/*
+ make_empty_repo "$copydir"
+ ;;
+ esac
}