#! /bin/bash
# $Id: vserver,v 1.31 2005/10/28 18:29:00 ensc Exp $

# Copyright (C) 2003,2004,2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
#  
# 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; version 2 of the License.
#  
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# set -e

: ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars}
test -e "$UTIL_VSERVER_VARS" || {
    echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2
    exit 1
}
. "$UTIL_VSERVER_VARS"
. "$_LIB_FUNCTIONS"

### Some local functions

function showHelp()
{
    echo \
$"Usage: $(basename $0) [-s|--sync] [-v|--verbose] [--silent]
             [--] <vserver> <command> <args>*

<vserver> is the name of a vserver.

Possible commands are:
    start [--rescue] [<rescue-cmd> <args>*]
                ... starts the specified vserver
    stop        ... stops the specified vserver
    restart     ... restarts the specified vserver; this is the subsequent
                    execution of a synchronized 'stop' and a 'start'
    condrestart ... restarts the vserver when it is running already
    suexec <user> <shell-command> <args*>
                ... executes a command as the specified user in the vserver
    exec <shell-command> <args*>
                ... executes a command as root in the vserver
    enter       ... executes the configured shell in the vserver
    chkconfig <chkconfig-options*>
                ... modifies the init-system; currently, only Red Hat's
		    chkconfig is supported
    running     ... succeeds iff the vserver is running
    status      ... gives out some human readable status information about
                    the vserver, and succeeds iff the vserver is running

    build <buildopts>*
                ... builds a new vserver from scratch

    unify [-R]
		... (de)unify vserver
		
    pkg install <pkg>
		... installs package(s) in the vserver
		
    apt-get,apt-config,apt-cache <apt-opts>*
		... execute the apt-* command for the given vserver
    rpm <rpm-opts>*
		... execute the rpm command for the given vserver

    pkgmgmt externalize|internalize [-y]
		... externalize or internalize the package-management for the
		    given vserver. 'Externalize' means that package metadata
		    and management tools (apt-get,rpm) are living in the host,
		    while 'internalize' means that data and programs from the
		    vserver will be used.

    unify <vunify-opts>*
                ... unify the vserver with its reference vserver(s).
		    

Please report bugs to $PACKAGE_BUGREPORT"
    exit 0
}

function showVersion()
{
    echo \
$"vserver $PACKAGE_VERSION -- manages the state of vservers
This program is part of $PACKAGE_STRING

Copyright (C) 2003,2004,2005 Enrico Scholz
This program is free software; you may redistribute it under the terms of
the GNU General Public License.  This program has absolutely no warranty."
    exit 0
}

function suexec()
{
    . $__PKGLIBDIR/vserver.suexec
}

function restart()
{
    "${SELF[@]}" --sync "$vserver" stop
    exec "${SELF[@]}" "$vserver" start
}

function msg()
{
    test -z "$OPTION_SILENT" || return 0
    echo "$@"
}

### main starts here

set +e

OPTIONS_ORIG=( "$@" )
tmp=$(getopt -o +sv --long nonamespace,--nonamespace,--insecure,defaulttty,help,debug,version,sync,verbose,silent -n "$0" -- "$@") || exit 1
eval set -- "$tmp"

OPTION_FORCE_SYNC=
OPTION_VERBOSE=
OPTION_SILENT=
OPTION_DEBUG=
OPTION_NONAMESPACE=
OPTION_INSECURE=
OPTION_DEFAULTTTY=

while true; do
    case "$1" in
	(--help)    	showHelp $0 ;;
	(--version) 	showVersion ;;
	(--debug)	OPTION_DEBUG=$1; set -x;;
	(-v|--verbose)	OPTION_VERBOSE=$1;;
	(-s|--sync) 	OPTION_FORCE_SYNC=$1;;
	(--silent) 	OPTION_SILENT=$1;;
	(----nonamespace)OPTION_NONAMESPACE=$1;;
	(--defaulttty)	OPTION_DEFAULTTTY=$1;;
	(----insecure)	OPTION_INSECURE=1;;
	(--)	   	shift; break;;
	(*)	   	echo $"vserver: internal error; arg=='$1'" >&2; exit 1;;
    esac
    shift
done

OPTION_ALL=( $OPTION_SILENT $OPTION_VERBOSE $OPTION_DEBUG $OPTION_DEFAULTTTY )
SELF=( "$0" "${OPTION_ALL[@]}" )

vserver=$1
cmd=$2

test "$cmd" != build || { shift 2; exec "$_VSERVER_BUILD" -n "$vserver" "$@"; }


allow_legacy=

case "$vserver" in
    (./*) VSERVER_DIR=`pwd`/$vserver;;
    (/*)  VSERVER_DIR=$vserver;;
    (*)	  VSERVER_DIR=$__CONFDIR/$vserver
	  allow_legacy=1
	  ;;
esac

if test -n "$allow_legacy"; then
    do_legacy=
    test ! -e "$VSERVER_DIR/legacy" || do_legacy=1
    test -d "$VSERVER_DIR" -o ! -e "$__CONFDIR/$vserver.conf" || do_legacy=1

    test -z "$do_legacy" || {
	echo $"WARNING: can not find configuration, assuming legacy method" >&2
	exec "$_VSERVER_LEGACY" "$@"
    }
fi

test -d "$VSERVER_DIR" || {
    echo $"\
Can not find a vserver-setup at '$VSERVER_DIR/'.

Possible solutions:
* fix the spelling of the '$vserver' vserver name
* read 'vserver $vserver build --help' about ways to create a new vserver
* see 'vserver --help' for the syntax of this command
"
    exit 5
} >&2

if test -e "$VSERVER_DIR"/name; then
    read VSERVER_NAME <"$VSERVER_DIR"/name
else
    VSERVER_NAME=$(basename "$VSERVER_DIR")
fi

test "$2" != start -o -n "$OPTION_NONAMESPACE" || isAvoidNamespace "$VSERVER_DIR" || \
    exec $_VNAMESPACE --new -- $_VSERVER ----nonamespace "${OPTIONS_ORIG[@]}"

. $__PKGLIBDIR/vserver.functions
case "$2" in
    (start|stop)
	shift 2
	. $__PKGLIBDIR/vserver.$cmd
	;;
    (suexec|restart)
	shift 2
	$cmd "$@"
	;;
    (condrestart)
	test ! isVserverRunning "$VSERVER_DIR" || restart
	;;
    (exec)
	shift 2
	suexec root "$@"
	;;
    (chkconfig)
	shift 2
	suexec root chkconfig "$@"
	;;
    (enter)
	getEnterShell "$VSERVER_DIR"
	suexec root "${ENTER_SHELL[@]}"
	;;
    (running)
	isVserverRunning "$VSERVER_DIR"
	;;

    (unify)
	shift 2
	exec $_VUNIFY "$@" "$vserver"
	;;

    (hashify)
	shift 2
	exec $_VHASHIFY "$@" "$vserver"
	;;
		
    (pkg)
	shift 2
	exec $_VPKG "$vserver" "$@"
	;;

    (pkgmgmt)
	op=$3
	shift 3
	exec $_VNAMESPACE --new -- $_PKGMGMT ${op:+--$op} "$@" -- "$vserver"
	;;

    (apt-get|apt-config|apt-cache)
	export _APT_GET=$2
	shift 2
	exec $_VAPT_GET -- "$@"
	;;
    (rpm)
	exec $_VRPM -- "$@"
	;;
	
    (status)
	if getVserverStatus "$VSERVER_DIR" ctx procnum; then
	    msg $"Vserver '$vserver' is running at context '$ctx'"

	    if test "$2" = status; then
		msg $"Number of processes: " $procnum
		msg $"Uptime:              "	$("$_FILETIME" "$VSERVER_DIR/run")
	    fi
	    exit 0
	else
	    msg $"Vserver '$vserver' is stopped"
	    exit 3
	fi
	;;
    (*)
	echo $"Usage: $0 {start|stop|suexec|restart|condrestart|exec|enter|chkconfig|running|status}" >&2
	exit 2
	;;
esac
