3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # $VSERVER_DIR ... path to vserver-cfg dir
20 # $VSERVER_NAME ... name of vserver
22 declare -a NICE_CMD=()
23 declare -a CHBIND_OPTS=()
24 declare -a CAP_OPTS=()
25 declare -a CHCONTEXT_INIT_OPTS=()
26 declare -a CHCONTEXT_FLAG_OPTS=()
27 declare -a CHCONTEXT_OPTS=()
28 declare -a CAPCHROOT_OPTS=()
29 declare -a INTERFACES=()
31 declare -a INITCMD_RESCUE=( /bin/sleep 900 )
32 declare -a INITCMD_START=()
33 declare -a INITCMD_START_SYNC=()
34 declare -a INITCMD_STOP=()
35 declare -a INITCMD_STOP_SYNC=()
36 declare -a INITCMD_PREPARE=()
37 declare -a INITKILL_SEQ=()
38 declare -a ENTER_SHELL=()
40 declare -a OPTS_VCONTEXT_CREATE=()
41 declare -a OPTS_VCONTEXT_MIGRATE=()
42 declare -a OPTS_VCONTEXT_ENTER=()
43 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
44 declare -a OPTS_VSCHED=()
46 declare -a STOPCMD_PREPARE=()
48 declare -a VSERVER_EXTRA_CMDS=()
51 VSHELPER_SYNC_TIMEOUT=30
56 _HAVE_INTERFACE_OPTIONS=
67 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
69 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
75 function _generateChbindOptions
81 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
83 local f=$vdir/interfaces/bcast
84 getFileValue bcast "$f"
86 CHBIND_OPTS=( $SILENT_OPT ${bcast:+--bcast "$bcast"} )
88 for i in "${INTERFACES[@]}"; do
89 CHBIND_OPTS=( "${CHBIND_OPTS[@]}" --ip "$i" )
92 _HAVE_CHBIND_OPTIONS=1
95 function _generateNiceCommand
100 test -r "$vdir/nice" || return 0;
101 read nice <"$vdir"/nice
103 NICE_CMD=( $_NICE -$nice )
107 function _generatePersonalityOptions
110 local f="$vdir"/personality
113 test -s "$f" || return 0
122 (*) flags=$flags$delim$tmp
129 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
130 --personality-type "$type"
131 ${flags:+--personality-flags "$flags"} )
134 function _generateCCapabilityOptions
138 local f="$vdir"/ccapabilities
140 test -e "$f" || return 0
144 (*) OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --ccap "$cap" );;
149 function _generateBCapabilityOptions
153 local f="$vdir"/bcapabilities
155 test -e "$f" || return 0
159 (*) OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --bcap "$cap" );;
164 function _generateCapabilityOptions
169 _generateBCapabilityOptions "$vdir"
170 _generateCCapabilityOptions "$vdir"
172 test -e "$vdir"/capabilities || return 0
181 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
182 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
185 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
188 done <"$vdir"/capabilities
191 function getEnterShell
198 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
200 test -n "$ENTER_SHELL" || {
202 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
204 test -x "$vdir/vdir/$1" || continue
211 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
212 function sendKillSequence
218 while isCtxRunning "$ctx"; do
219 test -z "$wait" || sleep "$wait"
221 killContext "$ctx" "$1"
222 test -n "$2" || break
228 function _generateInitOptions
231 local cfgdir=$vdir/apps/init
236 INITCMD_START_SYNC=()
241 INITKILL_SEQ=( 15 5 9 )
242 CHCONTEXT_INIT_OPTS=()
245 getFileValue INITSTYLE "$cfgdir"/style
246 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
247 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
248 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
249 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
251 case x"$INITSTYLE" in
253 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
254 INITCMD_STOP=( /sbin/killall5 )
260 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
261 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
263 for i in /etc/init.d/rc /etc/rc.d/rc; do
264 test -x "$vdir/vdir/$i" || continue
265 INITCMD_START=( "$i" "$RUNLEVEL_START" )
266 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
268 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
272 INITCMD_START=( /sbin/init )
273 INITCMD_STOP=( /sbin/init )
275 _NEED_VSHELPER_SYNC=1
276 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
277 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
281 INITCMD_START=( /sbin/minit-start )
282 INITCMD_STOP=( /sbin/minit-stop )
284 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
285 _NEED_VSHELPER_SYNC=1
286 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
287 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
288 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
292 INITCMD_START=( /sbin/rc default )
293 INITCMD_STOP=( /sbin/rc shutdown )
297 (*) echo "Unknown init-style '$INITSTYLE'; aborting" >&2;
301 if test x"$INITSTYLE" != xrescue; then
302 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
303 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
304 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
305 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
306 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
309 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
310 INITCMD_START_SYNC=()
315 if vshelper.isEnabled; then
316 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
322 function _generateFlagOptions
326 CHCONTEXT_FLAG_OPTS=()
328 test ! -e "$vdir"/flags || \
337 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
338 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
344 isAvoidNamespace "$vdir" || {
346 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
350 function _generateChcontextOptions
353 local ctx hostname domainname
358 read ctx <"$vdir"/context || :
360 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
361 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
364 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
366 _generateCapabilityOptions "$vdir"
367 _generateFlagOptions "$vdir"
369 CHCONTEXT_OPTS=( $SILENT_OPT \
370 "${CHCONTEXT_FLAG_OPTS[@]}" \
373 ${ctx:+--ctx "$ctx"} \
374 ${hostname:+--hostname "$hostname"} \
375 ${domainname:+--domainname "$domainname"} )
377 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
378 ${ctx:+--xid "$ctx"} )
379 ## put '--secure' at front so that it can be overridden
380 OPTS_VATTRIBUTE=( --secure "${OPTS_VATTRIBUTE[@]}" )
383 function _generateScheduleOptions
386 local f="$vdir"/schedule
387 test -e "$f" || return 0
389 local fill_rate interval tokens tokens_min tokens_max prio_bias
397 read prio_bias || prio_bias=
401 test -n "$prio_bias" || {
402 echo $"Bad content in '$f'; aborting..." >&2
406 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
407 --tokens "$tokens" --tokens_min "$tokens_min" \
408 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
411 function _getInterfaceValue
421 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
424 : ${_giv_tmp:=$_giv_dflt}
425 eval $_giv_val=\$_giv_tmp
428 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
429 function _transformMask2Prefix
433 test -n "$_tm2p_tmp" || {
434 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
441 function _addInterfaceCmd
443 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
444 let ++INTERFACE_CMDS_IDX
447 ## Usage: _generateMac <var> <iface> <ctx>
448 function _generateMac
451 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
455 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
458 ## Usage: _processSingleInterface <interface-directory>
459 function _processSingleInterface
474 _getInterfaceValue ip '' "$iface"
475 _getInterfaceValue extip '' "$iface" "$iface/.."
476 _getInterfaceValue dev '' "$iface" "$iface/.."
477 _getInterfaceValue prefix '' "$iface" "$iface/.."
478 _getInterfaceValue mask '' "$iface" "$iface/.."
479 _getInterfaceValue bcast '' "$iface" "$iface/.."
480 _getInterfaceValue name '' "$iface"
481 _getInterfaceValue scope '' "$iface" "$iface/.."
482 _getInterfaceValue mac '' "$iface"
484 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
485 test -n "$dev" -o -e "$iface"/nodev || {
486 echo $"No device specified for '$iface'" >&2
490 test ! -e "$iface"/down || up=
493 _transformMask2Prefix prefix "$prefix" "$mask"
494 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
496 test ! -e "$iface"/nodev || break
498 test ! -e "$iface"/only_ip || break
502 test -d /proc/net/vlan || {
503 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
506 test -f /proc/net/vlan || {
507 _addInterfaceCmd VCONFIG ${dev/./ }
508 _addInterfaceCmd IP_ADDR 127.0.0.1/8 broadcast 127.255.255.255 dev "$dev"
509 _addInterfaceCmd IP_LINK "$dev" $up
514 if ! test -e "$iface"/indirect; then
515 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} ${name:+label "$dev:$name"} dev "$dev"
516 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
517 _addInterfaceCmd IP_LINK "$dev" $up
518 elif ! test -n "$ctx"; then
519 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
522 test -z "$mac" || _generateMac mac "$(basename $iface)" "$ctx" || return 1
523 _addInterfaceCmd MODPROBE dummy "$dev"
524 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
525 _addInterfaceCmd NAMEIF "$dev" "$mac"
526 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
527 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$ctx" "$extip"
534 ## Usage: _generateInterfaceOptions <vserver-directory>
535 function _generateInterfaceOptions
540 test ! -e "$1"/context || read ctx <"$1"/context
542 for iface in "$1/interfaces/"*; do
543 test -d "$iface" || continue
544 test ! -e "$iface"/disabled || continue
546 _processSingleInterface "$iface"
548 _HAVE_INTERFACE_OPTIONS=1
551 function enableInterfaces
556 lock "$__LOCKDIR"/vserver.interfaces
558 while test $i -lt $INTERFACE_CMDS_IDX; do
559 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
570 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
572 NAMEIF) $_NAMEIF "$@";;
573 VCONFIG) $_VCONFIG add "$@";;
574 IP_ADDR) $_IP addr add "$@";;
575 IP_ADDR_FLUSH) $_IP addr flush "$@";;
576 IP_LINK) $_IP link set "$@";;
577 IP_ROUTE) $_IP route add "$@";;
578 *) echo "Unknown interface-command type '$type'" >&2; false;;
587 function disableInterfaces
589 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
591 local i=$INTERFACE_CMDS_IDX
594 lock "$__LOCKDIR"/vserver.interfaces
596 while test $i -gt 0; do
599 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
606 MODPROBE) $_RMMOD "${2:-$1}";;
608 VCONFIG) $_VCONFIG rem "$@";;
609 IP_ADDR) $_IP addr del "$@";;
611 IP_LINK) ;; ## Ignore the link-down command for now
612 IP_ROUTE) $_IP route del "$@";;
613 *) echo "Unknown interface-command type '$type'" >&2; false;;
620 ## Usage: prepareInit <vserver-directory>
623 pushd "$1/vdir" >/dev/null
626 { find var/run ! -type d -print0; \
627 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
630 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
631 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
636 "${INITCMD_PREPARE[@]}"
640 ## Usage: prepareInit <vserver-directory>
643 pushd "$1/vdir" >/dev/null
646 export PREVLEVEL=$RUNLEVEL_START # required by Debian's initscripts
649 "${STOPCMD_PREPARE[@]}"
654 function generateOptions
656 _generateInterfaceOptions "$1"
657 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
658 _generateNiceCommand "$1"
659 _generateInitOptions "$1"
660 _generateChcontextOptions "$1"
661 _generateScheduleOptions "$1"
662 _generatePersonalityOptions "$1"
664 if test -n "$_IS_FAKEINIT"; then
665 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
666 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
670 function _mountVserverInternal
673 test -e "$fstab" || return 0
676 pushd "$vdir" >/dev/null
677 "$@" $_SECURE_MOUNT -a --chroot --fstab "$fstab" --rootfs no
685 local fstab="$cfgdir"/fstab
687 test -e "$fstab" || return 0
688 pushd "$vdir" >/dev/null
689 $_SECURE_MOUNT -a --chroot --fstab "$fstab" --rootfs only -n
693 function mountVserver
700 test -e "$cfgdir"/fstab -o \
701 -e "$cfgdir"/fstab.local -o \
702 -e "$cfgdir"/fstab.remote || return 0
704 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
706 pushd "$vdir" >/dev/null
707 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
710 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
712 test -z "$NAMESPACE_CLEANUP" || isAvoidNamespace "$cfgdir" || \
713 $_VNAMESPACE --cleanup
715 _mountVserverInternal "$cfgdir"/fstab
716 _mountVserverInternal "$cfgdir"/fstab.local
717 _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}"
719 isAvoidNamespace "$cfgdir" || \
720 $_SECURE_MOUNT --rbind -n "$vdir" "/"
723 function _umountVserverInternal
726 test -e "$fstab" || return 0
731 while read src dst tmp; do
732 test -n "$tmp" || continue
738 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
744 function umountVserver
750 isAvoidNamespace "$cfgdir" || return 0
751 test -e "$cfgdir"/fstab -o \
752 -e "$cfgdir"/fstab.local || return 0
753 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
755 pushd "$vdir/" >/dev/null || return 1
756 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
757 _umountVserverInternal "$cfgdir"/fstab $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
758 popd >/dev/null || return 1
763 ## Usage: waitForSync <vserver> <vshelper-fifo-varname>
767 test -n "$_NEED_VSHELPER_SYNC" || _is_meth=async
769 vshelper.initSync "$1" "$2" "$_is_meth"
772 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
775 if $_VSERVER_INFO - FEATURE vwait; then
777 _is_tmpdir=$($_MKTEMPDIR /tmp/vwaitstat.XXXXXX)
779 $_NOHUP $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
780 --terminate --status-fd 3 "$2" \
781 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo &
783 echo "$!" >$_is_tmpdir/pid
784 eval "$4"=$_is_tmpdir
789 ## Usage: _waitForVWait <fifo> <pid>
790 function _waitForVWait
793 getFileArray status "$1"
799 'vwait' exited with error '$2' which indicates that vserver could not
804 A timeout occured while waiting for the vserver to finish and it was
805 killed by sending a SIGKILL signal. Please investigate the reasons
806 and/or increase the timeout in apps/vshelper/sync-timeout."
808 (TIMEOUT|\?\?\?|*) warning $"\
809 internal error: 'vwait' exited with an unexpected status; I will try
810 to continue but be prepared for unexpected events."
817 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
822 local vwait_statdir=$3
825 if test -d "$vwait_statdir"; then
826 _waitForVWait "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )"
827 elif test -n "$_NEED_VSHELPER_SYNC"; then
828 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
830 A timeout or other error occured while waiting for the synchronization
831 signal from vserver '$VSERVER_NAME'.
832 The vserver will be killed nevertheless..."
833 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
834 "${INITCMD_STOP_SYNC[@]}" || \
836 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
837 will be killed nevertheless..."
840 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
846 local vdir name flavor start i already_handled base
850 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
851 function execScriptlets
858 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
859 local DONT_SKIP_DEFAULTS=
860 local already_handled=
862 for i in "$base/$flavor" "$base/$flavor.d"/*; do
863 isRegularFile "$i" || continue
864 test -r "$i" || continue
868 test -x "$i" || start=_sourceWrap
869 $start "$i" "$flavor" "$name"
872 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
881 ! test -e "$cfgdir"/fstab.local ||
883 WARNING: 'fstab' will *not* be executed in the network context of the
884 vserver anymore. Therefore, 'fstab.local' has the same functionality
885 and is obsoleted. When you need the old behaviour, put the mounts
888 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
890 WARNING: The hostname is now configured in 'uts/nodename' but not in
893 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
895 WARNING: The domainname is now configured in 'uts/domainname' but not
896 in 'domainname'." >&2
900 for i in "$cfgdir"/interfaces/*/only_ip; do
901 if test -e "$i"; then
903 iface=${i##$cfgdir/interfaces/}
904 iface=${iface%%/only_ip}
906 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
911 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
913 vshelper.doSanityCheck
915 $_VSERVER_INFO - VERIFYCAP ||
916 panic $"capabilities are not enabled in kernel-setup"
918 $_VSERVER_INFO - VERIFYPROC ||
920 /proc/uptime can not be accessed. Usually, this is caused by
921 procfs-security. Please read the FAQ for more details
922 http://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ"