#!/bin/bash # LibreChRoot # Enters a chroot # Copyright 2010 Nicolás Reynolds # Copyright 2011 Joshua Haase # Copyright 2012 Luke Shumaker # ---------- GNU General Public License 3 ---------- # 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 . . /etc/libretools.conf cmd=${0##*/} lock_open_write() { local fd=$1 local path=$2 local msg=$3 # Only reopen the FD if it wasn't handed to us if [[ $(readlink -f /dev/fd/$fd) != "${path}.lock" ]]; then exec $fd>"${path}.lock" fi if ! flock -n $fd; then stat_busy "$msg" flock $fd stat_done fi } lock_open_read() { local fd=$1 local path=$2 local msg=$3 # Only reopen the FD if it wasn't handed to us if [[ $(readlink -f /dev/fd/$fd) != "${path}.lock" ]]; then exec $fd>"${path}.lock" fi if ! flock -sn $fd; then stat_busy "$msg" flock -s $fd stat_done fi } lock_close() { local fd=$1 exec $fd>&- } clean_pacman() { msg "Cleaning chroot with pacman: ${copydir}" cp -a "$(dirname $0)/chcleanup" "${copydir}/clean" mkarchroot -r "cd /build; /clean" "${copydir}" #mkarchroot "${copydir}" base base-devel sudo "${CHROOTEXTRAPKG[@]}" } clean_repo() { msg "Cleaning repo for chroot: ${copydir}" if [ -d "${copydir}/repo" ]; then find "${copydir}/repo/" -mindepth 1 -delete else mkdir -p "${copydir}/repo" fi bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db" } ## # This function is almost verbatim from makechrootpkg ## sync() { if [[ $CHROOTCOPY = root ]]; then error "Cannot sync the root copy with itself" exit 1 fi # Note that '9' is the same FD number as in mkarchroot lock_open_write 9 "$copydir" "Locking chroot copy '$copy'" lock_open_read 8 "$rootdir" "Locking clean chroot" stat_busy 'Creating clean working copy' local use_rsync=false if type -P btrfs >/dev/null; then [[ -d $copydir ]] && btrfs subvolume delete "$copydir" &>/dev/null btrfs subvolume snapshot "$chrootdir/root" "$copydir" &>/dev/null || use_rsync=true else use_rsync=true fi if $use_rsync; then mkdir -p "$copydir" rsync -a --delete -q -W -x "$CHROOTDIR/$CHROOT/root/" "$copydir" fi stat_done lock_close 8 lock_close 9 } update() { msg "Updating chroot: ${copydir}" mkarchroot -u "${copydir}" } enter() { msg "Entering chroot: ${copydir}" mkarchroot -r "bash" "${copydir}" } usage() { echo "Usage: $cmd [OPTIONS] [CHROOT]" echo 'Interacts with a chroot.' echo '' echo "The default CHROOT is \`${CHROOT}'." echo '' echo 'Options:' echo ' Settings:' echo " -d Use this dir instead of \`${CHROOTDIR}'" echo ' -l Use this as the chroot copy instead of basing it' echo ' on the username' echo ' Modes:' echo ' -h Show this message' echo ' -c Clean the chroot using pacman' echo " -C Clean the chroot by syncing it with 'root' copy" echo ' -r Clean /repo in the chroot' echo ' -u Update the chroot' } main() { # The logic for setting CHROOTCOPY is mirred from makechrootpkg CHROOTCOPY=$USER [[ -n $SUDO_USER ]] && CHROOTCOPY=$SUDO_USER [[ -z $CHROOTCOPY || $CHROOTCOPY = root ]] && CHROOTCOPY=copy local mode=enter while getopts 'hrcud:l:' arg; do case $arg in d) CHROOTDIR=$OPTARG;; l) CHROOTCOPY=$OPTARG;; c) mode=clean_pacman;; C) mode=sync;; r) mode=clean_repo;; u) mode=update;; h) usage; exit 0;; *) usage; exit 1;; esac done shift $(($OPTIND - 1)) case $# in 0) :;; 1) CHROOT="$1";; *) usage; exit 1;; esac # not local rootdir="${CHROOTDIR}/${CHROOT}/root" copydir="${CHROOTDIR}/${CHROOT}/${CHROOTCOPY}" if (( EUID )); then error "This script must be run as root." exit 1 fi if [[ ! -d $rootdir ]]; then libremkchroot -d "$CHROOTDIR" "$CHROOT" fi if [[ ! -d $copydir ]] && [[ $mode != sync ]]; then sync fi case "$mode" in clean_pacman) clean_pacman; exit $?;; clean_repo) clean_repo; exit $?;; update) update; exit $?;; enter) enter; exit $?;; esac } main "$@"