diff options
Diffstat (limited to 'src/chroot-tools')
-rw-r--r-- | src/chroot-tools/Makefile | 3 | ||||
-rwxr-xr-x | src/chroot-tools/chcleanup | 76 | ||||
-rw-r--r-- | src/chroot-tools/chroot.conf | 13 | ||||
-rwxr-xr-x | src/chroot-tools/librechroot | 230 | ||||
-rwxr-xr-x | src/chroot-tools/libremakepkg | 311 |
5 files changed, 633 insertions, 0 deletions
diff --git a/src/chroot-tools/Makefile b/src/chroot-tools/Makefile new file mode 100644 index 0000000..3ae95ea --- /dev/null +++ b/src/chroot-tools/Makefile @@ -0,0 +1,3 @@ +libre_execdir=$(sbindir) +libre_datadir=$(sysconfdir)/libretools.d +include ../../common.mk diff --git a/src/chroot-tools/chcleanup b/src/chroot-tools/chcleanup new file mode 100755 index 0000000..f957d3b --- /dev/null +++ b/src/chroot-tools/chcleanup @@ -0,0 +1,76 @@ +#!/bin/bash -eE +# (c) Nicolás Reynolds <fauno@parabola.nu> +# Released under GPLv3 +# +# Performs chroot cleanup smartly, it only removes the unneeded packages or +# leaves you with a cleansystem +# +# See: HOOKPREBUILD + +DRYRUN=${DRYRUN:-false} + +################################################################################ +# Define these here to avoid having dependencies on outside files + +msg() { + local mesg=$1; shift + printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 +} + +msg2() { + local mesg=$1; shift + printf "${BLUE} ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 +} + +error() { + local mesg=$1; shift + printf "${RED}==> $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 +} + +################################################################################ + +if [[ ! -f /.arch-chroot ]] && ! ${DRYRUN}; then + error "(chcleanup): Must be run inside of a chroot" + exit 1 +fi + +source /etc/libretools.d/chroot.conf +# If we're running makepkg +if [ -f PKGBUILD ]; then + source PKGBUILD + CHROOTEXTRAPKG+=("${depends[@]}" + "${makedepends[@]}" + "${checkdepends[@]}") +fi + +msg "Cleaning chroot..." + +TEMPDIR="$(mktemp --tmpdir -d $(basename $0).XXXXX)" +cp -a /var/lib/pacman/sync "${TEMPDIR}/" +cleanup_log="${TEMPDIR}"/libretools-cleanup.log + +# Get the full list of packages needed by dependencies, including the base system +pacman -b "${TEMPDIR}" \ + -Sp --print-format "%n" \ + base-devel "${CHROOTEXTRAPKG[@]}" \ + >"${cleanup_log}" + +# Diff installed packages against a clean chroot then remove leftovers +packages=($(comm -23 <(pacman -Qq | sort -u) \ + <(sort -u "${cleanup_log}"))) + +RET=0 +if [[ ${#packages[@]} != 0 ]]; then + msg2 "Removing %d packages" ${#packages[@]} + + if ${DRYRUN}; then + echo "${packages[@]}" + else + # Only remove leftovers, -Rcs removes too much + pacman --noconfirm -Rn "${packages[@]}" || RET=$? + fi +fi +# Cleanup +rm -rf "${TEMPDIR}" + +exit $RET diff --git a/src/chroot-tools/chroot.conf b/src/chroot-tools/chroot.conf new file mode 100644 index 0000000..a161a61 --- /dev/null +++ b/src/chroot-tools/chroot.conf @@ -0,0 +1,13 @@ +# The full path to the chroot is +# $CHROOTDIR/$CHROOT/$CHROOTCOPY +# where $CHROOTCOPY is set at runtime, either +# - based on the username +# - set with the `-l COPY` flag +# The purpose of having a $CHROOT setting is that multiple clones of the same +# base $CHROOT can quickly and easily be created. +CHROOTDIR=/var/lib/archbuild +CHROOT=default + +# Extra packages to have installed on the chroot. +# This is in addition to CHROOTPKG=(base-devel) +CHROOTEXTRAPKG=(distcc ccache tsocks libretools) diff --git a/src/chroot-tools/librechroot b/src/chroot-tools/librechroot new file mode 100755 index 0000000..45aec10 --- /dev/null +++ b/src/chroot-tools/librechroot @@ -0,0 +1,230 @@ +#!/bin/bash -euE +# librechroot + +# Copyright 2010 Nicolás Reynolds +# Copyright 2011 Joshua Haase +# Copyright 2012-2013 Luke Shumaker +# +# This file is part of Parabola. +# +# Parabola is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Parabola is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Parabola. If not, see <http://www.gnu.org/licenses/>. + +. /usr/share/libretools/conf.sh +load_conf_libretools_chroot + +. libremessages +. /usr/share/devtools/makechrootpkg.sh + +# Because the makechrootpkg.sh library functions don't work with -euE +normshell() ( + set +euE + "$@" +) + +cmd=${0##*/} +usage() { + echo "Usage: $cmd [OPTIONS] COMMAND [ARGS...]" + echo 'Interacts with an archroot (arch chroot).' + echo '' + echo 'There may be multiple chroots; they are stored in $CHROOTDIR.' + echo '' + echo 'Each chroot is named; the default is configured with $CHROOT.' + echo '' + echo "Each named chroot has a master clean copy (named 'root'), and any" + echo 'number of other named copies; the copy used by default is the' + echo "current username (or \$SUDO_USER, or 'copy' if root)." + echo '' + echo 'The full path to the chroot copy is "$CHROOTDIR/$CHROOT/$COPY",' + echo 'Unless the copy name is manually specified as an absolute path,' + echo 'in which case, that path is used.' + echo '' + echo 'The current settings for the above varibles are:' + echo " CHROOTDIR : $CHROOTDIR" + echo " CHROOT : $CHROOT" + echo " COPY : $COPY" + echo " root path : $rootdir" + echo " copy path : $copydir" + echo '' + echo 'If the chroot, or copy does not exist, it will be created' + echo 'automatically.' + echo '' + echo 'This command will make the following configuration changes in' + echo 'the chroot:' + echo " - overwrite \`/etc/libretools.d/chroot.conf'" + echo " - overwrite \`/etc/pacman.d/mirrorlist'" + echo " - set \`CacheDir' in \`/etc/pacman.conf'" + echo '' + echo 'Creating a copy, deleting a copy, or syncing a copy can be fairly' + echo 'slow; but are very fast if $CHROOTDIR is on a btrfs partition.' + echo '' + echo 'Options:' + echo ' -n <CHROOT> Name of the chroot to use' + echo ' -l <COPY> Name of, or absolute path to, the copy to use' + echo ' -N Disable networking in the chroot' + echo ' -C <file> Location of pacman config file' + echo ' -M <file> Location of makepkg config file' + echo '' + echo 'Commands:' + echo ' Create/copy/delete:' + echo ' noop|make Do not do anything, but still creates the' + echo ' chroot copy if it does not exist' + echo " sync Sync the copy with the clean ('root') copy" + echo " delete delete the chroot copy" + echo ' Dealing with packages:' + echo ' install-file FILES... Like `pacman -U FILES...`' + echo ' install-name NAMES... Like `pacman -S NAMES...`' + echo ' update Like `pacman -Syu`' + echo ' clean-pkgs Remove all "exta" packages from the chroot copy' + echo ' Other:' + echo ' run CMD... Run CMD in the chroot copy' + echo ' enter Enter an interactive shell in the chroot copy' + echo ' clean-repo Clean /repo in the chroot copy' + echo ' help Show this message' # usage +} + +# Globals: $CHROOTDIR, $CHROOT, $COPY, $rootdir and $copydir +main() { + COPY=$LIBREUSER + [[ $COPY != root ]] || COPY=copy + + # defaults + rootdir="${CHROOTDIR}/${CHROOT}/root" + copydir="${CHROOTDIR}/${CHROOT}/${COPY}" + + local mode=enter + local archroot_args=() + while getopts 'n:l:NC:M:' arg; do + case $arg in + n) CHROOT=$OPTARG;; + l) COPY=$OPTARG;; + N) + # We do this so that it carries through to + # chroot_* functions + archroot() { + $(which archroot) -N "$@" + } + ;; + C|M) archroot_args+=(-$arg "$OPTARG");; + *) usage; return 1;; + esac + done + shift $(($OPTIND - 1)) + if [[ $# < 1 ]]; then + error "Must specify a command" + usage + return 1 + fi + mode=$1 + shift + + rootdir="${CHROOTDIR}/${CHROOT}/root" + if [[ ${COPY:0:1} = / ]]; then + copydir=$COPY + else + copydir="${CHROOTDIR}/${CHROOT}/${COPY}" + fi + + ######################################################################## + + if [[ $mode == help ]]; then + usage + return 0 + fi + + if (( EUID )); then + error "This program must be run as root." + return 1 + fi + + umask 0022 + + # Keep this lock as long as we are running + # Note that '9' is the same FD number as in (mk)archroot + lock_open_write 9 "$copydir" \ + "Waiting for existing lock on chroot copy to be released: [$COPY]" + + if [[ ! -d $rootdir ]]; then + msg "Creating 'root' copy for chroot [$CHROOT]" + set +u # if archroot_args is empty, it counts as unbound + archroot "${archroot_args[@]}" -m "$rootdir" base-devel + set -u + fi + + if [[ ! -d $copydir ]] || [[ $mode == sync ]]; then + msg "Syncing copy [$COPY] with root copy" + normshell chroot_sync "$CHROOTDIR/$CHROOT" "$COPY" + fi + + mkdir -p "$copydir/etc/libretools.d" + { + if [[ -n ${CHROOTEXTRAPKG[@]:-} ]]; then + printf 'CHROOTEXTRAPKG=(' + printf "'%s' " "${CHROOTEXTRAPKG[@]}" + printf ')\n' + else + printf 'CHROOTEXTRAPKG=()\n' + fi + } > "$copydir"/etc/libretools.d/chroot.conf + + if [[ $mode != delete ]]; then + # "touch" the chroot first + # this will + # - overwrite \`/etc/pacman.d/mirrorlist'" + # - set \`CacheDir' in \`/etc/pacman.conf'" + # - apply -C or -M flags + set +u # if archroot_args is empty, it counts as unbound + archroot "${archroot_args[@]}" -r "$copydir" true + set -u + fi + + ######################################################################## + + case "$mode" in + # Creat/copy/delete + noop|make|sync) :;; + delete) + if [[ -d $copydir ]]; then + normshell chroot_delete "$copydir" + fi + ;; + + # Dealing with packages + install-file) normshell chroot_install_pkgs "$copydir" "$@";; + install-name) archroot -r "$copydir" pacman -Sy "$@";; + clean-pkgs) + trap "rm -f '$copydir'/clean '$copydir'/chrootexec" EXIT + cp -a "$(which chcleanup)" "$copydir/clean" + echo '#!/bin/bash' > "$copydir/chrootexec" + echo 'mkdir /build' >> "$copydir/chrootexec" + echo 'cd /build; /clean' >> "$copydir/chrootexec" + chmod 755 "$copydir/chrootexec" + archroot -r "$copydir" /chrootexec + ;; + + # Other + run) archroot -r "$copydir" "$@";; + enter) archroot -r "$copydir" bash;; + clean-repo) + rm -rf "${copydir}/repo/*" + bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null + ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db" + ;; + *) + error "Unrecognized command: \`$mode'" + return 1 + ;; + esac +} + +main "$@" diff --git a/src/chroot-tools/libremakepkg b/src/chroot-tools/libremakepkg new file mode 100755 index 0000000..b8cdca1 --- /dev/null +++ b/src/chroot-tools/libremakepkg @@ -0,0 +1,311 @@ +#!/bin/bash -euE +# libremakepkg + +# Copyright 2010 - 2011 Nicolás Reynolds +# Copyright 2011 Joshua Ismael Haase Hernández +# Copyright 2012-2013 Luke Shumaker +# +# This file is part of Parabola. +# +# Parabola is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Parabola is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Parabola. If not, see <http://www.gnu.org/licenses/>. + +. /usr/share/libretools/conf.sh +load_conf_libretools_chroot + +. libremessages + +shopt -s nullglob +umask 0022 + +# Boring/mundane functions ##################################################### + +# End inmediately but print a useful message +trap_exit() { + error "$*" + set +euE + . /usr/share/devtools/makechrootpkg.sh + chroot_copy_out_logs "$@" + exit 1 +} + +# Usage run [-N] $copydir "$cmd" +# Runs cmd properly, whether in a chroot already or not. +# +# Note that $cmd is a quoted string, not a list of arguments. +# $copydir=/ if INCHROOT=true +# +# Environment +# - $INCHROOT is set +run() { + local HASNET=true + [[ $1 == -N ]] && { HASNET=false; shift; } + local copydir=$1; shift + local cmd="$*" + + cat >"$copydir/chrootexec" <<EOF +#!/bin/bash +. /etc/profile +${INCHROOT} || export HOME=/build +${INCHROOT} || cd /build + +${cmd} +EOF + chmod 755 "$copydir/chrootexec" + + local flags='' + if $INCHROOT; then + $HASNET || flags='-n' + unshare $flags -- /chrootexec + else + $HASNET || flags='-N' + librechroot $flags -l "$copydir" run /chrootexec + fi +} + +# Usage: add_to_local_repo $copydir +add_to_local_repo() ( + set +euE + . /usr/share/devtools/makechrootpkg.sh + chroot_add_to_local_repo "$@" +) + +# Usage: chroot_copy_in $copydir +# Environment: +# - In the dirctory of a PKGBUILD +# - $SRCDEST is set +chroot_copy_in() ( + set +euE + . /usr/share/devtools/makechrootpkg.sh + chroot_copy_in "$@" +) + +# Usage: chroot_copy_out $copydir $owner +# Environment: +# - $SRCDEST is set +# - $PKGDEST is set +chroot_copy_out() ( + set +euE + . /usr/share/devtools/makechrootpkg.sh + chroot_copy_out_pkgs "$@" + chroot_copy_out_logs "$@" + chroot_copy_out_srcs "$@" +) + +# Usage: chroot_let_nobody_use_pacman $copydir +chroot_let_nobody_use_pacman() ( + set +euE + . /usr/share/devtools/makechrootpkg.sh + chroot_let_nobody_use_pacman "$@" +) + +# Usage: chroot_init $copydir $repack +# Environment +# - $LIBREHOME is set +chroot_init() { + local copydir=$1 + local repack=$2 + + librechroot -l "$copydir" make # make sure the chroot exists + mkdir -p "$copydir"/{build,pkgdest,srcdest} + + # Remove anything in there UNLESS -R (repack) was passed + $repack || rm -rf "$copydir"/build/* + + if [[ -r "$LIBREHOME/.gnupg/pubring.gpg" ]]; then + install -D "$LIBREHOME/.gnupg/pubring.gpg" "$copydir/build/.gnupg/pubring.gpg" + fi + rm -f "$copydir/build/.makepkg.conf" + + MAKEPKG_CONF="$copydir/etc/makepkg.conf" set_conf_makepkg PKGDEST /pkgdest + MAKEPKG_CONF="$copydir/etc/makepkg.conf" set_conf_makepkg SRCDEST /srcdest + + if grep -q '^\[repo\]' "$copydir/etc/pacman.conf"; then + cat >> "$copydir/etc/makepkg.conf" <<EOF +[repo] +SigLevel = Optional TrustAll +Server = file:///repo +EOF + fi + + chroot_let_nobody_use_pacman "$copydir" +} + +# Core functions ############################################################### + +# Usage: extract +# Extracts the sources (`makepkg -o`) +# Environment: +# - $INCHROOT is set +# - $copydir is set +# - $LIBREUSER is set +extract() { + local user=$LIBREUSER + $INCHROOT || user=nobody + + local clean + if $INCHROOT; then + clean=chcleanup + else + cp -a "$(which chcleanup)" "${copydir}/clean" + clean=/clean + fi + + run "$copydir" "${clean} && sudo -u ${user} makepkg ${makepkg_args} -o" + rm -f "$copydir"/clean +} + +# Usage: build +# Builds the package (`makepkg -e`) +# Environment: +# - $INCHROOT is set +# - $copydir is set +# - $LIBREUSER is set +build() { + local user=$LIBREUSER + $INCHROOT || user=nobody + + run -N "$copydir" "sudo -u ${user} makepkg ${makepkg_args} -e" +} + +# Functions that check for issues with the build ############################### + +check_pkgbuild() { + msg "Checking PKGBUILD for issues" + # TODO + if ! pkgbuild-check-nonfree -f; then + if [[ $? -eq 15 ]]; then + # other errors mean fail, not nonfree + error "PKGBUILD contains non-free issues" + exit 15 + else + warning "PKGBUILD couldn't be check aganist non-free issues" + fi + fi +} + +check_src() { + msg "Checking src directory for issues" + # TODO +} + +check_pkg() { + msg "Checking final package for issues" + # TODO +} + + +# The main program ############################################################# + +cmd=${0##*/} +usage() { + echo "Usage: $cmd [options] [-- makepkg args]" + echo 'This program will build your package.' + echo '' + echo 'If run from outside of a chroot, this will set PKGDEST and' + echo "SRCDEST in the chroot's \`/etc/makepkg.conf', as well as making" + echo "whataver alterations to the chroot \`librechroot' makes." + echo '' + echo "The \`-n' and \`-l' options behave identically to librechroot," + echo 'see the documentation there.' + echo '' + echo 'Options:' + echo ' -n <CHROOT> Name of the chroot to use' + echo ' -l <COPY> Name of, or absolute path to, the copy to use' + echo ' -R Repackage contents of the package without rebuilding' + echo ' -h Show this message' +} + +# Globals: $CHROOTDIR, $CHROOT, $COPY and $copydir +# Globals: $makepkg_args, $INCHROOT +main() { + # Parse command line ################################################### + + COPY=$LIBREUSER + [[ $COPY != root ]] || COPY=copy + + makepkg_args='-s --noconfirm -L ' + local repack=false + + INCHROOT=false + if [[ -f /.arch-chroot ]]; then + INCHROOT=true + fi + + while getopts 'n:l:Rh' arg ; do + case "${arg}" in + n) CHROOT=$OPTARG;; + l) COPY=$OPTARG;; + R) repack=true; makepkg_args+=" -R";; + h) usage; return 0;; + *) usage; return 1;; + esac + done + shift $(($OPTIND - 1)) + # Pass all arguments after -- right to makepkg + makepkg_args+=" $*" + + if $INCHROOT; then + copydir='/' + elif [[ ${COPY:0:1} = / ]]; then + copydir=$COPY + else + copydir="${CHROOTDIR}/${CHROOT}/${COPY}" + fi + + # Init ################################################################# + + if (( EUID )); then + error "This script must be run as root" + exit 1 + fi + + if [[ ! -f PKGBUILD ]]; then + # This is the message used by makepkg + error "PKGBUILD does not exist." + exit 1 + fi + + # Trap signals from makepkg + trap 'trap_exit "(libremakepkg): TERM signal caught. Exiting..."' TERM HUP QUIT + trap 'trap_exit "(libremakepkg): Aborted by user! Exiting..."' INT + trap 'trap_exit "(libremakepkg): An error has occurred. Exiting..."' ERR + + SRCDEST="$(get_conf_makepkg SRCDEST .)" + PKGDEST="$(get_conf_makepkg PKGDEST .)" + + # OK, we're starting now ############################################### + + $INCHROOT || lock_open_write 9 "$copydir" \ + "Waiting for existing lock on chroot copy to be released: [$COPY]" + + # Set target CARCH as it might be used within the PKGBUILD to select + # correct sources + MAKEPKG_CONF=$copydir/etc/makepkg.conf + export CARCH="$(get_conf_makepkg CARCH)" + unset MAKEPKG_CONF + + $INCHROOT || chroot_init "$copydir" "$repack" + + check_pkgbuild + $INCHROOT || chroot_copy_in "$copydir" + $repack || extract + check_src + build + check_pkg + + add_to_local_repo "$copydir" + $INCHROOT || chroot_copy_out "$copydir" "$LIBREUSER" +} + +main "$@" |