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:=$(dirname $0)/util-vserver-vars}
23 test -e "$UTIL_VSERVER_VARS" || {
24 echo "Can not find util-vserver installation; aborting..."
27 . "$UTIL_VSERVER_VARS"
30 USR_LIB_VSERVER=$PKGLIBDIR
32 VSERVER_CMD=$USR_SBIN/vserver
33 CHBIND_CMD=$USR_SBIN/chbind
34 CHCONTEXT_CMD=$USR_SBIN/chcontext
35 SAVE_S_CONTEXT_CMD=$USR_LIB_VSERVER/save_s_context
36 CAPCHROOT_CMD=$USR_LIB_VSERVER/capchroot
37 VSERVERKILLALL_CMD=$USR_LIB_VSERVER/vserverkillall
38 DEFAULTPATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin
46 mkdir -p $1/proc $1/dev/pts
47 if [ ! -d $1/proc/1 ] ; then
48 mount -t proc none $1/proc
49 mount -t devpts none $1/dev/pts
54 umount $1/proc 2>/dev/null
55 umount $1/dev/pts 2>/dev/null
58 # Check that the vservers parent directory has permission 000
59 # This is the key to avoid chroot escape
63 PERM=`$USR_LIB_VSERVER/showperm /vservers/$1/..`
64 if [ "$PERM" != 000 ] ; then
66 echo "**********************************************************"
67 echo /vservers/$1/.. has insecure permissions.
68 echo A vserver administrator may be able to visit the root server.
70 echo " " chmod 000 /vservers/$1/..
71 echo do it anytime you want, even if vservers are running.
72 echo "**********************************************************"
76 # Set the IP alias needed by a vserver
79 if [ "$NODEV" = "" -a "$IPROOT" != "" -a "$IPROOT" != "0.0.0.0" -a "$IPROOT" != "ALL" ] ;then
80 # A vserver may have more than one IP
81 # The first alias is dev:vserver
82 # and the other are dev:vserver1,2,3 and so on
83 # An IP may hold the device. The following is valid
84 # IPROOT="1.2.4.5 eth1:1.2.3.5"
86 # The first IP 1.2.3.4 will go on eth0 and the other on eth1
87 # VLAN devices are also supported (eth0.231 for vlan 231)
94 # Split the device and IP if available
97 eval `echo $oneip | tr : ' ' | (read dev ip; echo oneip=$ip; echo IPDEV=$dev)`
100 # Split the IP and the netmask if available
103 eval `echo $oneip | tr / ' ' | (read ip msk; echo oneip=$ip; echo MASK=$msk)`
104 eval `$USR_LIB_VSERVER/ifspec "" "$oneip" "$MASK" "$BCAST"`
107 if [ "$IPDEV" != "" ] ; then
110 if [ ! -f /proc/net/vlan/$IPDEV ] ; then
111 /sbin/vconfig add `echo $IPDEV | tr . ' '`
113 /sbin/ifconfig $IPDEV 127.0.0.1
117 # Compute the default netmask, if missing
118 eval `$USR_LIB_VSERVER/ifspec $IPDEV "$oneip" "$MASK" "$BCAST"`
121 #echo /sbin/ifconfig $IPDEV:$1$SUFFIX $oneip netmask $IPROOTMASK broadcast $IPROOTBCAST
122 /sbin/ifconfig $IPDEV:$1$SUFFIX $oneip netmask $IPROOTMASK broadcast $IPROOTBCAST
124 if [ "$SUFFIX" = "" ] ; then
127 SUFFIX=`expr $SUFFIX + 1`
131 if [ "$IPROOTBCAST" = "" ] ; then
132 IPROOTBCAST=255.255.255.255
135 ifconfig_iproot_off()
137 if [ "$NODEV" = "" -a "$IPROOT" != "" -a "$IPROOT" != "0.0.0.0" -a "$IPROOT" != "ALL" -a "$IPROOTDEV" != "" ] ;then
142 # Split the device and IP if available
145 eval `echo $oneip | tr : ' ' | (read dev ip; echo IPDEV=$dev)`
148 /sbin/ifconfig $IPDEV:$1$SUFFIX down 2>/dev/null
149 if [ "$SUFFIX" = "" ] ; then
152 SUFFIX=`expr $SUFFIX + 1`
157 # Split an IPROOT definition, trash the devices and
158 # compose a set of --ip option for chbind
162 if [ "$IPS" = "" ] ; then
165 if [ "$1" = "ALL" ] ; then
166 IPS=`$USR_LIB_VSERVER/listdevip`
170 # Split the device and IP if available
173 eval `echo $oneip | tr : ' ' | (read dev ip; echo oneip=$ip)`
178 # eval `echo $oneip | tr / ' ' | (read ip msk; echo oneip=$ip)`
185 # Extract the initial runlevel from the vserver inittab
188 INITDEFAULT=`grep :initdefault /vservers/$1/etc/inittab | sed 's/:/ /g' | ( read a level b; echo $level)`
191 # Read the vserver configuration file, reusing the PROFILE value
192 # found in /var/run/vservers
195 if [ -f /var/run/vservers/$1.ctx ] ; then
196 . /var/run/vservers/$1.ctx
197 if [ "$S_PROFILE" != "" ] ; then
198 export PROFILE=$S_PROFILE
202 . /etc/vservers/$1.conf
206 echo vserver [ options ] server-name command ...
208 echo server-name is a directory in /vservers
210 echo The commands are:
211 echo " build : Create a virtual server by copying the packages"
212 echo " of the root server"
213 echo " enter : Enter in the virtual server context and starts a shell"
214 echo " Same as \"vserver name exec /bin/sh\""
215 echo " exec : Exec a command in the virtual server context"
216 echo " suexec : Exec a command in the virtual server context uid"
217 echo " service : Control a service inside a vserver"
218 echo " vserver name service service-name start/stop/restart/status"
219 echo " start : Starts the various services in the vserver, runlevel 3"
220 echo " stop : Ends all services and kills the remaining processes"
221 echo " running : Tells if a virtual server is running"
222 echo " It returns proper exit code, so you can use it as a test"
223 echo " status : Tells some information about a vserver"
224 echo " chkconfig : It turns a server on or off in a vserver"
226 echo "--nodev : Do not configure the IP aliases of the vserver"
227 echo " Useful to enter a vserver without enabling its network"
228 echo " and avoiding conflicts with another copy of this vserver"
229 echo " running elsewhere"
230 echo "--silent : No informative messages about vserver context and IP numbers"
231 echo " Useful when you want to redirect the output"
243 CAPS="$CAPS --cap $f"
253 if [ "$1" = "--silent" ] ; then
256 elif [ "$1" = "--nodev" ] ; then
263 # Setup the default ulimit for a vserver
265 # File handle are limited to half of the current system limit
266 # Virtual memory is limited to the ram size
267 NFILE=`cat /proc/sys/fs/file-max`
268 NFILE=`expr $NFILE / 2`
269 VMEM=`cat /proc/meminfo | grep MemTotal | (read a b c; echo $b)`
270 # Disabled for now, we need a different to set the security
271 # context limit than fiddling with ulimit
272 #ulimit -H -n $NFILE -v $VMEM
274 if [ $# -lt 2 ] ; then
276 elif [ "$2" = "build" ] ; then
277 # Either the directory does not exist or is empty
278 NBSUB=`ls /vservers/$1 2>/dev/null | grep -v lost+found | wc -l`
280 if [ "$NBSUB" != 0 ] ; then
281 echo Virtual server /vservers/$1 already exist
283 if [ ! -d /vservers ] ; then
284 mkdir /vservers || exit 1
286 echo Directory /vservers was created with permissions 000
288 mkdir -p /vservers/$1 || exit 1
289 chmod 755 /vservers/$1
290 mkdir -p /vservers/$1/{etc/rc.d/init.d,sbin,var/run,var/log}
291 cd /vservers/$1 || exit 1
293 rm -f var/spool/mail/*
294 rm -f `find var/run -type f`
295 rm -f `find var/log -type f`
297 rm -f var/lock/subsys/*
298 rm -f etc/cron.d/kmod
299 mkdir proc tmp home root boot
300 test -f /root/.bashrc && cp -a /root/.bashrc root/.
301 test -f /root/.bash_profile && cp -a /root/.bash_profile root/.
304 # Create a minimal dev so the virtual server can't grab
307 vserver_mknod dev/null c 1 3 666
308 vserver_mknod dev/zero c 1 5 666
309 vserver_mknod dev/full c 1 7 666
310 vserver_mknod dev/random c 1 8 644
311 vserver_mknod dev/urandom c 1 9 644
312 vserver_mknod dev/tty c 5 0 666
313 vserver_mknod dev/ptmx c 5 2 666
315 # Turn off some service useless on a vserver
316 # vserver_turnoff apmd network autofs dhcpd gpm ipchains iptables \
317 # irda isdn keytable kudzu linuxconf-setup netfs nfs nfslock \
318 # pcmcia portmap pppoe random rawdevices rhnsd rstatd ruserd \
319 # rwalld rwhod sendmail smb snmpd v_httpd h_xinetd v_sshd vservers \
322 cd etc/init.d 2>/dev/null || cd etc/rc.d/init.d
326 *.bak|*~|functions|killall|halt|single)
329 #$USR_LIB_VSERVER/capchroot /vservers/$1 /sbin/chkconfig --level 2345 $serv off
330 $0 --silent $1 chkconfig --level 2345 $serv off
335 rm -f etc/rc.d/rc6.d/S*reboot
336 # Create a dummy /etc/fstab and /etc/mtab to please
337 # df and linuxconf. We use hdv1, which does not exist
338 # to remind the admin that it is not the real drive
339 echo /dev/hdv1 / ext2 defaults 1 1 >etc/fstab
340 echo /dev/hdv1 / ext2 rw 0 0 >etc/mtab
341 # Install the vreboot utility
342 cp -a $USR_LIB_VSERVER/vreboot sbin/.
343 ln -sf vreboot sbin/vhalt
345 echo Directory /vservers/$1 has been populated
346 if [ ! -d /etc/vservers ] ; then
348 chmod 600 /etc/vservers
349 echo Directory /etc/vservers has been created
351 if [ ! -f /etc/vservers/$1.conf ] ; then
352 CONF=/etc/vservers/$1.conf
354 if [ "$PROFILE" = "" ] ; then
357 # Select the IP number assigned to the virtual server
358 # This IP must be one IP of the server, either an interface
360 # A vserver may have more than one IP. Separate them with spaces.
361 # do not forget double quotes.
363 # IPROOT="1.2.3.4 2.3.4.5"
364 # IPROOT="eth0:1.2.3.4 eth1:2.3.4.5"
365 # If the device is not specified, IPROOTDEV is used
369 # The netmask and broadcast are computed by default from IPROOTDEV
372 # You can define on which device the IP alias will be done
373 # The IP alias will be set when the server is started and unset
374 # when the server is stopped
376 # You can set a different host name for the vserver
377 # If empty, the host name of the main server is used
388 # Uncomment the onboot line if you want to enable this
389 # virtual server at boot time
391 # You can set a different NIS domain for the vserver
392 # If empty, the current on is kept
393 # Set it to "none" to have no NIS domain set
395 # You can set the priority level (nice) of all process in the vserver
396 # Even root won't be able to raise it
398 # You can set various flags for the new security context
399 # lock: Prevent the vserver from setting new security context
400 # sched: Merge scheduler priority of all processes in the vserver
401 # so that it acts a like a single one.
402 # nproc: Limit the number of processes in the vserver according to ulimit
403 # (instead of a per user limit, this becomes a per vserver limit)
404 # private: No other process can join this security context. Even root
405 # Do not forget the quotes around the flags
407 # You can set various ulimit flags and they will be inherited by the
408 # vserver. You enter here various command line argument of ulimit
410 # The example above, combined with the nproc S_FLAGS will limit the
411 # vserver to a maximum of 200 processes
413 # You can set various capabilities. By default, the vserver are run
414 # with a limited set, so you can let root run in a vserver and not
415 # worry about it. He can't take over the machine. In some cases
416 # you can to give a little more capabilities (such as CAP_NET_RAW)
417 # S_CAPS="CAP_NET_RAW"
419 # Select an unused context (this is optional)
420 # The default is to allocate a free context on the fly
421 # In general you don't need to force a context
424 echo $CONF has been created. Look at it\!
427 elif [ ! -f /etc/vservers/$1.conf ] ; then
428 echo No configuration for this vserver: /etc/vservers/$1.conf
430 elif [ ! -d /vservers/$1/. ] ; then
431 echo No directory for this vserver: /vservers/$1
433 elif [ "$2" = "start" ] ; then
434 echo Starting the virtual server $1
436 if ! $VSERVER_CMD $1 running
438 test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-start $1
445 . /etc/vservers/$1.conf
448 cd /vservers/$1 || exit 1
450 if [ "$PROFILE" != "" ] ; then
451 echo export PROFILE=$PROFILE >etc/PROFILE
454 rm -f `find var/run -type f`
456 rm -f var/lock/subsys/*
457 mountproc /vservers/$1
465 STARTCMD="/etc/rc.d/rc $INITDEFAULT"
466 if [ -x /vservers/$1/etc/init.d/rc ] ; then
467 STARTCMD="/etc/init.d/rc $INITDEFAULT"
472 for f in $S_FLAGS dummy
480 FLAGS="$FLAGS --flag fakeinit"
481 STARTCMD=/sbin/minit-start
482 DISCONNECT=--disconnect
487 FLAGS="$FLAGS --flag $f"
489 DISCONNECT=--disconnect
492 FLAGS="$FLAGS --flag $f"
496 if [ "$FAKEINIT" = "" ] ; then
497 $USR_LIB_VSERVER/fakerunlevel $INITDEFAULT var/run/utmp
500 calculateCaps $S_CAPS
502 if [ "$S_CONTEXT" != "" ] ; then
503 CTXOPT="--ctx $S_CONTEXT"
505 if [ "$S_HOSTNAME" != "" ] ; then
506 HOSTOPT="--hostname $S_HOSTNAME"
507 export HOSTNAME=$S_HOSTNAME
509 if [ "$S_DOMAINNAME" != "" ] ; then
510 DOMAINOPT="--domainname $S_DOMAINNAME"
512 if [ "$S_NICE" != "" ] ; then
513 NICECMD="nice -$S_NICE"
515 mkdir -p /var/run/vservers
516 chmod 700 /var/run/vservers
518 if [ "$ULIMIT" != "" ] ; then
523 # We switch to /vservers/$1 now, because after the
524 # security context switch /vservers directory becomes a dead zone.
526 IPOPT=`setipopt $IPROOT`
527 export PATH=$DEFAULTPATH
528 $NICECMD $CHBIND_CMD $SILENT $IPOPT --bcast $IPROOTBCAST \
529 $CHCONTEXT_CMD $SILENT $DISCONNECT $CAPS $FLAGS $CTXOPT $HOSTOPT $DOMAINOPT --secure \
530 $SAVE_S_CONTEXT_CMD /var/run/vservers/$1.ctx \
531 $CAPCHROOT_CMD $CHROOTOPT . $STARTCMD
533 test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh post-start $1
535 elif [ "$2" = "running" ] ; then
536 if [ ! -f /var/run/vservers/$1.ctx ] ; then
537 echo Server $1 is not running
540 . /var/run/vservers/$1.ctx
541 NB=$($USR_SBIN/vps ax | awk '{print $2}' | grep \^$S_CONTEXT\$ | wc -l)
542 #NB=`$CHCONTEXT_CMD --silent --ctx $S_CONTEXT ps ax | wc -l`
543 #NB=`eval expr $NB + 0`
544 if [ "$NB" -gt 0 ] ; then
545 echo Server $1 is running
548 echo Server $1 is not running
552 elif [ "$2" = "status" ] ; then
555 . /var/run/vservers/$1.ctx
556 NB=$($USR_SBIN/vps ax | awk '{print $2}' | grep \^$S_CONTEXT\$ | wc -l)
557 echo $NB processes running
558 echo Vserver uptime: `$USR_LIB_VSERVER/filetime /var/run/vservers/$1.ctx`
560 elif [ "$2" = "stop" ] ; then
561 echo Stopping the virtual server $1
569 if $VSERVER_CMD $1 running
571 test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-stop $1
574 mountproc /vservers/$1
575 # The fakeinit flag tell us how to turn off the server
577 export PREVLEVEL=$INITDEFAULT
578 STOPCMD="/etc/rc.d/rc 6"
579 if [ -x /vservers/$1/etc/init.d/rc ] ; then
580 STOPCMD="/etc/init.d/rc 6"
582 for f in $S_FLAGS dummy
587 FLAGS="$FLAGS --flag fakeinit"
588 STOPCMD="/sbin/minit-stop"
592 FLAGS="$FLAGS --flag $f"
593 STOPCMD="/sbin/init 6"
600 calculateCaps $S_CAPS
603 IPOPT=`setipopt $IPROOT`
604 export PATH=$DEFAULTPATH
605 $CHBIND_CMD $SILENT $IPOPT --bcast $IPROOTBCAST \
606 $CHCONTEXT_CMD $SILENT $CAPS --secure --ctx $S_CONTEXT \
607 $CAPCHROOT_CMD . $STOPCMD
609 if test "$IS_MINIT"; then
610 echo "Waiting for minit finish-signal"
611 dd if=var/run/minit-stop of=/dev/zero bs=1 count=1 &>/dev/null
614 echo sleeping 5 seconds
618 echo Killing all processes
619 $CHBIND_CMD --silent $IPOPT --bcast $IPROOTBCAST \
620 $CHCONTEXT_CMD $CAPS --secure --silent --ctx $S_CONTEXT \
623 # We umount anyway, because "enter" establish the mount
624 # but when you exit, the server is considered not running
625 umountproc /vservers/$1
627 test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh post-stop $1
628 ifconfig_iproot_off $1
629 elif [ "$2" = "restart" ] ; then
635 elif [ "$2" = "suexec" ] ; then
636 if [ -z "$3" ] ; then
637 echo "Missing user!" >&2
638 echo "vserver vserver-name suexec user command [ args ... ]" >&2
640 elif [ -z "$4" ] ; then
641 echo "Missing command and arguments!" >&2
642 echo "vserver vserver-name suexec user command [ args ... ]" >&2
650 . /etc/vservers/$1.conf
653 mountproc /vservers/$1
654 PS1="[\u@vserver:$1 \W]"
660 for f in $S_CAPS dummy
669 CAPS="$CAPS --cap $f"
674 for f in $S_FLAGS dummy
678 FLAGS="$FLAGS --flag fakeinit"
684 FLAGS="$FLAGS --flag $f"
689 if [ "$ULIMIT" != "" ] ; then
692 if $0 $VSERVER running >/dev/null
694 . /var/run/vservers/$VSERVER.ctx
695 cd /vservers/$VSERVER
696 IPOPT=`setipopt $IPROOT`
697 export PATH=$DEFAULTPATH
698 $CHBIND_CMD $SILENT $IPOPT --bcast $IPROOTBCAST \
699 $CHCONTEXT_CMD $SILENT $FLAGS $CAPS --secure --ctx $S_CONTEXT \
700 $CAPCHROOT_CMD --suid $USERID . "$@"
702 test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-start $1
706 if [ "$S_CONTEXT" != "" ] ; then
707 CTXOPT="--ctx $S_CONTEXT"
709 if [ "$S_HOSTNAME" != "" ] ; then
710 HOSTOPT="--hostname $S_HOSTNAME"
711 export HOSTNAME=$S_HOSTNAME
713 if [ "$S_DOMAINNAME" != "" ] ; then
714 DOMAINOPT="--domainname $S_DOMAINNAME"
716 mkdir -p /var/run/vservers
717 cd /vservers/$VSERVER
718 IPOPT=`setipopt $IPROOT`
719 export PATH=$DEFAULTPATH
720 $CHBIND_CMD $SILENT $IPOPT --bcast $IPROOTBCAST \
721 $CHCONTEXT_CMD $SILENT $FLAGS $CAPS --secure $CTXOPT $HOSTOPT $DOMAINOPT \
722 $SAVE_S_CONTEXT_CMD /var/run/vservers/$VSERVER.ctx \
723 $CAPCHROOT_CMD --suid $USERID $CHROOTOPT . "$@"
726 elif [ "$2" = "exec" ] ; then
729 exec $0 $NODEV $SILENT $VSERV suexec root "$@"
730 elif [ "$2" = "enter" ] ; then
732 exec $0 $NODEV $SILENT $1 exec /bin/bash -login
733 elif [ "$2" = "service" ] ; then
737 exec $0 $NODEV $SILENT $VSERVER exec /sbin/service "$@"
738 elif [ "$2" = "chkconfig" ] ; then
743 if [ "$1" = "--level" ] ; then
744 LEVELS=( --level "$2" )
747 if [ $# != 2 -a ! -x /vservers/$VSERVER/sbin/chkconfig ] ; then
748 echo Invalid argument, expected vserver name chkconfig [ --level nnn ] service on\|off
749 elif [ -x /vservers/$VSERVER/sbin/chkconfig ] ; then
750 exec $0 --silent $VSERVER exec /sbin/chkconfig "${LEVELS[@]}" "$@"
751 elif [ -x /vservers/$VSERVER/usr/sbin/update-rc.d ] ; then
752 if [ "$2" = "on" -o "$2" = "start" ] ; then
753 $0 --silent $VSERVER exec /usr/sbin/update-rc.d -f $1 remove >/dev/null
754 exec $0 --silent $VSERVER exec /usr/sbin/update-rc.d $1 start 80 2 3 4 5 . stop 20 0 1 6 . >/dev/null
755 elif [ "$2" = "off" -o "$2" = "stop" ] ; then
756 $0 --silent $VSERVER exec /usr/sbin/update-rc.d -f $1 remove >/dev/null
757 exec $0 --silent $VSERVER exec /usr/sbin/update-rc.d $1 stop 20 0 1 2 3 4 5 6 . >/dev/null
759 echo vserver chkconfig: Expecting on or off
762 echo chkconfig functionality is not available on this
763 echo vserver distribution.
764 echo Looked for /sbin/chkconfig and /usr/sbin/update-rc.d
767 echo Command unknown $2