#!/bin/sh # ------- # File: chroot-tool # Description: Simple script to prepare environment to run commands in a chrooted directory # Author: Luis Garcia Gisbert # # This program 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 2 of the License, or # (at your option) any later version. # # This program 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 this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA # -------- CHT_REQ_BIND_DIRS="/dev /proc /sys" # export CHT_BIND_DIRS to get additional directories available to chroot CHT_BIND_DIRS="${CHT_BIND_DIRS} /tmp /net" BIND_DIRS="$CHT_REQ_BIND_DIRS $CHT_BIND_DIRS" DPKG_DIVERT="/usr/sbin/dpkg-divert" # export CHT_LOCAL_FILES and/or CHT_DIVERT_FILES CHT_LOCAL_FILES="$CHT_LOCAL_FILES /etc/resolv.conf" ALTERNATE_DIR="/usr/share/chroot-tool" if [ -d "${ALTERNATE_DIR}" ] ; then for f in $(find ${ALTERNATE_DIR} -type f -printf "%P\n") ; do CHT_DIVERT_FILES="$CHT_DIVERT_FILES /${f}" done fi #****f chroot-tool/chroot_divert # NAME # chroot_divert -- divert/restore a single file in chroot # SYNOPSIS # removes/restores files in the chroot. chroot_divert(){ f="$2" f_div="${f}.chroot-tool" f_alt="$3" F="${CHROOT_DIR}${f}" F_DIV="${CHROOT_DIR}${f_div}" if [ "$1" = "divert" ] ; then # do diversion if [ -x "${CHROOT_DIR}${DPKG_DIVERT}" ] ; then # OK use dpkg-diversion method chroot $CHROOT_DIR ${DPKG_DIVERT} --divert ${f_div} --rename ${f} || true else # poor man's method if [ -f "${F}" -a ! -f "${F_DIV}" ] ; then mv -f "${F}" "${F_DIV}" fi fi if [ "$f_alt" -a -f "$f_alt" ] ; then # install replacememnt cp -f "$f_alt" "$F" fi else # remove diversions rm -f "${F}" if [ -x "${CHROOT_DIR}${DPKG_DIVERT}" ] ; then # OK use dpkg-diversion method chroot $CHROOT_DIR ${DPKG_DIVERT} --rename --remove ${f} || true else # poor man's method if [ -f "${F_DIV}" ] ; then mv -f "${F_DIV}" "${F}" fi fi fi } already_mounted(){ if mount |grep -q "^$1\b.*\b${CHROOT_DIR}${d}\b.*\(\bbind\b\)" ; then return 0 fi return 1 } die(){ while [ "$1" ] ; do echo "$1" >&2 shift done unbind_dirs exit 1 } mount_dir(){ if ! already_mounted "$1" ; then if ! mount --bind "$1" "${CHROOT_DIR}${1}" 2>/dev/null >/dev/null ; then return 1 fi fi return 0 } bind_dirs(){ for d in $CHT_REQ_BIND_DIRS ; do [ -d "${d}" -a -d "${CHROOT_DIR}${d}" ] || return 1 mount_dir "$d" || return 1 done for d in $CHT_BIND_DIRS ; do mount_dir "$d" || true done return 0 } bind_dirs_verbose(){ bind_dirs || die "Error, unable to bind some of the required dirs: $BIND_DIRS" return 0 } unbind_dirs(){ for d in $BIND_DIRS ; do umount "${CHROOT_DIR}${d}" 2>/dev/null >/dev/null || true done return 0 } prepare_chroot(){ for f in $CHT_REMOVE_FILES ; do chroot_divert divert "$f" done for f in $CHT_LOCAL_FILES ; do chroot_divert divert "$f" "$f" done for f in $CHT_DIVERT_FILES ; do chroot_divert divert "$f" "${ALTERNATE_DIR}${f}" done } restore_chroot(){ for f in $CHT_REMOVE_FILES $CHT_LOCAL_FILES $CHT_DIVERT_FILES ; do chroot_divert restore "$f" done } usage(){ die "Usage: $0 {chroot|bind|unbind} CHROOT_DIR" \ " $0 run CHROOT_DIR COMMAND_CMD" } # main # tests [ $(id -u) -eq 0 ] || die "Please, run this program as root" ACTION="$1" CHROOT_DIR="$2" [ "$CHROOT_DIR" -a -d "$CHROOT_DIR" ] || usage shift 2 case $ACTION in bind) bind_dirs_verbose ;; unbind) unbind_dirs ;; chroot) bind_dirs_verbose prepare_chroot chroot $CHROOT_DIR || true restore_chroot unbind_dirs ;; run) [ "$1" ] || usage bind_dirs_verbose prepare_chroot chroot $CHROOT_DIR "$@" || true restore_chroot unbind_dirs ;; *) usage ;; esac exit 0