diff --git a/bin/basestrap.in b/bin/basestrap.in index 3c163dc..df65064 100644 --- a/bin/basestrap.in +++ b/bin/basestrap.in @@ -49,8 +49,6 @@ usage() { # fi # -orig_argv=("$@") - opts=':C:cdGiM' while getopts ${opts} arg; do @@ -67,7 +65,7 @@ while getopts ${opts} arg; do done shift $(( OPTIND - 1 )) -check_root "$0" "${orig_argv[@]}" +check_root (( $# )) || die "No root directory specified" newroot=$1; shift @@ -97,7 +95,7 @@ if ! pacman -r "$newroot" -Sy "${pacman_args[@]}"; then fi # kill chroot process if needed (TODO: check if needed at all) -kill_chroot_process "$newroot" +# kill_chroot_process "$newroot" if ${copykeyring};then copy_keyring "$newroot" diff --git a/bin/buildiso.in b/bin/buildiso.in index 26374e1..d7b6706 100755 --- a/bin/buildiso.in +++ b/bin/buildiso.in @@ -135,8 +135,6 @@ usage() { exit $1 } -orig_argv=("$@") - opts='p:a:b:r:t:k:i:g:czxmvqh' while getopts "${opts}" arg; do @@ -164,7 +162,7 @@ shift $(($OPTIND - 1)) timer_start=$(get_timer) -check_root "$0" "${orig_argv[@]}" +check_root prepare_dir "${log_dir}" diff --git a/bin/buildpkg.in b/bin/buildpkg.in index 10e99ba..c023833 100644 --- a/bin/buildpkg.in +++ b/bin/buildpkg.in @@ -103,8 +103,6 @@ usage() { exit $1 } -orig_argv=("$@") - opts='p:a:b:r:i:cwnsuqh' while getopts "${opts}" arg; do @@ -127,7 +125,7 @@ done shift $(($OPTIND - 1)) -check_root "$0" "${orig_argv[@]}" +check_root prepare_dir "${log_dir}" diff --git a/bin/buildtree.in b/bin/buildtree.in index d36701e..4e5b96f 100644 --- a/bin/buildtree.in +++ b/bin/buildtree.in @@ -55,8 +55,6 @@ usage() { exit $1 } -orig_argv=("$@") - opts='sacqh' while getopts "${opts}" arg; do @@ -72,7 +70,7 @@ done shift $(($OPTIND - 1)) -check_root "$0" "${orig_argv[@]}" +check_root prepare_dir "${tree_dir_abs}" diff --git a/bin/check-yaml.in b/bin/check-yaml.in index b8ff096..b5284d5 100644 --- a/bin/check-yaml.in +++ b/bin/check-yaml.in @@ -112,8 +112,6 @@ usage() { exit $1 } -orig_argv=("$@") - opts='p:a:i:k:gcvqh' while getopts "${opts}" arg; do @@ -133,7 +131,7 @@ done shift $(($OPTIND - 1)) -check_root "$0" "${orig_argv[@]}" +check_root prepare_dir "${tmp_dir}" diff --git a/bin/chroot-run.in b/bin/chroot-run.in index fff5bfa..9c8439f 100644 --- a/bin/chroot-run.in +++ b/bin/chroot-run.in @@ -19,7 +19,9 @@ import ${LIBDIR}/util.sh import ${LIBDIR}/util-mount.sh working_dir='' +files=() keep_mirrors=false +nosetarch=false usage() { echo "Usage: ${0##*/} [options] working-dir [run arguments]" @@ -30,6 +32,8 @@ usage() { echo ' -M Location of a makepkg config file' echo ' -S Location of a pacman-mirrors config file' echo ' -c Set pacman cache' + echo ' -f Copy file from the host to the chroot' + echo ' -s Do not run setarch' echo ' -r Bind mountargs ro' echo ' -w Bind mountargs rw' echo ' List format [src1:target1,...,srcN:targetN]' @@ -39,9 +43,7 @@ usage() { exit 1 } -orig_argv=("$@") - -opts='hKC:M:S:c:r:w:B:' +opts='hKC:M:S:c:r:w:B:f:s' while getopts ${opts} arg; do case "${arg}" in @@ -49,8 +51,10 @@ while getopts ${opts} arg; do M) makepkg_conf="$OPTARG" ;; S) mirrors_conf="$OPTARG" ;; c) cache_dir="$OPTARG" ;; - r) mountargs_ro="$OPTARG" ;; - w) mountargs_rw="$OPTARG" ;; + f) files+=("$OPTARG") ;; + s) nosetarch=true ;; + r) bindmounts_ro=("$OPTARG") ;; + w) bindmounts_rw=("$OPTARG") ;; B) build_mirror="$OPTARG" ;; K) keep_mirrors=true ;; h|?) usage ;; @@ -60,7 +64,8 @@ done shift $(($OPTIND - 1)) (( $# < 1 )) && die 'You must specify a directory.' -check_root "$0" "${orig_argv[@]}" + +check_root working_dir=$(readlink -f "$1") shift 1 @@ -81,6 +86,12 @@ copy_hostconf () { [[ -n $makepkg_conf ]] && cp $makepkg_conf "$1/etc/makepkg.conf" [[ -n $mirrors_conf ]] && cp ${mirrors_conf} "$1/etc/pacman-mirrors.conf" + local file + for file in "${files[@]}"; do + mkdir -p "$(dirname "$working_dir$file")" + cp -T "$file" "$working_dir$file" + done + if [[ -n ${build_mirror} ]];then build_mirror=${build_mirror}'/$repo/$arch' if ${keep_mirrors}; then @@ -95,7 +106,7 @@ copy_hostconf () { sed -r "s|^#?\\s*CacheDir.+|CacheDir = $(echo -n ${cache_dirs[@]})|g" -i "$1/etc/pacman.conf" } -chroot_extra_umount() { +chroot_extra_mount() { chroot_mount "/etc/resolv.conf" "$1/etc/resolv.conf" -B chroot_mount "${cache_dirs[0]}" "$1${cache_dirs[0]}" -B @@ -103,21 +114,21 @@ chroot_extra_umount() { chroot_mount "$cache_dir" "$1${cache_dir}" -Br done - if [[ -n ${mountargs_ro[@]} ]];then - local IFS=',' - for m in ${mountargs_ro[@]}; do +# if [[ -n ${bindmounts_ro[@]} ]];then +# local IFS=',' + for m in ${bindmounts_ro[@]}; do chroot_mount "${m%%:*}" "$1${m##*:}" -Br done - unset IFS - fi +# unset IFS +# fi - if [[ -n ${mountargs_rw[@]} ]];then - local IFS=',' - for m in ${mountargs_rw[@]}; do +# if [[ -n ${bindmounts_rw[@]} ]];then +# local IFS=',' + for m in ${bindmounts_rw[@]}; do chroot_mount "${m%%:*}" "$1${m##*:}" -B done - unset IFS - fi +# unset IFS +# fi } umask 0022 @@ -131,12 +142,14 @@ fi chroot_api_mount "${working_dir}" || die "failed to setup API filesystems in chroot %s" "${working_dir}" -chroot_extra_umount "${working_dir}" +chroot_extra_mount "${working_dir}" copy_hostconf "${working_dir}" eval $(grep '^CARCH=' "$working_dir/etc/makepkg.conf") +${nosetarch} && unset CARCH + ${CARCH:+setarch "$CARCH"} chroot "${working_dir}" "$@" -kill_chroot_process "${working_dir}" +# kill_chroot_process "${working_dir}" diff --git a/bin/manjaro-chroot.in b/bin/manjaro-chroot.in index 8d88240..0633340 100644 --- a/bin/manjaro-chroot.in +++ b/bin/manjaro-chroot.in @@ -55,8 +55,6 @@ usage() { exit $1 } -orig_argv=("$@") - opts=':haq' while getopts ${opts} arg; do @@ -69,7 +67,7 @@ while getopts ${opts} arg; do done shift $(( OPTIND - 1 )) -check_root "$0" "${orig_argv[@]}" +check_root if ${automount};then chrootdir=/mnt diff --git a/bin/mkchroot.in b/bin/mkchroot.in index e3678d9..36efee1 100644 --- a/bin/mkchroot.in +++ b/bin/mkchroot.in @@ -18,9 +18,12 @@ LIBDIR='@libdir@' import ${LIBDIR}/util.sh working_dir='' +files=() + build_locales=false keep_mirrors=false keep_flag='' +nosetarch=false usage() { echo "Usage: ${0##*/} [options] working-dir package-list..." @@ -29,6 +32,8 @@ usage() { echo ' -M Location of a makepkg config file' echo ' -S Location of a pacman-mirrors config file' echo ' -c Set pacman cache' + echo ' -f Copy file from the host to the chroot' + echo ' -s Do not run setarch' echo ' -L Use build locale.gen en/de' echo ' -B Use custom build mirror' echo ' -K Keep mirrorlist (-B)' @@ -37,9 +42,7 @@ usage() { exit 1 } -orig_argv=("$@") - -opts='hLKC:M:S:c:B:' +opts='hLKC:M:S:c:B:f:s' while getopts ${opts} arg; do case "${arg}" in @@ -47,18 +50,20 @@ while getopts ${opts} arg; do M) makepkg_conf="$OPTARG" ;; S) mirrors_conf="$OPTARG" ;; c) cache_dir="$OPTARG" ;; + f) files+=("$OPTARG") ;; + s) nosetarch=true ;; L) build_locales=true ;; B) build_mirror="$OPTARG" ;; K) keep_mirrors=true; keep_flag='-K' ;; h|?) usage ;; - *) error "invalid argument '$arg'"; usage ;; + *) error "invalid argument '%s'" "$arg"; usage ;; esac done shift $(($OPTIND - 1)) (( $# < 2 )) && die 'You must specify a directory and one or more packages.' -check_root "$0" "${orig_argv[@]}" +check_root working_dir="$(readlink -f $1)" shift 1 @@ -89,6 +94,11 @@ if is_btrfs "$working_dir"; then chmod 0755 "$working_dir" fi +for file in "${files[@]}"; do + mkdir -p "$(dirname "$working_dir$file")" + cp "$file" "$working_dir$file" +done + # Workaround when creating a chroot in a branch different of the host if [[ -n $pac_conf ]] && [[ -n $mirrors_conf ]] && [[ -n ${build_mirror} ]]; then url=${build_mirror}'/$repo/$arch' @@ -96,11 +106,21 @@ if [[ -n $pac_conf ]] && [[ -n $mirrors_conf ]] && [[ -n ${build_mirror} ]]; the pac_base="$working_dir/pacman-basestrap.conf" sed "s#Include = /etc/pacman.d/mirrorlist#Server = ${url}#g" $pac_conf > $pac_base + _env=() + while read -r varname; do + _env+=("$varname=${!varname}") + done < <(declare -x | sed -r 's/^declare -x ([^=]*)=.*/\1/' | grep -i '_proxy$') + env -i "${_env[@]}" \ basestrap -GMcd ${pac_base:+-C "$pac_base"} "$working_dir" \ "${cache_dirs[@]/#/--cachedir=}" "$@" || die 'Failed to install all packages' [[ -f "$pac_base" ]] && rm "$pac_base" else + _env=() + while read -r varname; do + _env+=("$varname=${!varname}") + done < <(declare -x | sed -r 's/^declare -x ([^=]*)=.*/\1/' | grep -i '_proxy$') + env -i "${_env[@]}" \ basestrap -GMcd ${pac_conf:+-C "$pac_conf"} "$working_dir" \ "${cache_dirs[@]/#/--cachedir=}" "$@" || die 'Failed to install all packages' fi @@ -117,6 +137,7 @@ if ${build_locales};then fi chroot_args=(${pac_conf:+-C "$pac_conf"} ${makepkg_conf:+-M "$makepkg_conf"} ${mirrors_conf:+-S "$mirrors_conf"} ${build_mirror:+-B "$build_mirror"} ${cache_dir:+-c "$cache_dir"} ${keep_flag}) +${nosetarch} && chroot_args+=(${nosetarch:+-s}) exec chroot-run \ ${chroot_args[*]} \ diff --git a/bin/mkchrootpkg.in b/bin/mkchrootpkg.in index 9ba0def..e96b6f5 100644 --- a/bin/mkchrootpkg.in +++ b/bin/mkchrootpkg.in @@ -19,138 +19,115 @@ import ${LIBDIR}/util.sh shopt -s nullglob -makepkg_args=(-s --noconfirm -L) -repack=false -update_first=false -clean_first=false -install_pkg= -run_namcap=false -temp_chroot=false -chrootdir= -passeddir= -declare -a install_pkgs -declare -i ret=0 +init_variables() { + default_makepkg_args=(-s --noconfirm -L --holdver) + makepkg_args=("${default_makepkg_args[@]}") + repack=false + update_first=false + clean_first=false + run_namcap=false + temp_chroot=false + chrootdir= + passeddir= + makepkg_user= + declare -ga install_pkgs + declare -gi ret=0 -copy=$USER -[[ -n $SUDO_USER ]] && copy=$SUDO_USER -[[ -z "$copy" || $copy = root ]] && copy=copy -src_owner=${SUDO_USER:-$USER} + bindmounts_ro=() + bindmounts_rw=() + + copy=$USER + [[ -n ${SUDO_USER:-} ]] && copy=$SUDO_USER + [[ -z "$copy" || $copy = root ]] && copy=copy + src_owner=${SUDO_USER:-$USER} +} usage() { echo "Usage: ${0##*/} [options] -r [--] [makepkg args]" - echo ' Run this script in a PKGBUILD dir to build a package inside a' - echo ' clean chroot. Arguments passed to this script after the' - echo ' end-of-options marker (--) will be passed to makepkg.' + echo ' Run this script in a PKGBUILD dir to build a package inside a' + echo ' clean chroot. Arguments passed to this script after the' + echo ' end-of-options marker (--) will be passed to makepkg.' echo '' - echo ' The chroot dir consists of the following directories:' - echo ' /{root, copy} but only "root" is required' - echo ' by default. The working copy will be created as needed' + echo ' The chroot dir consists of the following directories:' + echo ' /{root, copy} but only "root" is required' + echo ' by default. The working copy will be created as needed' echo '' - echo ' The chroot "root" directory must be created via the following' - echo ' command:' - echo ' mkchroot /root base-devel' + echo 'The chroot "root" directory must be created via the following' + echo 'command:' + echo ' mkarchroot /root base-devel' echo '' - echo " Default makepkg args: ${makepkg_args[*]}" + echo 'This script reads {SRC,SRCPKG,PKG,LOG}DEST, MAKEFLAGS and PACKAGER' + echo 'from makepkg.conf(5), if those variables are not part of the' + echo 'environment.' echo '' - echo ' Flags:' - echo ' -h This help' - echo ' -c Clean the chroot before building' - echo ' -u Update the working copy of the chroot before building' - echo ' This is useful for rebuilds without dirtying the pristine' - echo ' chroot' - echo ' -r The chroot dir to use' - echo ' -I Install a package into the working copy of the chroot' - echo ' -l The directory to use as the working copy of the chroot' - echo ' Useful for maintaining multiple copies' - echo " Default: $copy" - echo ' -n Run namcap on the package' - echo ' -T Build in a temporary directory' + echo "Default makepkg args: ${default_makepkg_args[*]}" + echo '' + echo 'Flags:' + echo '-h This help' + echo '-c Clean the chroot before building' + echo '-d Bind directory into build chroot as read-write' + echo '-D Bind directory into build chroot as read-only' + echo '-u Update the working copy of the chroot before building' + echo ' This is useful for rebuilds without dirtying the pristine' + echo ' chroot' + echo '-r The chroot dir to use' + echo '-I Install a package into the working copy of the chroot' + echo '-l The directory to use as the working copy of the chroot' + echo ' Useful for maintaining multiple copies' + echo " Default: $copy" + echo '-n Run namcap on the package' + echo '-T Build in a temporary directory' + echo '-U Run makepkg as a specified user' exit 1 } -orig_argv=("$@") - -while getopts 'hcur:I:l:nT' arg; do - case "$arg" in - c) clean_first=true ;; - u) update_first=true ;; - r) passeddir="$OPTARG" ;; - I) install_pkgs+=("$OPTARG") ;; - l) copy="$OPTARG" ;; - n) run_namcap=true; makepkg_args+=(-i) ;; - T) temp_chroot=true; copy+="-$$" ;; - h|*) usage ;; - esac -done - -[[ ! -f PKGBUILD && -z "${install_pkgs[*]}" ]] && die 'This must be run in a directory containing a PKGBUILD.' - -check_root "$0" "${orig_argv[@]}" - -# Canonicalize chrootdir, getting rid of trailing / -chrootdir=$(readlink -e "$passeddir") -[[ ! -d $chrootdir ]] && die "No chroot dir defined, or invalid path '%s'" "$passeddir" -[[ ! -d $chrootdir/root ]] && die "Missing chroot dir root directory. Try using: mkchroot %s/root base-devel" "$chrootdir" - -# Detect chrootdir filesystem type -chroottype=$(stat -f -c %T "$chrootdir") - -if [[ ${copy:0:1} = / ]]; then - copydir=$copy -else - copydir="$chrootdir/$copy" -fi - -# Pass all arguments after -- right to makepkg -makepkg_args+=("${@:$OPTIND}") - -# See if -R was passed to makepkg -for arg in "${@:OPTIND}"; do - case ${arg%%=*} in - -*R*|--repackage) - repack=true - break 2 - ;; - esac -done - -load_user_info - -# {{{ functions - -create_chroot() { - # Lock the chroot we want to use. We'll keep this lock until we exit. - lock 9 "$copydir.lock" "Locking chroot copy [$copy]" - - if [[ ! -d $copydir ]] || $clean_first; then - # Get a read lock on the root chroot to make - # sure we don't clone a half-updated chroot - slock 8 "$chrootdir/root.lock" "Locking clean chroot" - - stat_busy "Creating clean working copy [$copy]" - if is_btrfs "$chrootdir" && ! mountpoint -q "$copydir"; then - subvolume_delete_recursive "$copydir" || - die "Unable to delete subvolume %s" "$copydir" - btrfs subvolume snapshot "$chrootdir/root" "$copydir" >/dev/null || - die "Unable to create subvolume %s" "$copydir" - else - mkdir -p "$copydir" - rsync -a --delete -q -W -x "$chrootdir/root/" "$copydir" - fi - stat_done - - # Drop the read lock again - exec 8>&- +sync_chroot() { + local chrootdir=$1 + local copy=$2 + local copydir='' + if [[ ${copy:0:1} = / ]]; then + copydir=$copy + else + copydir="$chrootdir/$copy" fi + if [[ "$chrootdir/root" -ef "$copydir" ]]; then + error 'Cannot sync copy with itself: %s' "$copydir" + return 1 + fi + + # Get a read lock on the root chroot to make + # sure we don't clone a half-updated chroot + slock 8 "$chrootdir/root.lock" \ + "Locking clean chroot [%s]" "$chrootdir/root" + + stat_busy "Synchronizing chroot copy [%s] -> [%s]" "$chrootdir/root" "$copydir" + if is_btrfs "$chrootdir" && ! mountpoint -q "$copydir"; then + subvolume_delete_recursive "$copydir" || + die "Unable to delete subvolume %s" "$copydir" + btrfs subvolume snapshot "$chrootdir/root" "$copydir" >/dev/null || + die "Unable to create subvolume %s" "$copydir" + else + mkdir -p "$copydir" + rsync -a --delete -q -W -x "$chrootdir/root/" "$copydir" + fi + stat_done + + # Drop the read lock again + lock_close 8 + # Update mtime touch "$copydir" } -clean_temporary() { - stat_busy "Removing temporary copy [$copy]" +# Usage: delete_chroot $copydir [$copy] +delete_chroot() { + local copydir=$1 + local copy=${1:-$2} + + stat_busy "Removing chroot copy [%s]" "$copy" if is_btrfs "$chrootdir" && ! mountpoint -q "$copydir"; then - btrfs subvolume delete "$copydir" >/dev/null || + subvolume_delete_recursive "$copydir" || die "Unable to delete subvolume %s" "$copydir" else # avoid change of filesystem in case of an umount failure @@ -163,24 +140,35 @@ clean_temporary() { stat_done } +# Usage: install_packages $copydir $pkgs... install_packages() { + local copydir=$1 + local install_pkgs=("${@:2}") + local -a pkgnames local ret pkgnames=("${install_pkgs[@]##*/}") cp -- "${install_pkgs[@]}" "$copydir/root/" - - chroot-run "$copydir" \ - pacman -U --noconfirm -- "${pkgnames[@]/#//root/}" + chroot-run -r "${bindmounts_ro[@]}" -w "${bindmounts_rw[@]}" "$copydir" \ + pacman -U --noconfirm -- "${pkgnames[@]/#//root/}" ret=$? rm -- "${pkgnames[@]/#/$copydir/root/}" - # If there is no PKGBUILD we are done - [[ -f PKGBUILD ]] || exit $ret + return $ret } +# Usage: prepare_chroot $copydir $HOME $repack $run_namcap +# Globals: +# - MAKEFLAGS +# - PACKAGER prepare_chroot() { + local copydir=$1 + local USER_HOME=$2 + local repack=$3 + local run_namcap=$4 + $repack || rm -rf "$copydir/build" local builduser_uid="${SUDO_UID:-$UID}" @@ -204,7 +192,7 @@ prepare_chroot() { sed -e '/^MAKEFLAGS=/d' -e '/^PACKAGER=/d' -i "$copydir/etc/makepkg.conf" for x in BUILDDIR=/build PKGDEST=/pkgdest SRCPKGDEST=/srcpkgdest SRCDEST=/srcdest LOGDEST=/logdest \ - "MAKEFLAGS='$MAKEFLAGS'" "PACKAGER='$PACKAGER'" + "MAKEFLAGS='${MAKEFLAGS:-}'" "PACKAGER='${PACKAGER:-}'" do grep -q "^$x" "$copydir/etc/makepkg.conf" && continue echo "$x" >>"$copydir/etc/makepkg.conf" @@ -220,9 +208,7 @@ EOF { printf '#!/bin/bash\n' declare -f _chrootbuild - printf '_chrootbuild' - printf ' %q' "${makepkg_args[@]}" - printf ' || exit\n' + printf '_chrootbuild "$@" || exit\n' if $run_namcap; then declare -f _chrootnamcap @@ -236,9 +222,6 @@ EOF # so no global variables _chrootbuild() { . /etc/profile -# export HOME=/build -# cd /startdir -# sudo -u builduser makepkg "$@" sudo -iu builduser bash -c 'cd /startdir; makepkg "$@"' -bash "$@" } @@ -250,37 +233,52 @@ _chrootnamcap() { done } +# Usage: download_sources $copydir $src_owner +# Globals: +# - SRCDEST +# - USER download_sources() { + local copydir=$1 + local src_owner=$2 + local builddir="$(mktemp -d)" chmod 1777 "$builddir" # Ensure sources are downloaded - if [[ -n $SUDO_USER ]]; then - sudo -u $SUDO_USER env SRCDEST="$SRCDEST" BUILDDIR="$builddir" \ + makepkg_user=${makepkg_user:-$SUDO_USER} + if [[ -n $makepkg_user ]]; then + sudo -u "$makepkg_user" env SRCDEST="$SRCDEST" BUILDDIR="$builddir" \ makepkg --config="$copydir/etc/makepkg.conf" --verifysource -o else - ( export SRCDEST BUILDDIR="$builddir" - makepkg --asroot --config="$copydir/etc/makepkg.conf" --verifysource -o - ) + error "Running makepkg as root is not allowed." + exit 1 fi (( $? != 0 )) && die "Could not download sources." # Clean up garbage from verifysource - rm -rf $builddir + rm -rf "$builddir" } +# Usage: move_products $copydir $owner +# Globals: +# - PKGDEST +# - LOGDEST move_products() { + local copydir=$1 + local src_owner=$2 + + local pkgfile for pkgfile in "$copydir"/pkgdest/*; do chown "$src_owner" "$pkgfile" mv "$pkgfile" "$PKGDEST" # Fix broken symlink because of temporary chroot PKGDEST /pkgdest if [[ "$PWD" != "$PKGDEST" && -L "$PWD/${pkgfile##*/}" ]]; then - rm "$PWD/${pkgfile##*/}" ln -sf "$PKGDEST/${pkgfile##*/}" fi done + local l for l in "$copydir"/logdest/*; do [[ $l == */logpipe.* ]] && continue chown "$src_owner" "$l" @@ -294,49 +292,117 @@ move_products() { } # }}} -umask 0022 -load_vars "$USER_HOME/.makepkg.conf" || load_vars /etc/makepkg.conf +main() { + init_variables -# Use PKGBUILD directory if these don't exist -[[ -d $PKGDEST ]] || PKGDEST=$PWD -[[ -d $SRCDEST ]] || SRCDEST=$PWD -[[ -d $SRCPKGDEST ]] || SRCPKGDEST=$PWD -[[ -d $LOGDEST ]] || LOGDEST=$PWD + while getopts 'hcur:I:l:nTD:d:U:' arg; do + case "$arg" in + c) clean_first=true ;; + D) bindmounts_ro+=(--bind-ro="$OPTARG") ;; + d) bindmounts_rw+=(--bind="$OPTARG") ;; + u) update_first=true ;; + r) passeddir="$OPTARG" ;; + I) install_pkgs+=("$OPTARG") ;; + l) copy="$OPTARG" ;; + n) run_namcap=true; makepkg_args+=(-i) ;; + T) temp_chroot=true; copy+="-$$" ;; + U) makepkg_user="$OPTARG" ;; + h|*) usage ;; + esac + done -create_chroot + [[ ! -f PKGBUILD && -z "${install_pkgs[*]}" ]] && die 'This must be run in a directory containing a PKGBUILD.' + [[ -n $makepkg_user && -z $(id -u "$makepkg_user") ]] && die 'Invalid makepkg user.' -$update_first && chroot-run \ - -r "${mountargs_ro}" \ - -w "${mountargs_rw}" \ - "$copydir" \ - pacman -Syu --noconfirm + check_root -[[ -n ${install_pkgs[*]} ]] && install_packages + # Canonicalize chrootdir, getting rid of trailing / + chrootdir=$(readlink -e "$passeddir") + [[ ! -d $chrootdir ]] && die "No chroot dir defined, or invalid path '%s'" "$passeddir" + [[ ! -d $chrootdir/root ]] && die "Missing chroot dir root directory. Try using: mkarchroot %s/root base-devel" "$chrootdir" -download_sources - -prepare_chroot - -mountargs_rw="${PWD}:/startdir,${SRCDEST}:/srcdest" - -if chroot-run -r "${mountargs_ro}" \ - -w "${mountargs_rw}" \ - "$copydir" \ - /chrootbuild; then - move_products -else - (( ret += 1 )) -fi - -$temp_chroot && clean_temporary - -if (( ret != 0 )); then - if $temp_chroot; then - die "Build failed" + if [[ ${copy:0:1} = / ]]; then + copydir=$copy else - die "Build failed, check %s/build" "$copydir" + copydir="$chrootdir/$copy" fi -else - true -fi + + # Pass all arguments after -- right to makepkg + makepkg_args+=("${@:$OPTIND}") + + # See if -R was passed to makepkg + for arg in "${@:OPTIND}"; do + case ${arg%%=*} in + -*R*|--repackage) + repack=true + break 2 + ;; + esac + done + + if [[ -n $SUDO_USER ]]; then + eval "USER_HOME=~$SUDO_USER" + else + USER_HOME=$HOME + fi + + umask 0022 + + load_vars "$USER_HOME/.makepkg.conf" || load_vars /etc/makepkg.conf + + # Use PKGBUILD directory if these don't exist + [[ -d $PKGDEST ]] || PKGDEST=$PWD + [[ -d $SRCDEST ]] || SRCDEST=$PWD + [[ -d $SRCPKGDEST ]] || SRCPKGDEST=$PWD + [[ -d $LOGDEST ]] || LOGDEST=$PWD + + # Lock the chroot we want to use. We'll keep this lock until we exit. + lock 9 "$copydir.lock" "Locking chroot copy [%s]" "$copy" + + if [[ ! -d $copydir ]] || $clean_first; then + sync_chroot "$chrootdir" "$copy" + fi + + $update_first && chroot-run \ + -r "${bindmounts_ro[@]}" \ + -w "${bindmounts_rw[@]}" \ + "$copydir" \ + pacman -Syu --noconfirm + + if [[ -n ${install_pkgs[*]:-} ]]; then + install_packages "$copydir" "${install_pkgs[@]}" + ret=$? + # If there is no PKGBUILD we have done + [[ -f PKGBUILD ]] || return $ret + fi + + download_sources "$copydir" "$src_owner" + + prepare_chroot "$copydir" "$USER_HOME" "$repack" + + bindmounts_rw=("${PWD}:/startdir" "${SRCDEST}:/srcdest") + + if chroot-run -r "${bindmounts_ro[@]}" \ + -w "${bindmounts_rw[@]}" \ + "$copydir" \ + /chrootbuild "${makepkg_args[@]}"; then + move_products "$copydir" "$src_owner" + else + (( ret += 1 )) + fi + + $temp_chroot && delete_chroot "$copydir" "$copy" + + if (( ret != 0 )); then + if $temp_chroot; then + die "Build failed" + else + die "Build failed, check %s/build" "$copydir" + fi + else + true + fi +} + +main "$@" diff --git a/lib/util-msg.sh b/lib/util-msg.sh index 25a5bd8..d0e1271 100644 --- a/lib/util-msg.sh +++ b/lib/util-msg.sh @@ -11,11 +11,9 @@ export LC_MESSAGES=C export LANG=C -disable_colors(){ - unset ALL_OFF BOLD BLUE GREEN RED YELLOW -} +declare ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW='' -enable_colors(){ +if [[ -t 2 ]]; then # prefer terminal safe colored and bold text when tput is supported if tput setaf 0 &>/dev/null; then ALL_OFF="$(tput sgr0)" @@ -32,14 +30,8 @@ enable_colors(){ YELLOW="${BOLD}\e[33m" BLUE="${BOLD}\e[34m" fi - readonly ALL_OFF BOLD BLUE GREEN RED YELLOW -} - -if [[ -t 2 ]]; then - enable_colors -else - disable_colors fi +readonly ALL_OFF BOLD BLUE GREEN RED YELLOW plain() { local mesg=$1; shift diff --git a/lib/util.sh b/lib/util.sh index 4458a86..3ab8366 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -133,8 +133,16 @@ show_elapsed_time(){ info "Time %s: %s minutes" "$1" "$(elapsed_time $2)" } +lock_close() { + local fd=$1 + exec {fd}>&- +} + lock() { - eval "exec $1>"'"$2"' + if ! [[ "/dev/fd/$1" -ef "$2" ]]; then + mkdir -p -- "$(dirname -- "$2")" + eval "exec $1>"'"$2"' + fi if ! flock -n $1; then stat_busy "$3" flock $1 @@ -143,7 +151,10 @@ lock() { } slock() { - eval "exec $1>"'"$2"' + if ! [[ "/dev/fd/$1" -ef "$2" ]]; then + mkdir -p -- "$(dirname -- "$2")" + eval "exec $1>"'"$2"' + fi if ! flock -sn $1; then stat_busy "$3" flock -s $1 @@ -151,15 +162,6 @@ slock() { fi } -check_root() { - (( EUID == 0 )) && return - if type -P sudo >/dev/null; then - exec sudo -- "$@" - else - exec su root -c "$(printf ' %q' "$@")" - fi -} - copy_mirrorlist(){ cp -a /etc/pacman.d/mirrorlist "$1/etc/pacman.d/" } @@ -691,27 +693,27 @@ show_config(){ } # $1: chroot -kill_chroot_process(){ - # enable to have more debug info - #msg "machine-id (etc): $(cat $1/etc/machine-id)" - #[[ -e $1/var/lib/dbus/machine-id ]] && msg "machine-id (lib): $(cat $1/var/lib/dbus/machine-id)" - #msg "running processes: " - #lsof | grep $1 - - local prefix="$1" flink pid name - for root_dir in /proc/*/root; do - flink=$(readlink $root_dir) - if [ "x$flink" != "x" ]; then - if [ "x${flink:0:${#prefix}}" = "x$prefix" ]; then - # this process is in the chroot... - pid=$(basename $(dirname "$root_dir")) - name=$(ps -p $pid -o comm=) - info "Killing chroot process: %s (%s)" "$name" "$pid" - kill -9 "$pid" - fi - fi - done -} +# kill_chroot_process(){ +# # enable to have more debug info +# #msg "machine-id (etc): $(cat $1/etc/machine-id)" +# #[[ -e $1/var/lib/dbus/machine-id ]] && msg "machine-id (lib): $(cat $1/var/lib/dbus/machine-id)" +# #msg "running processes: " +# #lsof | grep $1 +# +# local prefix="$1" flink pid name +# for root_dir in /proc/*/root; do +# flink=$(readlink $root_dir) +# if [ "x$flink" != "x" ]; then +# if [ "x${flink:0:${#prefix}}" = "x$prefix" ]; then +# # this process is in the chroot... +# pid=$(basename $(dirname "$root_dir")) +# name=$(ps -p $pid -o comm=) +# info "Killing chroot process: %s (%s)" "$name" "$pid" +# kill -9 "$pid" +# fi +# fi +# done +# } create_min_fs(){ msg "Creating install root at %s" "$1" @@ -758,21 +760,41 @@ run(){ fi } +orig_argv=("$0" "$@") + +check_root() { + (( EUID == 0 )) && return + if type -P sudo >/dev/null; then + exec sudo -- "${orig_argv[@]}" + else + exec su root -c "$(printf ' %q' "${orig_argv[@]}")" + fi +} + +## +# usage : is_btrfs( $path ) +# return : whether $path is on a btrfs +## is_btrfs() { - [[ -e "$1" && "$(stat -f -c %T "$1")" == btrfs ]] + [[ -e "$1" && "$(stat -f -c %T "$1")" == btrfs ]] } +## +# usage : subvolume_delete_recursive( $path ) +# +# Find all btrfs subvolumes under and including $path and delete them. +## subvolume_delete_recursive() { - local subvol + local subvol - is_btrfs "$1" || return 0 + is_btrfs "$1" || return 0 - while IFS= read -d $'\0' -r subvol; do - if ! btrfs subvolume delete "$subvol" &>/dev/null; then - error "Unable to delete subvolume %s" "$subvol" - return 1 - fi - done < <(find "$1" -xdev -depth -inum 256 -print0) + while IFS= read -d $'\0' -r subvol; do + if ! btrfs subvolume delete "$subvol" &>/dev/null; then + error "Unable to delete subvolume %s" "$subvol" + return 1 + fi + done < <(find "$1" -xdev -depth -inum 256 -print0) - return 0 + return 0 }