#! /bin/bash
# common modules for pbuilder.
#   pbuilder -- personal Debian package builder
#   Copyright (C) 2001-2009 Junichi Uekawa
#
#   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

. "${BASH_SOURCE%/*}/pbuilder-runhooks"

function showhelp () {
    cat <<EOF
pbuilder - a personal builder
Copyright 2001-2007 Junichi Uekawa
Distributed under GNU Public License version 2 or later

pbuilder [operation] [pbuilder-options]
pdebuild [pdebuild-options] -- [pbuilder-options]

command lines:
pbuilder --create [--basetgz base.tgz-path] [--distribution sid|experimental|...]
  Creates a base.tgz

pbuilder --update [--basetgz base.tgz-path] [--distribution sid|experimental|...]
  Updates a base.tgz

pbuilder --build [--basetgz base.tgz-path] pbuilder_2.2.0-1.dsc
  Builds using the base.tgz. Requires a .dsc filename

pbuilder --clean
  Cleans the temporal build directory.

pbuilder --login
pbuilder --execute -- [command] [command-options]
  Logs in to the build environment and execute command.

pbuilder --dumpconfig
  Dumps configuration information to stdout for debugging.

pbuilder-options:
 --basetgz [base.tgz location]
 --buildplace [location of build]
 --mirror [mirror location]
 --othermirror [other mirror location in apt deb-line format, delimited with | signs]
 --http-proxy [proxy]
 --distribution [distribution(sid|experimental|...)]
 --architecture [architecture]
 --components [components]
 --buildresult [location-to-copy-build-result]
 --aptcache [location of retrieved package files]
 --removepackages [packages-to-remove on pbuilder create]
 --extrapackages [packages-to-add on pbuilder create]
 --configfile [configuration file to load]
 --hookdir [hook directory]
 --debemail [mail address]
 --debbuildopts [dpkg-buildpackage options]
 --logfile [filename to output log]
 --pkgname-logfile
 --aptconfdir [overriding apt config dir]
 --timeout [timeout time]
 --override-config
 --binary-arch
 --preserve-buildplace
 --bindmounts [bind-mount-point]
 --debug
 --twice
 --autocleanaptcache
 --compressprog [program]
 --debootstrapopts [debootstrap options]
 --save-after-login/--save-after-exec
 --debootstrap [debootstrap|cdebootstrap]

pdebuild-specific pbuilder-options:
 --pbuilderroot [command to obtain root privilege for pbuilder]
 --pbuildersatisfydepends [command to satisfy build-dependencies]
 --buildsourceroot [command to obtain root privilege for dpkg-buildpackage]
 --use-pdebuild-internal
 --architecture
 --auto-debsign
 --debsign-k [keyid]
EOF
    exit 1
}

# Log a message
# message is of a format
#  E: error message
#  W: warning message
#  I: informational message
function log() {
    case "$*" in
        "E: "*)
            echo "$*" >&2
            ;;
         "W: "*)
            echo "$*" >&2
            ;;
         "I: "*)
            echo "$*"
            ;;
        *)
            echo "malformed log message: $*"
            exit 1
            ;;
    esac
}

log.e() {
    log "E: $*"
}

log.w() {
    log "W: $*"
}

log.i() {
    log "I: $*"
}

# test whether a directory is empty
# fails if "$*" exists but isn't a directory
# fails and outputs garbage if "$*" doesn't actually exist
is_empty_dir() {
  return "$(find "$*" -maxdepth 0 -type d -empty -printf 0 -o -printf 1)"
}

# sanity checks to ensure mountpoint $1 is truly unmounted in $BUILDPLACE
# (fails relatively often to ensure we don't "rm -rf" a bind mount)
function seems_truly_unmounted() {
    local mountpoint
    mountpoint="$1"
    if ! [ -e "$BUILDPLACE/$mountpoint" ]; then
        log "W: $mountpoint doesn't exist"
        return 1
    fi
    if ! [ -d "$BUILDPLACE/$mountpoint" ]; then
        log "W: $mountpoint isn't a directory"
        return 1
    fi
    if [ -r "$BUILDPLACE/proc/mounts" ] && \
        grep -q "^[^ ]* $mountpoint " "$BUILDPLACE/proc/mounts"; then
        log "W: $mountpoint is mounted according to build place's /proc/mounts"
        return 1
    fi
    if [ -r "/proc/mounts" ] && \
        grep -q "^[^ ]* $BUILDPLACE/$mountpoint " "/proc/mounts"; then
        log "W: $mountpoint is mounted according to system's /proc/mounts"
        return 1
    fi
    if ! is_empty_dir "$BUILDPLACE/$mountpoint"; then
        log "W: $mountpoint not empty"
        return 1
    fi
    return 0
}

function umount_one () {
    DEB_BUILD_ARCH_OS=$(dpkg-architecture -qDEB_BUILD_ARCH_OS)
    if [ "${IGNORE_UMOUNT}" = "yes" ]; then
        # support ignore umount option.
        log.i "ignoring umount of $1 filesystem"
        return
    fi
    log.i "unmounting $1 filesystem"
    local UMOUNT_OUTPUT
    if ! UMOUNT_OUTPUT="$(LC_ALL=C umount "$BUILDPLACE/$1" 2>&1)"; then
        log "W: Could not unmount $1: $UMOUNT_OUTPUT"
        local ignore_umount_error="no"
        case $UMOUNT_OUTPUT in
          "umount: "*": not found"|"umount:"*": not mounted")
            # run an additional set of sanity checks
            if seems_truly_unmounted "$1"; then
                ignore_umount_error="yes"
            else
                log "W: Tried ignoring error in unmount, but sanity check failed: $1 might still be mounted"
            fi
            ;;
          *)
            :
            ;;
        esac
        if [ "$ignore_umount_error" != "yes" ]; then
            log "W: Retrying to unmount $1 in 5s"
            sleep 5s
            while ! umount "$BUILDPLACE/$1"; do
                sleep 5s
                cat <<EOF

  Could not unmount $1, some programs might
  still be using files in /proc (klogd?).
  Please check and kill these processes manually
  so that I can unmount $1.  Last umount error was:
$UMOUNT_OUTPUT

  This error only affects chroots; you may want to use
  user-mode-linux to avoid this message.

EOF
                chroot "$BUILDPLACE" bin/sh
            done
        else
            log "W: Ignored error in unmount"
        fi
    fi
}

function umountproc () {
    # push arguments on a stack to reverse direction.
    local reversed
    DEB_BUILD_ARCH_OS=$(dpkg-architecture -qDEB_BUILD_ARCH_OS)
    reversed=
    for mnt in $BINDMOUNTS; do
        reversed="$mnt $reversed"
    done
    for mnt in $reversed; do
        umount_one "$mnt"
    done
    if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
        umount_one "$(grep -m 1 ^selinuxfs /proc/mounts | cut -d ' ' -f 2)"
    fi
    if [ "$DEB_BUILD_ARCH_OS" = "linux" ] && [ "$USEDEVPTS" = "yes" ]; then
        umount_one "dev/pts"
    fi
    if [ "$USEDEVFS" = "yes" ]; then
        umount_one "dev"
    fi
    if [ "$USERUNSHM" = "yes" ] && [ "$DEB_BUILD_ARCH_OS" != "hurd" ]; then
        umount_one "run/shm"
    fi
    if [ "$USEPROC" = "yes" ]; then
        if [ "$DEB_BUILD_ARCH_OS" = "linux" ] && [ -e "$BUILDPLACE/proc/sys/fs/binfmt_misc/status" ]; then
            umount_one "proc/sys/fs/binfmt_misc"
        fi
        umount_one "proc"
    fi
    if [ "$DEB_BUILD_ARCH_OS" = "kfreebsd" ]; then
        umount_one "sys"
    fi
    if [ "$DEB_BUILD_ARCH_OS" = "hurd" ]; then
        umount_one "servers"
        umount_one "dev"

        # Workaround to remove chroot on Hurd: once /dev firmlink is
        # removed, chroot removal either gets stuck or fails by removing
        # some devices.
        for dev in "$BUILDPLACE"/dev/{netdde,tty*,pty*,fd,vcs}; do
            settrans -fg "$dev"
        done
    fi
}


# Mount /proc /dev/pts /dev and bind-mount points
# Also create a policy-rc.d script if it doesn't already exist.
function mountproc () {
    local -a mounted
    DEB_BUILD_ARCH_OS=$(dpkg-architecture -qDEB_BUILD_ARCH_OS)
    if [ "$USEPROC" = "yes" ]; then
        log.i "mounting /proc filesystem"
        mkdir -p "$BUILDPLACE/proc"
        case "$DEB_BUILD_ARCH_OS" in
            kfreebsd)
                PROCFS="linprocfs"
                ;;
            hurd)
                settrans -fg "$BUILDPLACE/proc"
                PROCFS="firmlink"
                ;;
            *)
                PROCFS="proc"
                ;;
        esac
        mount -t "$PROCFS" /proc "$BUILDPLACE/proc" || [ "$DEB_BUILD_ARCH_OS" = hurd ]
        ln -s ../proc/mounts "$BUILDPLACE/etc/mtab" 2> /dev/null || true
        mounted[${#mounted[@]}]="$BUILDPLACE/proc"
    fi
    if [ "$USEDEVFS" = "yes" ]; then
        log.i "mounting /dev filesystem"
        mkdir -p "$BUILDPLACE/dev" || true
        mount -t devfs /dev "$BUILDPLACE/dev"
        mounted[${#mounted[@]}]="$BUILDPLACE/dev"
    fi
    if [ "$DEB_BUILD_ARCH_OS" = "linux" ] && [ "$USERUNSHM" = "yes" ]; then
        log.i "mounting /run/shm filesystem"
        mkdir -p "$BUILDPLACE/run/shm" || true
        mount -t tmpfs tmpfs "$BUILDPLACE/run/shm"
        mounted[${#mounted[@]}]="$BUILDPLACE/run/shm"
    fi
    if [ "$DEB_BUILD_ARCH_OS" = "linux" ] && [ "$USEDEVPTS" = "yes" ]; then
        log.i "mounting /dev/pts filesystem"
        mkdir -p "$BUILDPLACE/dev/pts" || true
        TTYGRP=5
        TTYMODE=620
        [ -f /etc/default/devpts ] && . /etc/default/devpts
        mount -t devpts none "$BUILDPLACE/dev/pts" -onoexec,nosuid,gid=$TTYGRP,mode=$TTYMODE
        mounted[${#mounted[@]}]="$BUILDPLACE/dev/pts"
    fi
    if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
        log.i "mounting selinux filesystem"
        local SELINUX="$(grep -m 1 ^selinuxfs /proc/mounts | cut -d ' ' -f 2)"
        mkdir -p "$BUILDPLACE/$SELINUX"
        mount --bind "$SELINUX" "$BUILDPLACE/$SELINUX"
        mount -o remount,ro,bind "$BUILDPLACE/$SELINUX"
        mounted[${#mounted[@]}]="$BUILDPLACE/$SELINUX"
    fi
    if [ "$DEB_BUILD_ARCH_OS" = "hurd" ]; then
        # /dev and /servers might have already been mounted at
        # debootstrap chroot creation
        mount -t firmlink /dev "$BUILDPLACE/dev" || true
        mounted[${#mounted[@]}]="$BUILDPLACE/dev"
        mount -t firmlink /servers "$BUILDPLACE/servers" || true
        mounted[${#mounted[@]}]="$BUILDPLACE/servers"
    fi
    MOUNTPARAMS="-obind"
    [ "$DEB_BUILD_ARCH_OS" = "kfreebsd" ] && MOUNTPARAMS="-t nullfs"
    for mnt in $BINDMOUNTS; do
        log.i "Mounting $mnt"
        if mkdir -p "$BUILDPLACE/$mnt" &&
            mount $MOUNTPARAMS "$mnt" "$BUILDPLACE/$mnt"; then
            # successful.
            mounted[${#mounted[@]}]="$mnt"
        else
            # this part of code is the only part which is supposed to fail.
            # When unsuccessful, backtrack / umount and abort.
            if [ -n "${mounted[*]}" ]; then
                log.i "error recovery: umount successfully mounted mount-points: ${mounted[@]}"
                for umnt in "${mounted[@]}"; do
                    log.i "umounting $umnt"
                    umount "$umnt"
                done
            fi
            exit 1
        fi
    done
    if [ -f "$BUILDPLACE/usr/sbin/policy-rc.d" ]; then
        log.i "policy-rc.d already exists"
    else
        log.i "installing dummy policy-rc.d"
        echo "\
#!/bin/sh

while true; do
case \"\$1\" in
  -*) shift ;;
  makedev) exit 0;;
  x11-common) exit 0;;
  *)  exit 101;;
esac
done

" >  "$BUILDPLACE/usr/sbin/policy-rc.d"
        chmod a+x "$BUILDPLACE/usr/sbin/policy-rc.d"
    fi
}

## function to clean subdirs, use instead of rm -r
function clean_subdirectories () {
  if [ -z "$1" ]; then
      log "E: Fatal internal error in clean_subdirectories"
      exit 1;
  fi
  if [ ! -d "$1" ]; then
      log "W: directory $1 does not exist in clean_subdirectories"
      return;
  fi
  log.i "removing directory $1 and its subdirectories"
  find "$1" -xdev \( \! -type d \) -print0 |xargs -0 rm -f
  find "$1" -xdev -depth -type d -print0 | \
      (xargs -0 rmdir || true)
}

function cleanbuildplace () {
    if [ "$?" -ne 0 ]; then
        log "W: Aborting with an error";
    fi
    unloadhooks
    if [ "${INTERNAL_BUILD_UML}" != "yes" ]; then
        if [ -d "$BUILDPLACE" ]; then
            # A directory on the same partition as $BUILDPLACE, bind-mounted
            # into $BUILDPLACE, will be cleaned out by clean_subdirectories
            # (because -xdev doesn't know about bind mounts).  To avoid that
            # potential disaster (and also to avoid ugly error messages from
            # rmdir otherwise), we want to make sure that there is *nothing*
            # mounted under the chroot before we do our bulldozer routine.
            #
            # The readlink -f is a simple way to canonicalize the path for
            # $BUILDPLACE (no dirty double slashes for *us*), so it matches
            # what will be in the output of mount.
            if mount |grep -q -F " $(readlink -f "$BUILDPLACE")/"; then
                log "E: Something is still mounted under ${BUILDPLACE}; unmount and remove ${BUILDPLACE} manually"
            else
                log.i "cleaning the build env "
                clean_subdirectories "$BUILDPLACE"
            fi
        fi;
    fi
}

function umountproc_cleanbuildplace () {
    # rolling back to abort.
    if [ "$?" -ne 0 ]; then
        log "W: Aborting with an error";
    fi
    umountproc
    cleanbuildplace
}

function saveaptcache_umountproc_cleanbuildplace () {
    # save the apt cache, and call umountproc_cleanbuildplace
    save_aptcache
    umountproc_cleanbuildplace
}

function installaptlines (){
    log.i "Installing apt-lines"
    rm -f "$BUILDPLACE"/etc/apt/sources.list
    if [ -z "$DISTRIBUTION" ]; then
        log "E: Distribution not specified, please specify"
        exit 1
    fi
    if [ -n "$OTHERMIRROR" ]; then
        echo "$OTHERMIRROR" | tr "|" "\n" >> "$BUILDPLACE"/etc/apt/sources.list
    fi
    if [ -n "$MIRRORSITE" ] ; then
        cat >> "$BUILDPLACE"/etc/apt/sources.list << EOF
deb $MIRRORSITE $DISTRIBUTION $COMPONENTS
#deb-src $MIRRORSITE $DISTRIBUTION $COMPONENTS
EOF
    fi
    if [ -n "$APTCONFDIR" ]; then
        log.i "Copy " "$APTCONFDIR"/* " to chroot"
        cp -a "$APTCONFDIR/"* "$BUILDPLACE"/etc/apt
    fi

    if [ ! -d "$BUILDPLACE"/etc/apt/apt.conf.d ]; then
        log.i "Create /etc/apt/apt.conf.d/ inside chroot"
        mkdir "$BUILDPLACE"/etc/apt/apt.conf.d
    fi

    # configure /etc/apt.conf.d/15pbuilder
    cat > "$BUILDPLACE"/etc/apt/apt.conf.d/15pbuilder <<EOF
APT::Install-Recommends "false";
Acquire::Languages none;
EOF
    if [ -n "$EXPERIMENTAL" ]; then
        log.i "Installing apt-lines and pinning for experimental"
        if [ -n "$MIRRORSITE" ] ; then
            echo "deb $MIRRORSITE experimental main" >> "$BUILDPLACE"/etc/apt/sources.list
            echo "#deb-src $MIRRORSITE experimental main" >> "$BUILDPLACE"/etc/apt/sources.list
        fi
        cat >> "$BUILDPLACE"/etc/apt/apt.conf.d/15pbuilder <<EOF
APT::Default-Release "experimental";
EOF
    fi
}

function copy_local_configuration () {
    log.i "copying local configuration"
    if [ -n "$CONFDIR" ] && [ -d "$CONFDIR" ]; then
        log.i "copying files from $CONFDIR (if possible) instead of using the system ones"
    fi
    for a in hosts hostname resolv.conf mailname; do
        if [ -n "$CONFDIR" ] && [ -f "$CONFDIR/$a" ]; then
            rm -f "$BUILDPLACE/etc/$a"
            cp "$( readlink -f "$CONFDIR/$a" )" "$BUILDPLACE/etc/$a"
        elif [ -f "/etc/$a" ]; then
            rm -f "$BUILDPLACE/etc/$a"
            cp "$( readlink -f "/etc/$a" )" "$BUILDPLACE/etc/$a"
        else
            log "W: No local /etc/$a to copy, relying on $BUILDPLACE/etc/$a to be correct"
        fi
    done
}

function extractbuildplace () {
    # after calling this function, umountproc, and cleanbuildplace
    # needs to be called. Please trap it after calling this function.

    if [ "${INTERNAL_BUILD_UML}" != "yes" -a ! \( "${PRESERVE_BUILDPLACE}" = "yes" -a -d "$BUILDPLACE" \) ]; then
        cleanbuildplace
        log.i "Building the build Environment"
        if ! mkdir -p "$BUILDPLACE"; then
            log "E: failed to build the directory to chroot"
            exit 1
        fi
        log.i "extracting base tarball [${BASETGZ}]"
        if [ ! -f "$BASETGZ" ]; then
            log "E: failed to find $BASETGZ, have you done <pbuilder create> to create your base tarball yet?"
            exit 1
        fi
        if ! (cd "$BUILDPLACE" && tar -x --use-compress-program "$COMPRESSPROG" -p -f "$BASETGZ"); then
            log "E: failed to extract $BASETGZ to $BUILDPLACE"
            exit 1
        fi
    fi
    copy_local_configuration
    loadhooks

    # installaptlines may fail with exit 1, do it earlier than mountproc.
    if [ "$OVERRIDE_APTLINES" = "yes" ]; then
        installaptlines
    else # Warn if override config is not set
        if [ "$OVERRIDE_APTLINES_WARN" = "yes" ]; then
            log "W: --override-config is not set; not updating apt.conf Read the manpage for details."
        fi
    fi

    mountproc
    # FIXME maybe add more checks here? - actually it's not even really needed,
    # since it's created at chroot creation time too.
    mkdir -p "${BUILDPLACE}${BUILDDIR}"
    # XXX added in 0.216, to be deprecated in the future
    # Add a compatibility symlink from the old BUILDDIR (/tmp/buildd) to the new
    # one, if different.  (Yes, people should just fix their scripts to use
    # BUILDDIR, please file a bug if you need that variable to also be available
    # elsewhere other than hook script; given that, I won't do too fancy checks)
    if [ "$BUILDDIR" != '/tmp/buildd' ]; then
        if [ -h "$BUILDPLACE/tmp/buildd" ] && [ "$(readlink -f "$BUILDPLACE/tmp/buildd")" = "${BUILDPLACE}$BUILDDIR" ]; then
            rm "$BUILDPLACE/tmp/buildd"
        fi
        if [ -d "$BUILDPLACE/tmp/buildd" ] && [ ! -h "$BUILDPLACE/tmp/buildd" ]; then
            if [ ! "$(ls -A "$BUILDPLACE/tmp/buildd" 2>&1)" ]; then
                # empty /tmp/buildd, let's change it to a symlink to BUILDDIR
                rmdir "$BUILDPLACE/tmp/buildd"
                ln -rs "${BUILDPLACE}$BUILDDIR" "$BUILDPLACE/tmp/buildd"
            else
                log "W: Could not create compatibility symlink because /tmp/buildd is not empty"
            fi
        elif [ ! -e "$BUILDPLACE/tmp/buildd" ]; then
            ln -rs "${BUILDPLACE}$BUILDDIR" "$BUILDPLACE/tmp/buildd"
        else
            log "W: Could not create compatibility symlink because /tmp/buildd exists and it is not a directory"
        fi
    fi
    executehooks "H"
}

function echobacktime () {
    log.i "Current time: $(date)"
    log.i "pbuilder-time-stamp: $(date +%s)"
}

function recover_aptcache() {
    local doit
    # recover the aptcache archive
    if [ -n "$APTCACHE" ]; then
        if [ "$APTCACHEHARDLINK" = "yes" ]; then
            doit=ln
        else
            doit=cp
        fi
        log.i "Obtaining the cached apt archive contents"
        find "$APTCACHE" -maxdepth 1 -name \*.deb | \
            while read A ; do
            $doit "$A" "$BUILDPLACE/var/cache/apt/archives/" || true
        done
    fi
}

function save_aptcache() {
    # save the current aptcache archive
    # it is safe to call this function several times.
    local doit
    if [ -n "$APTCACHE" ]; then
        log.i "Copying back the cached apt archive contents"
        mkdir -p "$APTCACHE" ;
        if [ "$APTCACHEHARDLINK" = "yes" ]; then
            doit=ln
        else
            doit=cp
        fi
        find "$BUILDPLACE/var/cache/apt/archives/" -maxdepth 1 -name \*.deb | \
            while read A ;do
            if [ ! -f "$APTCACHE/$(basename "$A")" -a -f "$A" ]; then
                log.i "new cache content '$(basename "$A")' added"
                $doit "$A" "$APTCACHE/" || true
            fi
        done
    fi
}

function create_basetgz() {
    # don't pack the hooks in
    unloadhooks
    # create base.tgz
    (
        if ! cd "$BUILDPLACE"; then
            log "E: unexpected error in chdir to $BUILDPLACE"
            exit 1;
        fi
        while test -f "${BASETGZ}.tmp"; do
            log.i "Someone else has lock over ${BASETGZ}.tmp, waiting"
            sleep 10s
        done
        log.i "creating base tarball [${BASETGZ}]"
    if [ -h "$BUILDPLACE/tmp/buildd" ] && [ "$(readlink -f "$BUILDPLACE/tmp/buildd")" = "${BUILDPLACE}$BUILDDIR" ]; then
        rm "$BUILDPLACE/tmp/buildd"
    fi
        if ! tar -c --use-compress-program "$COMPRESSPROG" -f "${BASETGZ}.tmp" ./* ; then
            log "E: failed building base tarball"
            rm -f "${BASETGZ}.tmp"
            exit 1;
        fi
        mv "${BASETGZ}.tmp" "${BASETGZ}"
    )
}

function copyinputfile() {
    # copy files to inside chroot, copy all files specified by INPUTFILE[] parameter.
    TARGETDIR="$1"
    if [ -z "$TARGETDIR" ]; then
        log "E: Unexpected error in copyinputfile"
        exit 1x
    fi
    if [ -n "$INPUTFILE" ]; then
        log.i "copy ${INPUTFILE[*]} to target directory"
        cp "${INPUTFILE[@]}" "${TARGETDIR}"
    fi
}

# all trap hooks that should lead to 'exit'; and error exit.
function cleanbuildplace_trap () {
    trap "" sigpipe sighup
    set +e
    cleanbuildplace
    trap - exit sighup sigpipe
    exit 1
}
function saveaptcache_umountproc_cleanbuildplace_trap () {
    trap "" sigpipe sighup
    set +e
    saveaptcache_umountproc_cleanbuildplace
    trap - exit sighup sigpipe
    exit 1
}
function umountproc_cleanbuildplace_trap () {
    trap "" sigpipe sighup
    set +e
    umountproc_cleanbuildplace
    trap - exit sighup sigpipe
    exit 1
}
function umountproc_trap () {
    trap "" sigpipe sighup
    set +e
    umountproc
    trap - exit sighup sigpipe
    exit 1
}

# copy to .. if target directory is not ..
function conditional_cp_a() {
    local source_file="$1"
    # NOTE: target_dir must not end with /, which is usually the case
    # with 'readlink -f' result, which BUILDRESULT usually is.
    local target_dir="$2"
    # For testability, make cp overridable.
    local cp="${3:-cp}"

    # $PWD should end with non-'/', so dirname should give us the parent dir.
    local parent_dir=$(dirname "$PWD")

    if [ "${parent_dir}" != "${target_dir}" ]; then
        "$cp" -a "$source_file" "$target_dir"
    else
        log.i "file ${source_file} is already in target, not copying."
    fi
}

function add_additional_aptkeyrings() {
# To support package verification inside the repository we may have to import
# additional keys.
    for KEY in "${APTKEYRINGS[@]}"; do
        log.i "adding apt key file ${KEY}."
        $CHROOTEXEC /usr/bin/apt-key add - < "${KEY}" > /dev/null
    done
}

#Setting environmental variables that are really required:
#required for some packages to install...
export LANG=C
export LC_ALL=C