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


function showhelp () {
    cat <<EOF
pbuilder - a personal builder
Copyright 2001-2006 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 sarge|etch|sid|experimental]
  Creates a base.tgz

pbuilder update [--basetgz base.tgz-path] [--distribution sarge|etch|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(sarge|sid|etch|experimental)]
 --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
 --autocleanaptcache
 --debootstrapopts [debootstrap options]
 --save-after-login/--save-after-exec
 --debootstrap [debootstrap|cdebootstrap]

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

function umount_one () {
    if [ "${IGNORE_UMOUNT}" = "yes" ]; then
	# support ignore umount option.
	echo " -> ignoring umount of $1 filesystem"
	return
    fi
    echo " -> unmounting $1 filesystem"
    if ! umount "$BUILDPLACE/$1"; then
	    echo "W: Retrying to unmount $1"
	    sleep 5s
	    while ! umount "$BUILDPLACE/$1"; do
		sleep 5s
		cat <<EOF

  Could not unmount $1, there might be some program 
  still using files in /proc (klogd?).
  Please check and kill the process manually so that I can unmount $1

  This error is only happens with chroot; try using user-mode-linux to 
  avoid this message.

EOF
		chroot "$BUILDPLACE" bin/sh
	    done
	fi
}

function umountproc () {
    if [ "$USEDEVPTS" = "yes" ]; then
	umount_one "dev/pts"
    fi
    if [ "$USEDEVFS" = "yes" ]; then
	umount_one "dev"
    fi
    if [ "$USEPROC" = "yes" ]; then
	if [ -e $BUILDPLACE/proc/sys/fs/binfmt_misc/status ]; then
	    umount_one "proc/sys/fs/binfmt_misc"
	fi
	umount_one "proc"
    fi
    for mnt in $BINDMOUNTS; do
	umount_one "$mnt"
    done
}


# Mount /proc /dev/pts /dev and bind-mount points
# Also create a policy-rc.d script if it doesn't already exist.
function mountproc () {
    if [ "$USEPROC" = "yes" ]; then
	echo " -> mounting /proc filesystem"
	mkdir -p $BUILDPLACE/proc
	mount -t proc /proc "$BUILDPLACE/proc"
	ln -s ../proc/mounts $BUILDPLACE/etc/mtab 2> /dev/null || true
    fi
    if [ "$USEDEVFS" = "yes" ]; then
	echo " -> mounting /dev filesystem"
	mkdir -p $BUILDPLACE/dev || true
	mount -t devfs /dev "$BUILDPLACE/dev" 
    fi
    if [ "$USEDEVPTS" = "yes" ]; then
	echo " -> mounting /dev/pts filesystem"
	mkdir -p $BUILDPLACE/dev/pts || true
	mount -t devpts /dev/pts "$BUILDPLACE/dev/pts" 
    fi
    for mnt in $BINDMOUNTS; do
	echo "-> Mounting $mnt"
	mkdir -p "$BUILDPLACE/$mnt"
	mount -obind "$mnt" "$BUILDPLACE/$mnt"
    done
    if [ -f "$BUILDPLACE/usr/sbin/policy-rc.d" ]; then
	echo " -> policy-rc.d already exists"
    else
	echo " -> 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
      echo "Fatal internal error in clean_subdirectories"
      exit 1;
  fi
  if [ ! -d "$1" ]; then
      echo "Warning: directory $1 does not exist in clean_subdirectories"
      return;
  fi
  echo "    -> 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
	echo " -> Aborting with an error";
    fi
    if [ "${INTERNAL_BUILD_UML}" != "yes" ]; then
	if [ -d "$BUILDPLACE" ]; then 
	    echo " -> cleaning the build env "
	    clean_subdirectories "$BUILDPLACE"
	fi;
    fi
}

function umountproc_cleanbuildplace () {
    # rolling back to abort.
    if [ "$?" -ne 0 ]; then
	echo " -> 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 (){
    echo "  -> Installing apt-lines"
    rm -f "$BUILDPLACE"/etc/apt/sources.list
    if [ -z "$DISTRIBUTION" ]; then
	echo "Distribution not specified, please specify" >&2
	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 main 
#deb-src $MIRRORSITE $DISTRIBUTION main
EOF
    fi
    if [ -n "$APTCONFDIR" ]; then
	echo "  -> Copy " "$APTCONFDIR"/* " to chroot"
	cp -a "$APTCONFDIR/"* "$BUILDPLACE"/etc/apt
    fi
		  
    if [ -n "$EXPERIMENTAL" ]; then
	echo "  -> 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 << EOF
APT::Default-Release "experimental";
EOF
    fi
}

function copy_local_configuration () {
    echo " -> copying local configuration"
    for a in hosts hostname resolv.conf; do 
	rm -f "$BUILDPLACE/etc/$a"
	if [ ! -f "/etc/$a" ]; then
	    echo "E: /etc/$a does not exist, your setup is insane. fix it" >&2
	fi
	cp $( readlink -f "/etc/$a" ) "$BUILDPLACE/etc/$a";
    done
}

function extractbuildplace () {
    # after calling this function, umountproc, and cleanbuildplace
    # needs to be called. Please trap it.
    if [ "${INTERNAL_BUILD_UML}" != "yes" -a ! \( "${PRESERVE_BUILDPLACE}" = "yes" -a -d "$BUILDPLACE" \) ]; then
	cleanbuildplace
	echo "Building the build Environment"
	if ! mkdir -p "$BUILDPLACE"; then
	    echo "E: failed to build the directory to chroot"
	    exit 1
	fi
	echo " -> extracting base tarball [${BASETGZ}]"
	if [ ! -f "$BASETGZ" ]; then
	    echo "E: failed to find $BASETGZ, have you done <pbuilder create> to create your base tarball yet?"
	    exit 1
	fi
	if ! (cd "$BUILDPLACE" && tar xfzp "$BASETGZ"); then
	    echo "E: failed to extract $BASETGZ to $BUILDPLACE"
	    exit 1
	fi
	echo " -> creating local configuration"
	hostname -f > "$BUILDPLACE/etc/mailname"
    fi
    copy_local_configuration
    mountproc
    mkdir -p "$BUILDPLACE/tmp/buildd"
    
    if [ "$OVERRIDE_APTLINES" = "yes" ]; then
	installaptlines
    fi
}


function recover_aptcache() {
    local doit
    # recover the aptcache archive
    if [ -n "$APTCACHE" ]; then
	if [ "$APTCACHEHARDLINK" = "yes" ]; then
	    doit=ln
	else
	    doit=cp
	fi
	echo "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
	echo "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
		echo " -> new cache content "$(basename "$A")" added"
		$doit "$A" "$APTCACHE/" || true
	    fi
	done
    fi
}

function create_basetgz() {
    # create base.tgz
    ( 
	if ! cd "$BUILDPLACE"; then
	    echo "Error: unexpected error in chdir to $BUILDPLACE" >&2
	    exit 1;
	fi
	while test -f "${BASETGZ}.tmp"; do
	    echo "  -> Someone else has lock over ${BASETGZ}.tmp, waiting"
	    sleep 10s
	done
	echo " -> creating base tarball [${BASETGZ}]"
	if ! tar cfz "${BASETGZ}.tmp" * ; then
	    echo " -> failed building base tarball"
	    rm -f "${BASETGZ}.tmp"
	    exit 1;
	fi
	mv "${BASETGZ}.tmp" "${BASETGZ}"
    )
}

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