#!/bin/bash


help()
{
    echo "Usage: `basename $0` [-v] [-h] [-X] [-A] directory" ;
    echo
    echo "Used to chroot into a build environment created by build-env." ;
    echo "In addition to calling chroot, this command copies a few" ;
    echo "config files from the host machine into the chroot environment," ;
    echo "and makes sure /proc and /dev are properly mounted and unmounted" ;
    echo "in the chroot environment" ;
    echo
    echo "Options:"
    echo
    echo "	-X	Allow access to host's X server"
    echo "	-A	Allow access to host's ssh-agent server"
    echo "	-v	Verbose. Runs with set -xv"
    echo "	-h	Print this help"
    echo "	-<sig>	Unknown option is passed on to 'kill' as a signal."
}

SEMAPHORE=".use-env-count"

enter () {
    if [ -e "$SEMAPHORE" ] ; then
	COUNT=$(cat $SEMAPHORE)
	COUNT=$((COUNT+1))
	echo $COUNT >$SEMAPHORE
	INUSE=true
    else
	INUSE=false
	echo 1 >$SEMAPHORE
    fi
    $INUSE
}

leave () {
    if [ -e "$SEMAPHORE" ] ; then
	COUNT=$(cat $SEMAPHORE)
	COUNT=$((COUNT-1))
	if [ "$COUNT" = "0" ] ; then
	    rm $SEMAPHORE
	    INUSE=false
	else 
	    echo $COUNT >$SEMAPHORE
	    INUSE=true
	fi
    else
	echo $0: error, semaphore does not exist
	exit 1
    fi
    $INUSE
}

show () {
    if [ -e $SEMAPHORE ] ; then
	COUNT=$(cat $SEMAPHORE)
	echo "SEMAPHORE=Just $COUNT"
    else
	echo SEMAPHORE=Nothing.
    fi
}

testSemaphore () {
    case "$1" in
	+) if enter ; then echo someone is already here ; else echo you are the only one here ; fi ; show ;;
	-) if leave ; then echo leaving someone behind ; else echo close the door on your way out; fi ; show ;;
	.) show ;;
	"") show ;;
	*) echo $0: unknown option $1 ; exit 1 ;;
    esac
}

# Copy a file or directory, but only if the src exists and the
# destination does not
# Note: if you specify a file as the first
# argument, the second argument must also be a filename.

maybe_cp ()
{
    if [[ -e "$1" &&  ! -e "$2" ]] ; then
	cp "$1" "$2"
    fi
}

# Kill all the process with current working directory $1
# written by dsf.
kill_by_cwd () {
    SIG=
    
    if [ "$SIG" = "" ]; then SIG="-TERM"; fi
    
    if [ ! -e $1 ]; then exit 0; fi
    DIR="`readlink -f $1`"
    if [ ! "$DIR" ]; then exit 1; fi
    
    # Kill processes whose cwd begins with $DIR
    
    PIDS=""
    
    pushd /proc > /dev/null
    
    ls -1d [0-9]* |
    while read i; do
	if readlink /proc/$i/cwd | grep -q "^$DIR"; then
	    ps uw $i
	    if [ "$NODO" != "yes" ]; then kill $SIG $i; fi
	fi
    done

    popd > /dev/null
}

# Called when the chroot environment is exited
 
cleanup()
{

    echo Cleaning up....

    # Disabled, because the semantics are not clear
    # with the new enter/leave semantics

    # Allow the user to do some cleanup while still in the chroot
    # with /proc and /dev mounted.
    if false ; then 
	if [ -e $HOME/.build-env/use-env.post1 ] ; then
	    . $HOME/.build-env/use-env.post1
	fi
    fi

    # Kill any processes started in the chroot, so they don't hold
    # file handle open in /proc or /dev
    kill_by_cwd "$1"

    umount $1/sys
    umount $1/dev
    umount $1/proc

    for o in $OPTIONS ; do
	case $o in
	    X11) echo "Disabling X access." ;
		umount $1/tmp/.X11-unix ;;
	    SSH) echo "Disabling SSH agent access." ;
		umount $1$SSH_AUTH_SOCK_DIR ;;
	esac  
    done

    # Disabled, because the semantics are not clear
    # with the new enter/leave semantics

    # Allow the user to do some cleanup after exiting the chroot
    # and umount /dev and /proc

    if false ; then 
	if [ -e $HOME/.build-env/use-env.post2 ] ; then
	    . $HOME/.build-env/use-env.post2
	fi
    fi
    
    # Restore daemon tools.
    deneuter $1/sbin/start-stop-daemon
    deneuter $1/sbin/invoke-rc.d

    echo done.
    exit 0
}


function neuter()
{
    prog=$1
    if [ -f $prog ] ; then
	mv $prog ${prog}.real
	(echo "#!/bin/bash"; echo "exit 0") > $prog
	chmod +x $prog
    fi
}

function deneuter()
{
    prog=$1
    if [ -f ${prog}.real ] ; then
	rm -f $prog
	mv $prog.real $prog
    fi
}



### Main ####

OPTIONS=""

# Process options
while [ "${1#-}" != "$1" ]; do
  case "$1" in
    -v) set -xv; shift;;
    -X) OPTIONS="X11 $OPTIONS"; shift;;
    -A) OPTIONS="SSH $OPTIONS"; shift;;
    -h) help ; exit 0 ;;
    *) echo "$0: Unexpected argument $1"; exit 1; ;;
  esac
done

# Make sure a directory was specified
if [ -e "$1" ]; then 
    ROOT="$1"
    CHROOT_CMD="chroot $*"
else
    help ;
    exit 1;
fi 

prepare () {
    # copy in things that we will probably want in the chroot environment
    # only copy if the destination file do not exist in case the user
    # wants to modify them.

    maybe_cp /etc/hosts $1/etc/hosts ;
    maybe_cp /etc/mailname $1/etc/mailname ;
    maybe_cp /etc/resolv.conf $1/etc/resolv.conf ;
    maybe_cp /etc/dupload.conf $1/etc/dupload.conf ;

    if [[ -d $HOME/.ssh  && ! -d $1$HOME/.ssh ]] ; then
	cp -a $HOME/.ssh $1$HOME/
    fi

    # things to copy everytime
    if [ -e ~/.Xauthority ] ; then cp ~/.Xauthority $1$HOME/ ; fi

    # Ask me no questions and I'll tell you no lies.
    export DEBIAN_FRONTEND="noninteractive"
    export PS1="[ue: `basename $1`] \w\\$ " 
    export debian_chroot=`basename $1`

    mount -t proc none $1/proc
    if [[ `grep devfs /proc/filesystems` ]] ; then
	mount -t devfs  none $1/dev
    fi
    mount -t sysfs sysfs $1/sys

    for o in $OPTIONS ; do
	case $o in
	    X11) echo "Enabling X access." ;
		mkdir -p $1/tmp/.X11-unix ;
		mount --bind /tmp/.X11-unix $1/tmp/.X11-unix ;;
	    SSH) echo "Enabling SSH agent access." ;
		SSH_AUTH_SOCK_DIR=`dirname $SSH_AUTH_SOCK`
		mkdir -p $1$SSH_AUTH_SOCK_DIR ;
		mount --bind $SSH_AUTH_SOCK_DIR $1$SSH_AUTH_SOCK_DIR ;;
	esac  
    done

    neuter $1/sbin/start-stop-daemon
    neuter $1/sbin/invoke-rc.d

    # Disabled, because the semantics are not clear
    # with the new enter/leave semantics
    # run user script
    if false ; then
	if [ -e $HOME/.build-env/use-env.pre ] ; then
	    . $HOME/.build-env/use-env.pre
	fi
    fi
}


if enter ; then
    echo I: Someone else is already here.  Not preparing. 1>&2
else
    prepare $ROOT
fi

echo Entering chroot
trap '(cleanup $1 $OPTIONS)' SIGHUP
$CHROOT_CMD

if leave ; then
    echo I: Not cleaning up.  Someone is still here.  1>&2
else
    cleanup $ROOT $OPTIONS
fi
