3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 # based on vserver by Jacques Gelinas
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 # This is a script to control a virtual server
22 : ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars}
23 test -e "$UTIL_VSERVER_VARS" || {
24 echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2
27 . "$UTIL_VSERVER_VARS"
30 USR_LIB_VSERVER=$PKGLIBDIR
31 DEFAULTPATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin
40 mkdir -p $1/proc $1/dev/pts
41 if [ ! -d $1/proc/1 ] ; then
42 mount -t proc none $1/proc
43 mount -t devpts -o gid=5,mode=0620 none $1/dev/pts
48 umount $1/proc 2>/dev/null
49 umount $1/dev/pts 2>/dev/null
52 # Check that the vservers parent directory has permission 000
53 # This is the key to avoid chroot escape
57 PERM=`$_SHOWPERM $DEFAULT_VSERVERDIR/$1/..`
58 if [ "$PERM" != 000 ] ; then
60 echo "**********************************************************"
61 echo $DEFAULT_VSERVERDIR/$1/.. has insecure permissions.
62 echo A vserver administrator may be able to visit the root server.
64 echo " " chmod 000 $DEFAULT_VSERVERDIR/$1/..
65 echo do it anytime you want, even if vservers are running.
66 echo "**********************************************************"
70 # Set the IP alias needed by a vserver
73 if [ "$NODEV" = "" -a "$IPROOT" != "" -a "$IPROOT" != "0.0.0.0" -a "$IPROOT" != "ALL" ] ;then
74 # A vserver may have more than one IP
75 # The first alias is dev:vserver
76 # and the other are dev:vserver1,2,3 and so on
77 # An IP may hold the device. The following is valid
78 # IPROOT="1.2.4.5 eth1:1.2.3.5"
80 # The first IP 1.2.3.4 will go on eth0 and the other on eth1
81 # VLAN devices are also supported (eth0.231 for vlan 231)
88 # Split the device and IP if available
91 eval `echo $oneip | tr : ' ' | (read dev ip; echo oneip=$ip; echo IPDEV=$dev)`
94 # Split the IP and the netmask if available
97 eval `echo $oneip | tr / ' ' | (read ip msk; echo oneip=$ip; echo MASK=$msk)`
98 eval `$_IFSPEC "" "$oneip" "$MASK" "$BCAST"`
101 if [ "$IPDEV" != "" ] ; then
104 if [ ! -f /proc/net/vlan/$IPDEV ] ; then
105 /sbin/vconfig add `echo $IPDEV | tr . ' '`
107 /sbin/ifconfig $IPDEV 127.0.0.1
111 # Compute the default netmask, if missing
112 eval `$_IFSPEC $IPDEV "$oneip" "$MASK" "$BCAST"`
115 #echo /sbin/ifconfig $IPDEV:$1$SUFFIX $oneip netmask $IPROOTMASK broadcast $IPROOTBCAST
116 /sbin/ifconfig $IPDEV:$1$SUFFIX $oneip netmask $IPROOTMASK broadcast $IPROOTBCAST
118 if [ "$SUFFIX" = "" ] ; then
121 SUFFIX=`expr $SUFFIX + 1`
125 if [ "$IPROOTBCAST" = "" ] ; then
126 IPROOTBCAST=255.255.255.255
129 ifconfig_iproot_off()
131 if [ "$NODEV" = "" -a "$IPROOT" != "" -a "$IPROOT" != "0.0.0.0" -a "$IPROOT" != "ALL" -a "$IPROOTDEV" != "" ] ;then
136 # Split the device and IP if available
139 eval `echo $oneip | tr : ' ' | (read dev ip; echo IPDEV=$dev)`
142 /sbin/ifconfig $IPDEV:$1$SUFFIX down 2>/dev/null
143 if [ "$SUFFIX" = "" ] ; then
146 SUFFIX=`expr $SUFFIX + 1`
151 # Split an IPROOT definition, trash the devices and
152 # compose a set of --ip option for chbind
156 if [ "$IPS" = "" ] ; then
159 if [ "$1" = "ALL" ] ; then
164 # Split the device and IP if available
167 eval `echo $oneip | tr : ' ' | (read dev ip; echo oneip=$ip)`
172 # eval `echo $oneip | tr / ' ' | (read ip msk; echo oneip=$ip)`
179 # Extract the initial runlevel from the vserver inittab
182 INITDEFAULT=`grep :initdefault $DEFAULT_VSERVERDIR/$1/etc/inittab | sed 's/:/ /g' | ( read a level b; echo $level)`
185 # Read the vserver configuration file, reusing the PROFILE value
186 # found in /var/run/vservers
189 if [ -f $PKGSTATEDIR/$1.ctx ] ; then
190 . $PKGSTATEDIR/$1.ctx
191 if [ "$S_PROFILE" != "" ] ; then
192 export PROFILE=$S_PROFILE
200 echo vserver [ options ] server-name command ...
202 echo server-name is a directory in $DEFAULT_VSERVERDIR
204 echo The commands are:
205 echo " build : Create a virtual server by copying the packages"
206 echo " of the root server"
207 echo " enter : Enter in the virtual server context and starts a shell"
208 echo " Same as \"vserver name exec /bin/sh\""
209 echo " exec : Exec a command in the virtual server context"
210 echo " suexec : Exec a command in the virtual server context uid"
211 echo " service : Control a service inside a vserver"
212 echo " vserver name service service-name start/stop/restart/status"
213 echo " start : Starts the various services in the vserver, runlevel 3"
214 echo " stop : Ends all services and kills the remaining processes"
215 echo " running : Tells if a virtual server is running"
216 echo " It returns proper exit code, so you can use it as a test"
217 echo " status : Tells some information about a vserver"
218 echo " chkconfig : It turns a server on or off in a vserver"
220 echo "--nodev : Do not configure the IP aliases of the vserver"
221 echo " Useful to enter a vserver without enabling its network"
222 echo " and avoiding conflicts with another copy of this vserver"
223 echo " running elsewhere"
224 echo "--silent : No informative messages about vserver context and IP numbers"
225 echo " Useful when you want to redirect the output"
237 CAPS="$CAPS --cap $f"
247 if [ "$1" = "--silent" ] ; then
250 elif [ "$1" = "--nodev" ] ; then
257 # Setup the default ulimit for a vserver
259 # File handle are limited to half of the current system limit
260 # Virtual memory is limited to the ram size
261 NFILE=`cat /proc/sys/fs/file-max`
262 NFILE=`expr $NFILE / 2`
263 VMEM=`cat /proc/meminfo | grep MemTotal | (read a b c; echo $b)`
264 # Disabled for now, we need a different to set the security
265 # context limit than fiddling with ulimit
266 #ulimit -H -n $NFILE -v $VMEM
268 if [ $# -lt 2 ] ; then
270 elif [ "$2" = "build" ] ; then
271 # Either the directory does not exist or is empty
272 NBSUB=`ls $DEFAULT_VSERVERDIR/$1 2>/dev/null | grep -v lost+found | wc -l`
274 if [ "$NBSUB" != 0 ] ; then
275 echo Virtual server $DEFAULT_VSERVERDIR/$1 already exist
277 if [ ! -d $DEFAULT_VSERVERDIR ] ; then
278 mkdir $DEFAULT_VSERVERDIR || exit 1
279 chmod 000 $DEFAULT_VSERVERDIR
280 echo Directory $DEFAULT_VSERVERDIR was created with permissions 000
282 mkdir -p $DEFAULT_VSERVERDIR/$1 || exit 1
283 chmod 755 $DEFAULT_VSERVERDIR/$1
284 if test "$UTIL_VSERVER_AVOID_COPY"; then
285 mkdir -p $DEFAULT_VSERVERDIR/$1/{etc/rc.d/init.d,sbin,var/run,var/log}
287 cp -ax /sbin /bin /etc /usr /var /lib $DEFAULT_VSERVERDIR/$1/. || exit 1
289 cd $DEFAULT_VSERVERDIR/$1 || exit 1
291 rm -f var/spool/mail/*
292 rm -f `find var/run -type f`
293 rm -f `find var/log -type f`
295 rm -f var/lock/subsys/*
296 rm -f etc/cron.d/kmod
297 mkdir proc tmp home root boot
298 test -f /root/.bashrc && cp -a /root/.bashrc root/.
299 test -f /root/.bash_profile && cp -a /root/.bash_profile root/.
302 # Create a minimal dev so the virtual server can't grab
305 vserver_mknod dev/null c 1 3 666
306 vserver_mknod dev/zero c 1 5 666
307 vserver_mknod dev/full c 1 7 666
308 vserver_mknod dev/random c 1 8 644
309 vserver_mknod dev/urandom c 1 9 644
310 vserver_mknod dev/tty c 5 0 666
311 vserver_mknod dev/ptmx c 5 2 666
313 # Turn off some service useless on a vserver
314 # vserver_turnoff apmd network autofs dhcpd gpm ipchains iptables \
315 # irda isdn keytable kudzu linuxconf-setup netfs nfs nfslock \
316 # pcmcia portmap pppoe random rawdevices rhnsd rstatd ruserd \
317 # rwalld rwhod sendmail smb snmpd v_httpd h_xinetd v_sshd vservers \
320 cd etc/init.d 2>/dev/null || cd etc/rc.d/init.d
324 *.bak|*~|functions|killall|halt|single)
327 #$USR_LIB_VSERVER/capchroot $DEFAULT_VSERVERDIR/$1 /sbin/chkconfig --level 2345 $serv off
328 $0 --silent $1 chkconfig --level 2345 $serv off
333 rm -f etc/rc.d/rc6.d/S*reboot
334 # Create a dummy /etc/fstab and /etc/mtab to please
335 # df and linuxconf. We use hdv1, which does not exist
336 # to remind the admin that it is not the real drive
337 echo /dev/hdv1 / ext2 defaults 1 1 >etc/fstab
338 echo /dev/hdv1 / ext2 rw 0 0 >etc/mtab
339 # Install the vreboot utility
340 cp -a "$_VREBOOT" sbin/.
341 ln -sf vreboot sbin/vhalt
343 echo Directory $DEFAULT_VSERVERDIR/$1 has been populated
344 if [ ! -d $CONFDIR ] ; then
347 echo Directory $CONFDIR has been created
349 if [ ! -f $CONFDIR/$1.conf ] ; then
350 CONF=$CONFDIR/$1.conf
352 if [ "$PROFILE" = "" ] ; then
355 # Select the IP number assigned to the virtual server
356 # This IP must be one IP of the server, either an interface
358 # A vserver may have more than one IP. Separate them with spaces.
359 # do not forget double quotes.
361 # IPROOT="1.2.3.4 2.3.4.5"
362 # IPROOT="eth0:1.2.3.4 eth1:2.3.4.5"
363 # If the device is not specified, IPROOTDEV is used
367 # The netmask and broadcast are computed by default from IPROOTDEV
370 # You can define on which device the IP alias will be done
371 # The IP alias will be set when the server is started and unset
372 # when the server is stopped
374 # You can set a different host name for the vserver
375 # If empty, the host name of the main server is used
386 # Uncomment the onboot line if you want to enable this
387 # virtual server at boot time
389 # You can set a different NIS domain for the vserver
390 # If empty, the current on is kept
391 # Set it to "none" to have no NIS domain set
393 # You can set the priority level (nice) of all process in the vserver
394 # Even root won't be able to raise it
396 # You can set various flags for the new security context
397 # lock: Prevent the vserver from setting new security context
398 # sched: Merge scheduler priority of all processes in the vserver
399 # so that it acts a like a single one.
400 # nproc: Limit the number of processes in the vserver according to ulimit
401 # (instead of a per user limit, this becomes a per vserver limit)
402 # private: No other process can join this security context. Even root
403 # Do not forget the quotes around the flags
405 # You can set various ulimit flags and they will be inherited by the
406 # vserver. You enter here various command line argument of ulimit
407 # ULIMIT="-HS -u 200"
408 # The example above, combined with the nproc S_FLAGS will limit the
409 # vserver to a maximum of 200 processes
411 # You can set various capabilities. By default, the vserver are run
412 # with a limited set, so you can let root run in a vserver and not
413 # worry about it. He can't take over the machine. In some cases
414 # you can to give a little more capabilities (such as CAP_NET_RAW)
415 # S_CAPS="CAP_NET_RAW"
417 # Select an unused context (this is optional)
418 # The default is to allocate a free context on the fly
419 # In general you don't need to force a context
422 echo $CONF has been created. Look at it\!
425 elif [ ! -f $CONFDIR/$1.conf ] ; then
426 echo No configuration for this vserver: $CONFDIR/$1.conf
428 elif [ ! -d $DEFAULT_VSERVERDIR/$1/. ] ; then
429 echo No directory for this vserver: $DEFAULT_VSERVERDIR/$1
431 elif [ "$2" = "start" ] ; then
432 echo Starting the virtual server $1
436 test -x $CONFDIR/$1.sh && $CONFDIR/$1.sh pre-start $1
446 cd $DEFAULT_VSERVERDIR/$1 || exit 1
448 if [ "$PROFILE" != "" ] ; then
449 echo export PROFILE=$PROFILE >etc/PROFILE
452 rm -f `find var/run -type f`
454 chgrp ${UTMP_GROUP:-utmp} var/run/utmp
455 chmod 0664 var/run/utmp
456 rm -f var/lock/subsys/*
457 mountproc $DEFAULT_VSERVERDIR/$1
465 STARTCMD="/etc/rc.d/rc $INITDEFAULT"
466 if [ -x $DEFAULT_VSERVERDIR/$1/etc/init.d/rc ] ; then
467 STARTCMD="/etc/init.d/rc $INITDEFAULT"
468 elif [ -x $DEFAULT_VSERVERDIR/$1/usr/bin/emerge ] ; then
469 STARTCMD="/sbin/rc default"
470 elif [ -x $DEFAULT_VSERVERDIR/$1/etc/rc.d/rc.M ] ; then
471 STARTCMD="/etc/rc.d/rc.M"
476 for f in $S_FLAGS dummy
484 FLAGS="$FLAGS --flag fakeinit"
485 STARTCMD=/sbin/minit-start
486 DISCONNECT=--disconnect
491 FLAGS="$FLAGS --flag $f"
493 DISCONNECT=--disconnect
496 FLAGS="$FLAGS --flag $f"
500 if [ "$FAKEINIT" = "" ] ; then
501 $USR_LIB_VSERVER/fakerunlevel $INITDEFAULT var/run/utmp
504 calculateCaps $S_CAPS
506 if [ "$S_CONTEXT" != "" ] ; then
507 CTXOPT="--ctx $S_CONTEXT"
509 if [ "$S_HOSTNAME" != "" ] ; then
510 HOSTOPT="--hostname $S_HOSTNAME"
511 export HOSTNAME=$S_HOSTNAME
513 if [ "$S_DOMAINNAME" != "" ] ; then
514 DOMAINOPT="--domainname $S_DOMAINNAME"
516 if [ "$S_NICE" != "" ] ; then
517 NICECMD="nice -$S_NICE"
519 mkdir -p $PKGSTATEDIR
520 chmod 700 $PKGSTATEDIR
522 if [ "$ULIMIT" != "" ] ; then
527 # We switch to /vservers/$1 now, because after the
528 # security context switch /vservers directory becomes a dead zone.
529 cd $DEFAULT_VSERVERDIR/$1
530 IPOPT=`setipopt $IPROOT`
531 export PATH=$DEFAULTPATH
532 $NICECMD $_CHBIND $SILENT $IPOPT --bcast $IPROOTBCAST \
533 $_CHCONTEXT_COMPAT $SILENT $DISCONNECT $CAPS $FLAGS $CTXOPT $HOSTOPT $DOMAINOPT --secure \
534 $_SAVE_S_CONTEXT $PKGSTATEDIR/$1.ctx \
535 $_CAPCHROOT $CHROOTOPT . $STARTCMD
537 test ! -x $CONFDIR/$1.sh || $CONFDIR/$1.sh post-start $1
539 elif [ "$2" = "running" ] ; then
540 if [ ! -f $PKGSTATEDIR/$1.ctx ] ; then
541 echo Server $1 is not running
544 . $PKGSTATEDIR/$1.ctx
545 NB=$($USR_SBIN/vps ax | awk '{print $2}' | grep \^$S_CONTEXT\$ | wc -l)
546 #NB=`$_CHCONTEXT_COMPAT --silent --ctx $S_CONTEXT ps ax | wc -l`
547 #NB=`eval expr $NB + 0`
548 if [ "$NB" -gt 0 ] ; then
549 echo Server $1 is running
552 echo Server $1 is not running
556 elif [ "$2" = "status" ] ; then
559 . $PKGSTATEDIR/$1.ctx
560 NB=$($USR_SBIN/vps ax | awk '{print $2}' | grep \^$S_CONTEXT\$ | wc -l)
561 echo $NB processes running
562 echo Vserver uptime: `$USR_LIB_VSERVER/filetime $PKGSTATEDIR/$1.ctx`
564 elif [ "$2" = "stop" ] ; then
565 echo Stopping the virtual server $1
575 test -x $CONFDIR/$1.sh && $CONFDIR/$1.sh pre-stop $1
577 cd $DEFAULT_VSERVERDIR/$1
578 mountproc $DEFAULT_VSERVERDIR/$1
579 # The fakeinit flag tell us how to turn off the server
581 export PREVLEVEL=$INITDEFAULT
582 STOPCMD="/etc/rc.d/rc 6"
583 if [ -x $DEFAULT_VSERVERDIR/$1/etc/init.d/rc ] ; then
584 STOPCMD="/etc/init.d/rc 6"
585 elif [ -x $DEFAULT_VSERVERDIR/$1/usr/bin/emerge ] ; then
586 STOPCMD="/sbin/rc shutdown"
587 elif [ -x $DEFAULT_VSERVERDIR/$1/etc/rc.d/rc.6 ] ; then
588 STOPCMD="/etc/rc.d/rc.6"
591 for f in $S_FLAGS dummy
596 FLAGS="$FLAGS --flag fakeinit"
597 STOPCMD="/sbin/minit-stop"
601 FLAGS="$FLAGS --flag $f"
602 STOPCMD="/sbin/init 6"
609 calculateCaps $S_CAPS
611 cd $DEFAULT_VSERVERDIR/$1
612 IPOPT=`setipopt $IPROOT`
613 export PATH=$DEFAULTPATH
614 $_CHBIND $SILENT $IPOPT --bcast $IPROOTBCAST \
615 $_CHCONTEXT_COMPAT $SILENT $CAPS --secure --ctx $S_CONTEXT \
616 $_CAPCHROOT . $STOPCMD
618 if test "$IS_MINIT"; then
619 echo "Waiting for minit finish-signal"
620 dd if=var/run/minit-stop of=/dev/zero bs=1 count=1 &>/dev/null
623 echo sleeping 5 seconds
627 echo Killing all processes
628 $_CHBIND --silent $IPOPT --bcast $IPROOTBCAST \
629 $_CHCONTEXT_COMPAT $CAPS --secure --silent --ctx $S_CONTEXT \
632 # We umount anyway, because "enter" establish the mount
633 # but when you exit, the server is considered not running
634 umountproc $DEFAULT_VSERVERDIR/$1
636 test -x $CONFDIR/$1.sh && $CONFDIR/$1.sh post-stop $1
637 ifconfig_iproot_off $1
638 elif [ "$2" = "restart" ] ; then
644 elif [ "$2" = "suexec" ] ; then
645 if [ -z "$3" ] ; then
646 echo "Missing user!" >&2
647 echo "vserver vserver-name suexec user command [ args ... ]" >&2
649 elif [ -z "$4" ] ; then
650 echo "Missing command and arguments!" >&2
651 echo "vserver vserver-name suexec user command [ args ... ]" >&2
660 cd $DEFAULT_VSERVERDIR/$1
662 mountproc $DEFAULT_VSERVERDIR/$1
663 PS1="[\u@vserver:$1 \W]"
669 for f in $S_CAPS dummy
678 CAPS="$CAPS --cap $f"
683 for f in $S_FLAGS dummy
687 FLAGS="$FLAGS --flag fakeinit"
693 FLAGS="$FLAGS --flag $f"
698 if [ "$ULIMIT" != "" ] ; then
701 if $0 $VSERVER running >/dev/null
703 . $PKGSTATEDIR/$VSERVER.ctx
704 cd $DEFAULT_VSERVERDIR/$VSERVER
705 IPOPT=`setipopt $IPROOT`
706 export PATH=$DEFAULTPATH
707 exec $_CHBIND $SILENT $IPOPT --bcast $IPROOTBCAST \
708 $_CHCONTEXT_COMPAT $SILENT $FLAGS $CAPS --secure --ctx $S_CONTEXT \
709 $_CAPCHROOT --suid $USERID . "$@"
711 test -x $CONFDIR/$1.sh && $CONFDIR/$1.sh pre-start $1
715 if [ "$S_CONTEXT" != "" ] ; then
716 CTXOPT="--ctx $S_CONTEXT"
718 if [ "$S_HOSTNAME" != "" ] ; then
719 HOSTOPT="--hostname $S_HOSTNAME"
720 export HOSTNAME=$S_HOSTNAME
722 if [ "$S_DOMAINNAME" != "" ] ; then
723 DOMAINOPT="--domainname $S_DOMAINNAME"
725 mkdir -p $PKGSTATEDIR
726 cd $DEFAULT_VSERVERDIR/$VSERVER
727 IPOPT=`setipopt $IPROOT`
728 export PATH=$DEFAULTPATH
729 exec $_CHBIND $SILENT $IPOPT --bcast $IPROOTBCAST \
730 $_CHCONTEXT_COMPAT $SILENT $FLAGS $CAPS --secure $CTXOPT $HOSTOPT $DOMAINOPT \
731 $_SAVE_S_CONTEXT $PKGSTATEDIR/$VSERVER.ctx \
732 $_CAPCHROOT --suid $USERID $CHROOTOPT . "$@"
735 elif [ "$2" = "exec" ] ; then
738 exec $0 $NODEV $SILENT $VSERV suexec root "$@"
739 elif [ "$2" = "enter" ] ; then
741 exec $0 $NODEV $SILENT $1 exec /bin/bash -login
742 elif [ "$2" = "service" ] ; then
746 exec $0 $NODEV $SILENT $VSERVER exec /sbin/service "$@"
747 elif [ "$2" = "chkconfig" ] ; then
751 if [ "$1" = "--level" ] ; then
756 if [ $# != 2 -a ! -x $DEFAULT_VSERVERDIR/$VSERVER/sbin/chkconfig ] ; then
757 echo Invalid argument, expected vserver name chkconfig [ --level nnn ] service on\|off
758 elif [ -x $DEFAULT_VSERVERDIR/$VSERVER/sbin/chkconfig ] ; then
759 exec $0 --silent $VSERVER exec /sbin/chkconfig "$@"
760 elif [ -x $DEFAULT_VSERVERDIR/$VSERVER/usr/sbin/update-rc.d ] ; then
761 if [ "$2" = "on" -o "$2" = "start" ] ; then
762 $0 --silent $VSERVER exec /usr/sbin/update-rc.d -f $1 remove >/dev/null
763 exec $0 --silent $VSERVER exec /usr/sbin/update-rc.d $1 start 80 2 3 4 5 . stop 20 0 1 6 . >/dev/null
764 elif [ "$2" = "off" -o "$2" = "stop" ] ; then
765 $0 --silent $VSERVER exec /usr/sbin/update-rc.d -f $1 remove >/dev/null
766 exec $0 --silent $VSERVER exec /usr/sbin/update-rc.d $1 stop 20 0 1 2 3 4 5 6 . >/dev/null
768 echo vserver chkconfig: Expecting on or off
771 echo chkconfig functionality is not available on this
772 echo vserver distribution.
773 echo Looked for /sbin/chkconfig and /usr/sbin/update-rc.d
776 echo Command unknown $2