diff options
Diffstat (limited to 'src/chroot-tools')
-rw-r--r-- | src/chroot-tools/Makefile | 21 | ||||
-rwxr-xr-x | src/chroot-tools/chcleanup | 13 | ||||
-rwxr-xr-x | src/chroot-tools/distcc-tool | 16 | ||||
-rw-r--r-- | src/chroot-tools/hooks-chcleanup.sh | 7 | ||||
-rw-r--r-- | src/chroot-tools/hooks-check.sh | 25 | ||||
-rw-r--r-- | src/chroot-tools/hooks-distcc.sh | 2 | ||||
-rwxr-xr-x | src/chroot-tools/indent | 35 | ||||
-rwxr-xr-x | src/chroot-tools/librechroot | 132 | ||||
-rwxr-xr-x | src/chroot-tools/libremakepkg | 146 | ||||
-rw-r--r-- | src/chroot-tools/makechrootpkg.sh.patch | 120 |
10 files changed, 366 insertions, 151 deletions
diff --git a/src/chroot-tools/Makefile b/src/chroot-tools/Makefile index 0540636..97ca688 100644 --- a/src/chroot-tools/Makefile +++ b/src/chroot-tools/Makefile @@ -1,11 +1,13 @@ # These files are coming from devtools copy_files = makechrootpkg.sh.in mkarchroot.in arch-nspawn.in # These are programs that we will use internally, but shouldn't be in PATH -libexecs = mkarchroot arch-nspawn distcc-tool chcleanup +libexecs = mkarchroot arch-nspawn distcc-tool chcleanup indent no-progs = $(libexecs) # These are the shell libraries we will use libs = makechrootpkg.sh $(wildcard hooks-*.sh) +pots = $(libexecs) $(libs) + pkglibexecdir = $(libexecdir)/libretools/chroot clean_files = makechrootpkg.sh.ugly* *~ include ../../common.mk @@ -25,20 +27,19 @@ makechrootpkg.sh.in: %.sh.in: $(devtoolsdir)/%.in cp $< $@ makechrootpkg.sh.ugly: %.ugly: %.in %.patch Makefile cp $*.in $@ - @echo 'PATCH $@ $*.patch'; patch $@ $*.patch || { rm -f -- '$@'; false; } + @echo 'PATCH $@ $*.patch'; patch $@ $*.patch makechrootpkg.sh: %: %.ugly Makefile - @echo 'EDIT < $< > $@'; $(edit) <'$<' >'$@' || { rm -f -- '$@'; false; } - @echo 'INDENT $@'; $(call indent,$@) || { rm -f -- '$@'; false; } + @echo 'EDIT < $< > $@'; $(edit) <'$<' >'$@' + @echo 'INDENT $@'; $(call indent,$@) mkarchroot: mkarchroot.in Makefile @echo '< $< M4_EDIT | SED > $@' - @<'$<' $(edit) | sed 's|arch-nspawn|$$(librelib chroot/&)|' >'$@' || { rm -f -- '$@'; false; } - @echo 'CHMOD $<'; chmod 755 "$@" || { rm -f -- '$@'; false; } + @<'$<' $(edit) | sed -e 's|arch-nspawn|$$(librelib chroot/&)|' -e 's/pacstrap/env -i &/' >'$@' + @echo 'CHMOD $<'; chmod 755 "$@" archroot: %: %.in Makefile @echo "GEN $@" - @$(edit) <"$<" >"$@" || { rm -f -- '$@'; false; } - @chmod 755 "$@" || { rm -f -- '$@'; false; } + @$(edit) <"$<" >"$@" + @chmod 755 "$@" -distcc-tool.pot: distcc-tool - xgettext --omit-header -i --from-code=UTF-8 -L shell --keyword={error,errusage} -o $@ $< +distcc-tool.pot: xgettext-keywords-sh+=--keyword=errusage diff --git a/src/chroot-tools/chcleanup b/src/chroot-tools/chcleanup index a43065b..9ad121e 100755 --- a/src/chroot-tools/chcleanup +++ b/src/chroot-tools/chcleanup @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -eE -# (c) Nicolás Reynolds <fauno@parabola.nu> +# Copyright (C) Nicolás Reynolds <fauno@parabola.nu> # Released under GPLv3 # # Performs chroot cleanup smartly, it only removes the unneeded packages or @@ -53,19 +53,18 @@ fi source /etc/libretools.d/chroot.conf # If we're running makepkg -if [ -f PKGBUILD ]; then +if [[ -f PKGBUILD ]]; then export CARCH="$(. /etc/makepkg.conf; printf '%s' "$CARCH")" - source PKGBUILD + source ./PKGBUILD CHROOTEXTRAPKG+=("${depends[@]}" "${makedepends[@]}" "${checkdepends[@]}") fi msg "Cleaning chroot..." -msg2 "Fetching updated package lists..." -pacman -Sy || { - warning "There was an error updating package lists, ignoring." -} + +# Sync the local repo with pacman +cp /repo/repo.db /var/lib/pacman/sync/repo.db # Setup the temporary directory TEMPDIR="$(mktemp --tmpdir -d $(basename $0).XXXXX)" diff --git a/src/chroot-tools/distcc-tool b/src/chroot-tools/distcc-tool index 7633029..9f78ead 100755 --- a/src/chroot-tools/distcc-tool +++ b/src/chroot-tools/distcc-tool @@ -2,7 +2,7 @@ # -*- tab-width: 4; sh-basic-offset: 4 -*- # distcc-tool -# Copyright 2013 Luke Shumaker +# Copyright (C) 2013-2014 Luke Shumaker # # This file is part of Parabola. # @@ -32,6 +32,8 @@ if ! type gettext &>/dev/null; then gettext() { echo "$@"; } fi +q0="$(printf '%q' "$0")" # quoted $0 + panic() { echo "$(gettext 'panic: malformed call to internal function')" >&2 exit 1 @@ -50,7 +52,7 @@ print() { } usage() { - print "Usage: $0 COMMAND [COMMAND-ARGS]" + print "Usage: %s COMMAND [COMMAND-ARGS]" "$q0" print "Tool for using distcc within a networkless chroot" echo print "Commands:" @@ -125,7 +127,7 @@ parse_DISTCC_HOSTS() { *@*) # SSH_HOST doesn't allow custom port numbers, and even if it # did, ssh would complain about MITM. Instead, we'll count on - # ssh ProxyCommand being configured to used `client`. + # ssh ProxyCommand being configured to use `client`. newhosts+=("$HOSTSPEC") ;; # GLOBAL_OPTION @@ -135,7 +137,7 @@ parse_DISTCC_HOSTS() { ;; # ZEROCONF +zeroconf) - error "%s does not support the +zeroconf option" "$0" + error "%s does not support the +zeroconf option" "$q0" exit 1 ;; # TCP_HOST or OLDSTYLE_TCP_HOST @@ -159,7 +161,7 @@ parse_DISTCC_HOSTS() { # set up port forwaring if $forward_ports; then - socat TCP-LISTEN:${newport},fork SYSTEM:"$0 client $HOSTID ${PORT:-3632}" & + socat TCP-LISTEN:${newport},fork SYSTEM:"$q0 client $HOSTID ${PORT:-3632}" & pids+=($!) fi @@ -222,8 +224,8 @@ odaemon() { local chrootpath=$1 umask 111 - socat UNIX-LISTEN:"$chrootpath/socket",fork SYSTEM:"$0 server" & - trap "kill -- $!; rm -f '$chrootpath/socket'" EXIT + socat UNIX-LISTEN:"$chrootpath/socket",fork SYSTEM:"$q0 server" & + trap "kill -- $!; rm -f -- $(printf '%q' "$chrootpath/socket")" EXIT wait } diff --git a/src/chroot-tools/hooks-chcleanup.sh b/src/chroot-tools/hooks-chcleanup.sh index 09e6dd9..86c872c 100644 --- a/src/chroot-tools/hooks-chcleanup.sh +++ b/src/chroot-tools/hooks-chcleanup.sh @@ -1,16 +1,15 @@ #!/usr/bin/env bash set -euE -hooks_pre_build+=("clean_chroot") +hook_pre_build+=("clean_chroot") clean_chroot() ( set +x local copydir=$1 if $INCHROOT; then - cd /build + cd /startdir sudo -u nobody "$(librelib chroot/chcleanup)" else - librechroot -l "$copydir" clean-pkgs + librechroot "${librechroot_flags[@]}" clean-pkgs fi - r=$?; echo clean_chroot returning $r; return $r ) diff --git a/src/chroot-tools/hooks-check.sh b/src/chroot-tools/hooks-check.sh index e8120b8..2702f95 100644 --- a/src/chroot-tools/hooks-check.sh +++ b/src/chroot-tools/hooks-check.sh @@ -1,30 +1,11 @@ #!/usr/bin/env bash set -euE -hook_check_pkgbuild+=("check_pkgbuild_dependencies") -check_pkgbuild_dependencies() { +hook_check_pkgbuild+=("check_pkgbuild_nonfree") +check_pkgbuild_nonfree() { local s=0 sudo -EH -u "$LIBREUSER" pkgbuild-check-nonfree -f || s=$? - case $s in - 0) :;; - 15) error "This PKGBUILD links to known unfree packages"; return 1;; - *) warning "pkgbuild-check-nonfree failed to run";; - esac -} - -hook_check_pkgbuild+=("check_pkgbuild_license") -check_pkgbuild_license() { - local s=0 - sudo -EH -u "$LIBREUSER" pkgbuild-check-licenses -f || s=$? - for i in 1 2 4; do - if [[ $i -eq $(($s & $i)) ]]; then - case $i in - 1) warning "pkgbuild-check-licenses encountered an error";; - 2) warning "This PKGBUILD has an uncommon license";; - 4) error "This PKGBUILD has a known nonfree license"; ret=1;; - esac - fi - done + pkgbuild-summarize-nonfree $s } #hook_check_pkgbuild+=("check_pkgbuild_namcap") diff --git a/src/chroot-tools/hooks-distcc.sh b/src/chroot-tools/hooks-distcc.sh index 9e42242..d8d708a 100644 --- a/src/chroot-tools/hooks-distcc.sh +++ b/src/chroot-tools/hooks-distcc.sh @@ -75,7 +75,7 @@ distcc_stop() { if [[ -f "$copydir/run/distcc-tool.pid" ]]; then - odaemon=$(cat "$copydir/distcc-tool.pid") + odaemon=$(< "$copydir/distcc-tool.pid") kill -- "$odaemon" rm -f -- \ diff --git a/src/chroot-tools/indent b/src/chroot-tools/indent new file mode 100755 index 0000000..0e2d0e0 --- /dev/null +++ b/src/chroot-tools/indent @@ -0,0 +1,35 @@ +#!/usr/bin/env perl +use warnings; +use strict; +use constant BUFFER_SIZE => 40; +binmode(STDIN); +binmode(STDOUT); + +exit(1) if ($#ARGV != 0); +my $indent = $ARGV[0]; + +my $print_indent = 1; +my $buffer; +my $size; +my $c; +while (1) { + $size = sysread(STDIN, $buffer, BUFFER_SIZE); + last if ($size < 1); + for (0..$size-1) { + $c = substr($buffer, $_, 1); + if ($c eq "\n") { + syswrite(STDOUT, $indent) if ($print_indent); + # XXX: SYSTEMD-STDOUT HACK + #syswrite(STDOUT, $c, 1); + syswrite(STDOUT, "\r\n", 2); + $print_indent = 1; + } elsif ($c eq "\r") { + syswrite(STDOUT, $c, 1); + $print_indent = 1; + } else { + syswrite(STDOUT, $indent) if ($print_indent); + syswrite(STDOUT, $c, 1); + $print_indent = 0; + } + } +} diff --git a/src/chroot-tools/librechroot b/src/chroot-tools/librechroot index 0b3ad43..051148d 100755 --- a/src/chroot-tools/librechroot +++ b/src/chroot-tools/librechroot @@ -2,9 +2,9 @@ set -euE # librechroot -# Copyright 2010 Nicolás Reynolds -# Copyright 2011 Joshua Haase -# Copyright 2012-2013 Luke Shumaker +# Copyright (C) 2010 Nicolás Reynolds +# Copyright (C) 2011 Joshua Haase +# Copyright (C) 2012-2014 Luke Shumaker # # This file is part of Parabola. # @@ -21,10 +21,11 @@ set -euE # You should have received a copy of the GNU General Public License # along with Parabola. If not, see <http://www.gnu.org/licenses/>. -# HACKING: if a command is added or removed, it must be changed in 3 places: +# HACKING: if a command is added or removed, it must be changed in 4 places: # - the usage() text # - the commands=() array -# - the case statement in main() +# - the case statement in main() that checks the number of arguments +# - the case statement in main() that runs them . $(librelib conf) load_files chroot @@ -88,16 +89,16 @@ usage() { 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 varibles are:' + 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 + 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. + 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 @@ -136,8 +137,8 @@ usage() { 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 `/build/PKGBUILD` in - the chroot copy' + as a dependency in the file `/startdir/PKGBUILD` + in the chroot copy' print ' Other:' flag "run $(_ CMD...)" 'Run CMD in the chroot copy' flag 'enter' 'Enter an interactive shell in the chroot copy' @@ -150,7 +151,7 @@ readonly commands=( run enter clean-repo help ) -# set $rootdir and $copydir; blank them on error +# 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. @@ -174,12 +175,37 @@ calculate_directories() { declare -p copydir } +check_mountpoint() { + local file=$1 + local mountpoint="$(df -P "$file"|sed '1d;s/.*\s//')" + local mountopts=($(LC_ALL=C mount|awk "{ if (\$3==\"$mountpoint\") { gsub(/[(,)]/, \" \", \$6); print \$6 } }")) + ! in_array nosuid "${mountopts[@]}" && ! in_array noexec "${mountopts[@]}" +} + arch_nspawn_flags=() sysd_nspawn_flags=() arch-nspawn() { local copydir=$1; shift + # XXX: SYSTEMD-STDOUT HACK + if [[ -t 1 ]]; then + cmd=("$@") + else + # This perl script is similar to `sed 's|\n|\r\n|g'`, (or, more + # correctly, `sed 's|$|\r|'`) but it does't line-buffer. + local perlcmd=' +my $size; +my $buffer; +while(1) { + $size=sysread(STDIN, $buffer, 40); + last if ($size < 1); + $buffer =~ s/\n/\r\n/g; + syswrite(STDOUT, $buffer); +}' + cmd=(bash --noprofile --norc -c "set -o pipefail; $(printf '%q ' "$@") |& perl -e $(printf '%q' "$perlcmd")") + fi + set +u # if an array is empty, it counts as unbound - "$_arch_nspawn" "${arch_nspawn_flags[@]}" "$copydir" "${sysd_nspawn_flags[@]}" -- "$@" + "$_arch_nspawn" "${arch_nspawn_flags[@]}" "$copydir" "${sysd_nspawn_flags[@]}" -- "${cmd[@]}" set -u } @@ -197,22 +223,65 @@ main() { C|M) arch_nspawn_flags+=(-$opt "$OPTARG");; w) sysd_nspawn_flags+=("--bind=$OPTARG");; r) sysd_nspawn_flags+=("--bind-ro=$OPTARG");; - *) usage >/dev/stderr; return 1;; + *) usage >&2; return 1;; esac done shift $(($OPTIND - 1)) if [[ $# -lt 1 ]]; then error "Must specify a command" - usage >/dev/stderr + usage >&2 return 1 fi mode=$1 if ! in_array "$mode" "${commands[@]}"; then error "Unrecognized command: %s" "$mode" - usage >/dev/stderr + usage >&2 return 1 fi shift + case "$mode" in + 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 1 + fi + :;; + install-file) + if [[ $# -lt 1 ]]; then + error 'Command `%s` requires at least one file' "$mode" + usage >&2 + return 1 + 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 1 + fi + fi + :;; + install-name) + if [[ $# -lt 1 ]]; then + error 'Command `%s` requires at least one package name' "$mode" + usage >&2 + return 1 + fi + :;; + run) + if [[ $# -lt 1 ]]; then + error 'Command `%s` requires at least one argument' "$mode" + usage >&2 + return 1 + fi + :;; + esac + if [[ $mode == help ]]; then usage @@ -236,11 +305,28 @@ main() { umask 0022 + # XXX: SYSTEMD-STDIN HACK + if ! [[ -t 0 ]]; then + error "Input is not a TTY" + plain "https://labs.parabola.nu/issues/420" + plain "https://bugs.freedesktop.org/show_bug.cgi?id=70290" + prose "Due to a bug in systemd-nspawn, redirecting stdin is not + supported. We have been able to mitigate the problems + with redirecting stdout, but until the bug is fixed, + redirecting stdin will only end in pain." >&2 + return 1 + fi + # Keep this lock 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 ! check_mountpoint "$copydir.lock"; then + error "Chroot copy is mounted with nosuid or noexec options: [%s]" "$COPY" + return 1 + fi + if [[ ! -d $rootdir ]]; then msg "Creating 'root' copy for chroot [%s]" "$CHROOT" set +u # if an array is empty, it counts as unbound @@ -256,10 +342,12 @@ main() { mkdir -p "$copydir/etc/libretools.d" { - if [[ -n ${CHROOTEXTRAPKG[*]:-} ]]; then - declare -p CHROOTEXTRAPKG | sed -r 's/declare( -.)* //' + if [[ ${#CHROOTEXTRAPKG[*]} -eq 0 ]]; then + echo 'CHROOTEXTRAPKG=()' else - printf 'CHROOTEXTRAPKG=()\n' + printf 'CHROOTEXTRAPKG=(' + printf '%q ' "${CHROOTEXTRAPKG[@]}" + printf ')\n' fi } > "$copydir"/etc/libretools.d/chroot.conf @@ -293,15 +381,17 @@ main() { arch-nspawn "$copydir" pacman -Sy "$@" ;; update) - arch-nspawn "$copydir" pacman -Syu --noconfirm + # umount resolv.conf so that it can be upgraded, if nescessary + # this disables DNS, so fetch everything first + arch-nspawn "$copydir" bash -c 'pacman -Syuw --noconfirm && umount /etc/resolv.conf && pacman -Su --noconfirm' ;; clean-pkgs) trap "rm -f '$copydir'/bin/chcleanup '$copydir'/chrootexec" EXIT install -m755 "$(librelib chroot/chcleanup)" "$copydir/bin/chcleanup" printf '%s\n' \ '#!/bin/bash' \ - 'mkdir -p /build' \ - 'cd /build' \ + 'mkdir -p /startdir' \ + 'cd /startdir' \ '/bin/chcleanup' \ > "$copydir/chrootexec" chmod 755 "$copydir/chrootexec" diff --git a/src/chroot-tools/libremakepkg b/src/chroot-tools/libremakepkg index a59315b..26080bc 100755 --- a/src/chroot-tools/libremakepkg +++ b/src/chroot-tools/libremakepkg @@ -2,9 +2,9 @@ set -euE # libremakepkg -# Copyright 2010-2011 Nicolás Reynolds -# Copyright 2011 Joshua Ismael Haase Hernández -# Copyright 2012-2013 Luke Shumaker +# Copyright (C) 2010-2011 Nicolás Reynolds +# Copyright (C) 2011 Joshua Ismael Haase Hernández +# Copyright (C) 2012-2014 Luke Shumaker # # This file is part of Parabola. # @@ -25,15 +25,18 @@ set -euE . $(librelib messages) . $(librelib chroot/makechrootpkg.sh) +set -o pipefail shopt -s nullglob umask 0022 # Global variables: +readonly _indent="$(librelib chroot/indent)" readonly INCHROOT=$([[ -f /.arch-chroot ]] && echo true || echo false) NONET=true # can be changed with the -N flag -# {SRC,LOG,PKG}DEST set at runtime by makepkg.conf +# {PKG,SRC,SRCPKG,LOG}DEST set at runtime by makepkg.conf # MAKEFLAGS, PACKAGER set at runtime by makepkg.conf # LIBREUSER, LIBREHOME are set by conf.sh +librechroot_flags=() # Hooks ######################################################################## @@ -47,6 +50,25 @@ hook_check_pkg=(:) # Boring/mundane functions ##################################################### +indent() { + "$_indent" ' | ' +} + +# Usage: _check_perms_dir $directory +# Make sure that $directory is readable and executable (searchable) by 'nobody' +check_directory_permissions() ( + local dir=$1 + # `cd` to the directory, then test `.`; that way if parent + # directories aren't readable, we aren't testing for that. We + # only need the last element in `$dir`. + cd "$dir" + if ! sudo -u nobody test -r . -a -x .; then + error "Directory '%s' must be readable by user 'nobody'" "$dir" + return 1 + fi + return 0 +) + # Usage: exit_copy $copydir $src_owner # End immediately, but copy log files out exit_copy() { @@ -62,17 +84,18 @@ exit_copy() { run_hook() { local hookname=$1; shift local hookvar="hook_${hookname}[@]" + local fails=() - msg "Running hook: %s" "$hookname" for hook in "${!hookvar}"; do - msg2 'hook: %s' "$hook" - "$hook" "$@" || { error "result: %s" $?; fails+=("$hook"); } - done + "$hook" "$@" || fails+=("$hook") + done |& indent + if [[ ${#fails[@]} -gt 0 ]]; then error "Failure(s) in %s: %s" "$hookname" "${fails[*]}" return 1 + else + return 0 fi - return 0 } # Usage: add_to_local_repo $copydir $pkgfiles... @@ -88,25 +111,32 @@ add_to_local_repo() { done } +hook_post_build+=('cleanup') +cleanup() { + local copydir=$1 + rm -f -- "$copydir"/chroot{prepare,build} +} + build() ( local copydir=$1; shift - local cmd=(/chrootbuild "$@") + local repack=$1; shift - run_hook pre_build "$copydir" - trap "run_hook post_build '$copydir'" EXIT - - local netflag='' + local run_ynet=() + local run_nnet=() if $INCHROOT; then - ! $NONET || netflag='-n' - unshare $netflag -- "${cmd[@]}" + run_ynet=(unshare) + run_nnet=(unshare -n) else - ! $NONET || netflag='-N' - librechroot $netflag \ - -r "$PWD:/startdir_host" \ - -r "$SRCDEST:/srcdest_host" \ - -l "$copydir" \ - run "${cmd[@]}" + run_ynet=(librechroot "${librechroot_flags[@]}" run) + run_nnet=(librechroot "${librechroot_flags[@]}" -N run) fi + $NONET || run_nnet=("${run_ynet[@]}") + + prepare_chroot "$copydir" "$LIBREHOME" "$repack" false + "${run_ynet[@]}" /chrootprepare false "$@" |& indent + run_hook pre_build "$copydir" + trap "run_hook post_build '$copydir'" EXIT + "${run_nnet[@]}" /chrootbuild false "$@" |& indent ) # The main program ############################################################# @@ -118,7 +148,7 @@ usage() { prose 'If run from outside of a chroot, command will make the following configuration changes in the chroot:' bullet 'whatever changes `librechroot` makes.' - bullet 'set `PKGDEST` and `SRCDEST` in `/etc/makepkg.conf`' + bullet 'set `{PKG,SRC,SRCPKG,LOG}DEST` in `/etc/makepkg.conf`' bullet 'set `PACKAGER` in `/etc/makepkg.conf` to reflect the value outside of the chroot.' bullet '(maybe) delete `/build/.makepkg.conf`' @@ -134,8 +164,12 @@ usage() { the documentation there.' echo print 'Options:' + print ' %s options:' librechroot flag "-n <$(_ CHROOT)>" 'Name of the chroot to use' flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the chroot copy to use' + flag "-w <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read/write' + flag "-r <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read-only' + print ' %s options:' libremakepkg flag '-N' "Don't disable networking during build() and package(). PLEASE don't use this unless you have a special reason, its use is a violation @@ -159,10 +193,14 @@ main() { local chroot='' # Parse command line options ########################################### - while getopts 'n:l:NRh' flag ; do + while getopts 'n:l:w:r:NRh' flag ; do case "${flag}" in - n) if $INCHROOT; then err_chflag "$flag"; else chroot=$OPTARG; fi;; - l) if $INCHROOT; then err_chflag "$flag"; else copy=$OPTARG; fi;; + n) if $INCHROOT; then err_chflag "$flag"; else + chroot=$OPTARG; fi;; + l) if $INCHROOT; then err_chflag "$flag"; else + copy=$OPTARG; fi;; + w|r) if $INCHROOT; then err_chflag "$flag"; else + librechroot_flags+=(-$flag "$OPTARG"); fi;; N) NONET=false;; R) repack=true; makepkg_args+=(-R);; h) usage; return 0;; @@ -190,6 +228,15 @@ main() { fi unset chroot + # Load makepkg configuration ########################################### + # Note that all of these are globals + PKGDEST="$(get_var makepkg PKGDEST "$PWD")" + SRCDEST="$(get_var makepkg SRCDEST "$PWD")" + SRCPKGDEST="$(get_var makepkg SRCPKGDEST "$PWD")" + LOGDEST="$(get_var makepkg LOGDEST "$PWD")" + MAKEFLAGS="$(get_var makepkg MAKEFLAGS '')" + PACKAGER="$(get_var makepkg PACKAGER '')" + # Quick sanity check ################################################### if (( EUID )); then @@ -203,14 +250,17 @@ main() { exit 1 fi - # Load makepkg configuration ########################################### - # Note that all of these are globals - SRCDEST="$(get_conf_makepkg SRCDEST "$PWD")" - PKGDEST="$(get_conf_makepkg PKGDEST "$PWD")" - LOGDEST="$(get_conf_makepkg LOGDEST "$PWD")" - mkdir -p "$SRCDEST" "$PKGDEST" "$LOGDEST" - MAKEFLAGS="$(get_conf_makepkg MAKEFLAGS '')" - PACKAGER="$(get_conf_makepkg PACKAGER '')" + # Make sure that the various *DEST directories exist + mkdir -p -- "$PKGDEST" "$SRCDEST" "$SRCPKGDEST" "$LOGDEST" + # Check the permissions for $startdir and $SRCDEST + ( + declare -i ret=0 + check_directory_permissions "$PWD" || ret=1 + if ! [[ "$PWD" -ef "$SRCDEST" ]]; then + check_directory_permissions "$SRCDEST" || ret=1 + fi + exit $ret + ) # OK, we are starting now ############################################## @@ -218,32 +268,40 @@ main() { lock 9 "/build/.lock" \ "Waiting for existing lock on build directory to be released" else + librechroot_flags+=( + -r "$PWD:/startdir_host" + -r "$SRCDEST:/srcdest_host" + -n "$CHROOT" + -l "$copy" + ) + # Obtain a lock on the chroot lock 9 "$copydir.lock" \ "Waiting for existing lock on chroot copy to be released: [%s]" "$copy" # Create the chroot if it does not exist - librechroot -n "$CHROOT" -l "$copy" make + msg 'Initializing the chroot...' + librechroot "${librechroot_flags[@]}" make |& indent fi # Set target CARCH # note that we waited until after locking/creating the chroot to do this - export CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_conf_makepkg CARCH)" + export CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_var makepkg CARCH)" # Pre-build + msg 'Starting pre-build activities...' run_hook check_pkgbuild - download_sources "$copydir" "$LIBREUSER" - prepare_chroot "$copydir" "$LIBREHOME" "$repack" false - clean_chroot "$copydir" + msg 'Downloading sources...' + download_sources "$copydir" "$LIBREUSER" |& indent # Build + msg 'Starting to build the package...' trap "exit_copy '$copydir' '$LIBREUSER'" EXIT - warning 'Entering build...' - build "$copydir" "${makepkg_args[@]}" + build "$copydir" "$repack" "${makepkg_args[@]}" + # Post-build - warning 'Entering hook check_pkg...' + msg 'Starting post-build activities...' run_hook check_pkg - warning 'Entering add_to_local_repo ...' - add_to_local_repo "$copydir" "$copydir"/pkgdest/*.pkg.tar* + add_to_local_repo "$copydir" "$copydir"/pkgdest/*.pkg.tar* |& indent } main "$@" diff --git a/src/chroot-tools/makechrootpkg.sh.patch b/src/chroot-tools/makechrootpkg.sh.patch index f5b8ed7..540e6ba 100644 --- a/src/chroot-tools/makechrootpkg.sh.patch +++ b/src/chroot-tools/makechrootpkg.sh.patch @@ -1,5 +1,5 @@ ---- makechrootpkg.sh.in 2013-09-08 23:01:20.000000000 -0400 -+++ makechrootpkg.sh.ugly 2013-09-09 15:43:06.000000000 -0400 +--- makechrootpkg.sh.in 2014-01-05 18:51:41.463720929 -0500 ++++ makechrootpkg.sh.ugly 2014-02-09 20:20:25.021630727 -0500 @@ -12,6 +12,7 @@ shopt -s nullglob @@ -8,8 +8,8 @@ _makepkg_args=(-s --noconfirm -L --holdver) makepkg_args=("${_makepkg_args[@]}") repack=false -@@ -26,9 +27,10 @@ - declare -i ret=0 +@@ -29,9 +30,10 @@ + bindmounts_rw=() copy=$USER -[[ -n $SUDO_USER ]] && copy=$SUDO_USER @@ -20,15 +20,15 @@ usage() { echo "Usage: ${0##*/} [options] -r <chrootdir> [--] [makepkg args]" -@@ -62,6 +64,7 @@ +@@ -67,6 +69,7 @@ exit 1 } +parse_options_init() { - while getopts 'hcur:I:l:nT' arg; do + while getopts 'hcur:I:l:nTD:d:' arg; do case "$arg" in h) usage ;; -@@ -86,9 +89,6 @@ +@@ -93,9 +96,6 @@ [[ ! -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" @@ -38,9 +38,9 @@ if [[ ${copy:0:1} = / ]]; then copydir=$copy else -@@ -103,30 +103,47 @@ - repack=true - fi +@@ -115,30 +115,48 @@ + esac + done -if [[ -n $SUDO_USER ]]; then +if [[ -n ${SUDO_USER:-} ]]; then @@ -54,8 +54,9 @@ +# Usage: load_vars $makepkg_conf +# Globals: +# - SRCDEST -+# - LOGDEST ++# - SRCPKGDEST +# - PKGDEST ++# - LOGDEST +# - MAKEFLAGS +# - PACKAGER load_vars() { @@ -63,7 +64,7 @@ [[ -f $makepkg_conf ]] || return 1 - for var in {SRC,PKG,LOG}DEST MAKEFLAGS PACKAGER; do + for var in {SRC,SRCPKG,PKG,LOG}DEST MAKEFLAGS PACKAGER; do - [[ -z ${!var} ]] && eval $(grep "^${var}=" "$makepkg_conf") + [[ -z ${!var:-} ]] && eval $(grep "^${var}=" "$makepkg_conf") done @@ -92,7 +93,7 @@ # 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" -@@ -147,10 +164,15 @@ +@@ -159,11 +177,16 @@ # Drop the read lock again lock_close 8 @@ -100,6 +101,7 @@ } -clean_temporary() { +- stat_busy "Removing temporary copy [%s]" "$copy" +# Usage: delete_chroot $copydir [$copy] +delete_chroot() { + local copydir=$1 @@ -107,10 +109,11 @@ + # Detect chrootdir filesystem type + local chroottype=$(stat -f -c %T "$copydir") + - stat_busy "Removing temporary copy [%s]" "$copy" - if [[ "$chroottype" == btrfs ]]; then ++ stat_busy "Removing chroot copy [%s]" "$copy" + if [[ "$chroottype" == btrfs ]] && ! mountpoint -q "$copydir"; then btrfs subvolume delete "$copydir" >/dev/null || -@@ -166,9 +188,14 @@ + die "Unable to delete subvolume %s" "$copydir" +@@ -178,9 +201,14 @@ stat_done } @@ -125,7 +128,7 @@ for install_pkg in "${install_pkgs[@]}"; do pkgname="${install_pkg##*/}" cp "$install_pkg" "$copydir/$pkgname" -@@ -179,11 +206,19 @@ +@@ -193,11 +221,19 @@ rm "$copydir/$pkgname" done @@ -147,9 +150,9 @@ $repack || rm -rf "$copydir/build" mkdir -p "$copydir/build" -@@ -217,12 +252,12 @@ +@@ -236,12 +272,12 @@ - chown -R nobody "$copydir"/{build,pkgdest,logdest,srcdest,startdir} + chown -R nobody "$copydir"/{build,pkgdest,srcpkgdest,logdest,srcdest,startdir} - if [[ -n $MAKEFLAGS ]]; then + if [[ -n ${MAKEFLAGS:-} ]]; then @@ -162,22 +165,26 @@ sed -i '/^PACKAGER=/d' "$copydir/etc/makepkg.conf" echo "PACKAGER='${PACKAGER}'" >> "$copydir/etc/makepkg.conf" fi -@@ -235,6 +270,14 @@ +@@ -254,20 +290,38 @@ chmod 440 "$copydir/etc/sudoers.d/nobody-pacman" fi + if ! grep -q '^\[repo\]' "$copydir/etc/pacman.conf"; then -+ cat >> "$copydir/etc/pacman.conf" <<EOF -+[repo] ++ local line=$(grep -n '^\[' "$copydir/etc/pacman.conf" |grep -Fv ':[options]'|sed 's/:.*//;1q') ++ local ins='[repo] +SigLevel = Optional TrustAll +Server = file:///repo -+EOF ++' ++ sed -i "${line}i${ins//$'\n'/\n}" "$copydir/etc/pacman.conf" + fi + # This is a little gross, but this way the script is recreated every time in the # working copy ++ printf $'#!/bin/bash\n%s\n_chrootprepare "$@"' "$(declare -f _chrootprepare)" \ ++ > "$copydir/chrootprepare" ++ chmod +x "$copydir/chrootprepare" printf $'#!/bin/bash\n%s\n_chrootbuild %q "$@"' "$(declare -f _chrootbuild)" \ -@@ -242,13 +285,19 @@ + "$run_namcap" >"$copydir/chrootbuild" chmod +x "$copydir/chrootbuild" } @@ -199,7 +206,7 @@ makepkg --config="$copydir/etc/makepkg.conf" --verifysource -o else ( export SRCDEST BUILDDIR="$builddir" -@@ -258,7 +307,7 @@ +@@ -277,10 +331,10 @@ (( $? != 0 )) && die "Could not download sources." # Clean up garbage from verifysource @@ -207,8 +214,20 @@ + rm -rf "$builddir" } - _chrootbuild() { -@@ -295,6 +344,7 @@ +-_chrootbuild() { ++_chrootprepare() { + # This function isn't run in makechrootpkg, + # so no global variables + local run_namcap="$1"; shift +@@ -291,6 +345,7 @@ + shopt -s nullglob + + # XXX: Workaround makepkg disliking read-only dirs ++ rm -rf -- /srcdest/* /startdir/* + ln -sft /srcdest /srcdest_host/* + ln -sft /startdir /startdir_host/* + +@@ -316,11 +371,29 @@ # Safety check if [[ ! -w PKGBUILD ]]; then @@ -216,7 +235,30 @@ echo "Can't write to PKGBUILD!" exit 1 fi -@@ -312,12 +362,24 @@ + +- sudo -u nobody makepkg "${makepkg_args[@]}" || exit 1 ++ # Sync deps now, as networking may be disabled during _chrootbuild ++ cp /repo/repo.db /var/lib/pacman/sync/repo.db ++ sudo -u nobody makepkg "${makepkg_args[@]}" -o ++} ++ ++_chrootbuild() { ++ # This function isn't run in makechrootpkg, ++ # so no global variables ++ local run_namcap="$1"; shift ++ local makepkg_args=("$@") ++ ++ . /etc/profile ++ export HOME=/build ++ shopt -s nullglob ++ ++ cd /startdir ++ ++ sudo -u nobody makepkg "${makepkg_args[@]}" -e || exit 1 + + if $run_namcap; then + pacman -S --needed --noconfirm namcap +@@ -333,12 +406,24 @@ exit 0 } @@ -239,9 +281,9 @@ + local l for l in "$copydir"/logdest/*; do + [[ $l == */logpipe.* ]] && continue chown "$src_owner" "$l" - mv "$l" "$LOGDEST" -@@ -325,6 +387,10 @@ +@@ -352,6 +437,10 @@ } # }}} @@ -252,9 +294,9 @@ umask 0022 load_vars /etc/makepkg.conf -@@ -335,27 +401,37 @@ - [[ -d $SRCDEST ]] || SRCDEST=$PWD - [[ -d $LOGDEST ]] || LOGDEST=$PWD +@@ -363,30 +452,45 @@ + [[ -d $SRCPKGDEST ]] || SRCPKGDEST=$PWD + [[ -d $LOGDEST ]] || LOGDEST=$PWD -create_chroot +# Lock the chroot we want to use. We'll keep this lock until we exit. @@ -264,7 +306,9 @@ + sync_chroot "$chrootdir" "$copy" +fi - $update_first && arch-nspawn "$copydir" pacman -Syu --noconfirm + $update_first && arch-nspawn "$copydir" \ + "${bindmounts_ro[@]}" "${bindmounts_rw[@]}" \ + pacman -Syu --noconfirm -[[ -n ${install_pkgs[*]} ]] && install_packages +if [[ -n ${install_pkgs[*]:-} ]]; then @@ -283,6 +327,12 @@ if arch-nspawn "$copydir" \ --bind-ro="$PWD:/startdir_host" \ --bind-ro="$SRCDEST:/srcdest_host" \ + "${bindmounts_ro[@]}" "${bindmounts_rw[@]}" \ ++ /chrootprepare && ++ arch-nspawn "$copydir" \ ++ --bind-ro="$PWD:/startdir_host" \ ++ --bind-ro="$SRCDEST:/srcdest_host" \ ++ "${bindmounts_ro[@]}" "${bindmounts_rw[@]}" \ /chrootbuild "${makepkg_args[@]}" then - move_products @@ -296,7 +346,7 @@ if (( ret != 0 )); then if $temp_chroot; then -@@ -366,3 +442,4 @@ +@@ -397,3 +501,4 @@ else true fi |