#!/bin/sh
# This is a script to control a virtual server
vserver_mknod(){
	mknod $1 $2 $3 $4
	chmod $5 $1
}

mountproc()
{
	mkdir -p $1/proc $1/dev/pts
	if [ ! -d $1/proc/1 ] ; then
		mount -t proc none $1/proc
		mount -t devpts none $1/dev/pts
	fi
}
umountproc()
{
	umount $1/proc 2>/dev/null
	umount $1/dev/pts 2>/dev/null
}
usage()
{
	echo vserver server-name command ...
	echo
	echo server-name is a directory in /vservers
	echo
	echo The commands are:
	echo " build   : Create a virtual server by copying the packages"
	echo "           of the root server"
	echo " enter   : Enter in the virtual server context and starts a shell"
	echo "           Same as \"vserver name exec /bin/sh\""
	echo " exec    : Exec a command in the virtual server context"
	echo " service : Control a service inside a vserver"
	echo "           vserver name service service-name start/stop/restart/status"
	echo " start   : Starts the various services in the vserver, runlevel 3"
	echo " stop    : Ends all services and kills the remaining processes"
	echo " running : Tells if a virtual server is running"
	echo "           It returns proper exit code, so you can use it as a test"
}


if [ $# -lt 2 ] ; then
	usage
elif [ "$2" = "build" ] ; then
	if [ -d /vservers/$1 ] ; then
		echo Virtual server /vservers/$1 already exist
	else
		mkdir -p /vservers/$1 || exit 1
		chmod 755 /vservers/$1
		cp -ax /sbin /bin /etc /usr /var /lib /vservers/$1/. || exit 1
		cd /vservers/$1 || exit 1
		rm -fr lib/modules/*
		rm -f var/spool/mail/*
		rm -fr var/run/*
		rm -f `find var/log -type f`
		rm -f var/lock/subsys/*
		mkdir proc tmp home root boot
		test -f /root/.bashrc && cp -a /root/.bashrc root/.
		test -f /root/.bash_profile && cp -a /root/.bash_profile root/.
		chmod 1777 tmp
		chmod 750 root
		# Create a minimal dev so the virtual server can't grab
		# more privileges
		mkdir dev dev/pts
		vserver_mknod dev/null c 1 3 666
		vserver_mknod dev/zero c 1 5 666
		vserver_mknod dev/full c 1 7 666
		vserver_mknod dev/random c 1 8 644
		vserver_mknod dev/urandom c 1 9 644
		vserver_mknod dev/tty c 5 0 666
		vserver_mknod dev/ptmx c 5 2 666
		# Turn off some service useless on a vserver
		#		vserver_turnoff apmd network autofs dhcpd gpm ipchains iptables \
		#			irda isdn keytable kudzu linuxconf-setup netfs nfs nfslock \
		#			pcmcia portmap pppoe random rawdevices rhnsd rstatd ruserd \
		#			rwalld rwhod sendmail smb snmpd v_httpd h_xinetd v_sshd vservers \
		#			xfs ypbind xinetd
		(
			cd etc/rc.d/init.d
			for serv in *
			do
				case $serv in
				*.bak|*~|functions|killall|halt|single)
					;;
				*)
					/usr/sbin/chroot /vservers/$1 /sbin/chkconfig --level 2345 $serv off
					;;
				esac
			done
		)
		rm -f etc/rc.d/rc6.d/S*reboot
		# Create a dummy /etc/fstab and /etc/mtab to please
		# df and linuxconf. We use hdv1, which does not exist
		# to remind the admin that it is not the real drive
		echo /dev/hdv1 / ext2 defaults 1 1 >etc/fstab
		echo /dev/hdv1 / ext2 rw 0 0 >etc/mtab
		# Install the vreboot utility
		cp -a /usr/lib/vserver/vreboot sbin/.
		ln -sf vreboot sbin/vhalt

		echo Directory /vservers/$1 has been populated
		if [ ! -d /etc/vservers ] ; then
			mkdir /etc/vservers
			chmod 600 /etc/vservers
			echo Directory /etc/vservers has been created
		fi
		if [ ! -f /etc/vservers/$1.conf ] ; then
			CONF=/etc/vservers/$1.conf
			cat >$CONF <<-EOF
# Select an unused context (this is optional)
# The default is to allocate a free context on the fly
# In general you don't need to force a context
#S_CONTEXT=
# Select the IP number assigned to the virtual server
# This IP must be one IP of the server, either an interface
# or an IP alias
IPROOT=1.2.3.4
# You can define on which device the IP alias will be done
# The IP alias will be set when the server is started and unset
# when the server is stopped
#IPROOTDEV=eth0
# Uncomment the onboot line if you want to enable this
# virtual server at boot time
#ONBOOT=yes
# You can set a different host name for the vserver
# If empty, the host name of the main server is used
S_HOSTNAME=
# You can set a different NIS domain for the vserver
# If empty, the current on is kept
S_DOMAINNAME=
# You can set the priority level (nice) of all process in the vserver
# Even root won't be able to raise it
S_NICE=
# You can set various flags for the new security context
# lock: Prevent the vserver from setting new security context
# sched: Merge scheduler priority of all processes in the vserver
#        so that it acts a like a single one.
# nproc: Limit the number of processes in the vserver according to ulimit
#        (instead of a per user limit, this becomes a per vserver limit)
# private: No other process can join this security context. Even root
# Do not forget the quotes around the flags
S_FLAGS="lock nproc"
# You can set various ulimit flags and they will be inherited by the
# vserver. You enter here various command line argument of ulimit
# ULIMIT="-H -u 200"
# The example above, combined with the nproc S_FLAGS will limit the
# vserver to a maximum of 200 processes
ULIMIT="-H -u 1000"
# You can set various capabilities. By default, the vserver are run
# with a limited set, so you can let root run in a vserver and not
# worry about it. He can't take over the machine. In some cases
# you can to give a little more capabilities (such as CAP_NET_RAW)
# S_CAPS="CAP_NET_RAW"
S_CAPS=""
			EOF
			echo $CONF has been created. Look at it\!
		fi
	fi
elif [ ! -f /etc/vservers/$1.conf ] ; then
	echo No configuration for this vserver: /etc/vservers/$1.conf
	exit 1
elif [ ! -d /vservers/$1/. ] ; then
	echo No directory for this vserver: /vservers/$1
	exit 1
elif [ "$2" = "start" ] ; then
	echo Starting the virtual server $1
	if ! /usr/sbin/vserver $1 running
	then
		test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-start $1
		IPROOT=
		IPROOTDEV=
		S_NICE=
		S_FLAGS=
		. /etc/vservers/$1.conf
		if [ "$IPROOT" != "" -a "$IPROOTDEV" != "" ] ;then
			/sbin/ifconfig $IPROOTDEV:$1 $IPROOT netmask 255.255.255.255
		fi
		cd /vservers/$1 || exit 1
		rm -fr var/run/*
		rm -f  var/lock/subsys/*
		mountproc /vservers/$1
		CTXOPT=
		HOSTOPT=
		DOMAINOPT=
		NICECMD=
		FLAGS=
		CAPS=
		for f in $S_FLAGS dummy
		do
			case $f in
			dummy)
				;;
			*)
				FLAGS="$FLAGS --flag $f"
				;;
			esac
		done
		for f in $S_CAPS dummy
		do
			case $f in
			dummy)
				;;
			*)
				CAPS="$CAPS --cap $f"
				;;
			esac
		done
		if [ "$S_CONTEXT" != "" ] ; then
			CTXOPT="--ctx $S_CONTEXT"
		fi
		if [ "$S_HOSTNAME" != "" ] ; then
			HOSTOPT="--hostname $S_HOSTNAME"
			export HOSTNAME=$S_HOSTNAME
		fi
		if [ "$S_DOMAINNAME" != "" ] ; then
			DOMAINOPT="--domainname $S_DOMAINNAME"
		fi
		if [ "$S_NICE" != "" ] ; then
			NICECMD="nice -$S_NICE"
		fi
		mkdir -p /var/run/vservers
		chmod 700 /var/run/vservers
		if [ "$ULIMIT" != "" ] ; then
			ulimit $ULIMIT
		fi
		#echo FLAGS=$FLAGS
		#echo CAPS=$CAPS
		$NICECMD /usr/sbin/chbind --ip $IPROOT \
			/usr/sbin/chcontext $CAPS $FLAGS $CTXOPT $HOSTOPT $DOMAINOPT --secure \
			/usr/lib/vserver/save_s_context /var/run/vservers/$1.ctx \
			/usr/sbin/chroot /vservers/$1 /etc/rc.d/rc 3 
		test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh post-start $1
	fi
elif [ "$2" = "running" ] ; then
	if [ ! -f /var/run/vservers/$1.ctx ] ; then
		echo Server $1 is not running
		exit 1
	else
		. /var/run/vservers/$1.ctx
		NB=`/usr/sbin/chcontext --silent --ctx $S_CONTEXT ps ax | wc -l`
		NB=`eval expr $NB + 0`
		if [ "$NB" -gt 3 ] ; then
			echo Server $1 is running
			exit 0
		else
			echo Server $1 is not running
			exit 1
		fi
	fi
elif [ "$2" = "stop" ] ; then
	echo Stopping the virtual server $1
	if /usr/sbin/vserver $1 running
	then
		test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-stop $1
		IPROOT=
		IPROOTDEV=
		. /etc/vservers/$1.conf
		. /var/run/vservers/$1.ctx
		cd /vservers/$1
		mountproc /vservers/$1
		/usr/sbin/chbind --ip $IPROOT \
			/usr/sbin/chcontext --secure --ctx $S_CONTEXT \
			/usr/sbin/chroot /vservers/$1 /etc/rc.d/rc 6
		echo Killing all processes
		/usr/sbin/chbind --silent --ip $IPROOT \
			/usr/sbin/chcontext --secure --silent --ctx $S_CONTEXT \
			/usr/lib/vserver/vserverkillall
		if [ "$IPROOT" != "" -a "$IPROOTDEV" != "" ] ;then
			/sbin/ifconfig $IPROOTDEV:$1 down
		fi
		test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh post-stop $1
	fi
	# We umount anyway, because "enter" establish the mount
	# but when you exit, the server is considered not running
	umountproc /vservers/$1
elif [ "$2" = "restart" ] ; then
	if /usr/sbin/vserver $1 running
	then
		$0 $1 stop
		$0 $1 start
	fi
elif [ "$2" = "exec" ] ; then
	IPROOT=
	IPROOTDEV=
	. /etc/vservers/$1.conf
	cd /vservers/$1
	if [ "$IPROOT" != "" -a "$IPROOTDEV" != "" ] ;then
		/sbin/ifconfig $IPROOTDEV:$1 $IPROOT netmask 255.255.255.255
	fi
	mountproc /vservers/$1
	PS1="[\u@vserver:$1 \W]"
	export PS1
	VSERVER=$1
	shift
	shift
	if $0 $VSERVER running
	then
		. /var/run/vservers/$VSERVER.ctx
		/usr/sbin/chbind --ip $IPROOT \
			/usr/sbin/chcontext --secure --ctx $S_CONTEXT \
			/usr/sbin/chroot /vservers/$VSERVER $*
	else
		CTXOPT=
		HOSTOPT=
		DOMAINOPT=
		CAPS=
		for f in $S_CAPS dummy
		do
			case $f in
			dummy)
				;;
			*)
				CAPS="$CAPS --cap $f"
				;;
			esac
		done
		if [ "$S_CONTEXT" != "" ] ; then
			CTXOPT="--ctx $S_CONTEXT"
		fi
		if [ "$S_HOSTNAME" != "" ] ; then
			HOSTOPT="--hostname $S_HOSTNAME"
			export HOSTNAME=$S_HOSTNAME
		fi
		if [ "$S_DOMAINNAME" != "" ] ; then
			DOMAINOPT="--domainname $S_DOMAINNAME"
		fi
		mkdir -p /var/run/vservers
		/usr/sbin/chbind --ip $IPROOT \
			/usr/sbin/chcontext $CAPS --secure $CTXOPT $HOSTOPT $DOMAINOPT \
			/usr/lib/vserver/save_s_context /var/run/vservers/$VSERVER.ctx \
			/usr/sbin/chroot /vservers/$VSERVER $*
	fi
elif [ "$2" = "enter" ] ; then
	exec $0 $1 exec /bin/sh
elif [ "$2" = "service" ] ; then
	VSERVER=$1
	shift
	shift
	exec $0 $VSERVER exec /sbin/service $*
elif [ "$2" = "chkconfig" ] ; then
	VSERVER=$1
	shift
	shift
	exec $0 $VSERVER exec /sbin/chkconfig $*
else
	echo Command unknown $2
	echo
	usage
fi

