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_START=()
32 declare -a INITCMD_START_SYNC=()
33 declare -a INITCMD_STOP=()
34 declare -a INITCMD_STOP_SYNC=()
35 declare -a INITCMD_PREPARE=()
36 declare -a INITKILL_SEQ=()
37 declare -a ENTER_SHELL=()
39 declare -a OPTS_VCONTEXT_CREATE=()
40 declare -a OPTS_VCONTEXT_MIGRATE=()
41 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
42 declare -a OPTS_VSCHED=()
44 declare -a STOPCMD_PREPARE=()
46 declare -a VSERVER_EXTRA_CMDS=()
48 VSHELPER_SYNC_TIMEOUT=30
53 _HAVE_INTERFACE_OPTIONS=
64 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
66 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
72 function _generateChbindOptions
78 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
80 local f=$vdir/interfaces/bcast
81 getFileValue bcast "$f"
83 CHBIND_OPTS=( $SILENT_OPT ${bcast:+--bcast "$bcast"} )
85 for i in "${INTERFACES[@]}"; do
86 CHBIND_OPTS=( "${CHBIND_OPTS[@]}" --ip "$i" )
89 _HAVE_CHBIND_OPTIONS=1
92 function _generateNiceCommand
97 test -r "$vdir/nice" || return 0;
98 read nice <"$vdir"/nice
100 NICE_CMD=( $_NICE -$nice )
103 function _generateCCapabilityOptions
107 local f="$vdir"/ccapabilities
109 test -e "$f" || return 0
113 (*) OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --ccap "$cap" );;
118 function _generateBCapabilityOptions
122 local f="$vdir"/bcapabilities
124 test -e "$f" || return 0
128 (*) OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --bcap "$cap" );;
133 function _generateCapabilityOptions
138 _generateBCapabilityOptions "$vdir"
139 _generateCCapabilityOptions "$vdir"
141 test -e "$vdir"/capabilities || return 0
150 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
151 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
154 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
157 done <"$vdir"/capabilities
160 function getEnterShell
167 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
169 test -n "$ENTER_SHELL" || {
171 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
173 test -x "$vdir/vdir/$1" || continue
180 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
181 function sendKillSequence
187 while isCtxRunning "$ctx"; do
188 test -z "$wait" || sleep "$wait"
190 $_VKILL --xid "$ctx" ${1:+-s "$1"} 2>/dev/null || :
191 test -n "$2" || break
197 function _generateInitOptions
200 local cfgdir=$vdir/apps/init
205 INITCMD_START_SYNC=()
210 INITKILL_SEQ=( 15 5 9 )
211 CHCONTEXT_INIT_OPTS=()
214 getFileValue INITSTYLE "$cfgdir"/style
215 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
216 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
217 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
218 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
220 case x"$INITSTYLE" in
222 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
223 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
225 for i in /etc/init.d/rc /etc/rc.d/rc; do
226 test -x "$vdir/vdir/$i" || continue
227 INITCMD_START=( "$i" "$RUNLEVEL_START" )
228 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
230 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
234 INITCMD_START=( /sbin/init )
235 INITCMD_STOP=( /sbin/init )
237 _NEED_VSHELPER_SYNC=1
238 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
239 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
243 INITCMD_START=( /sbin/minit-start )
244 INITCMD_STOP=( /sbin/minit-stop )
246 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
247 _NEED_VSHELPER_SYNC=1
248 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
249 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
253 INITCMD_START=( /sbin/rc default )
254 INITCMD_STOP=( /sbin/rc shutdown )
258 (*) echo "Unknown init-style '$INITSTYLE'; aborting" >&2;
262 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
263 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
264 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
265 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
266 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
269 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
270 INITCMD_START_SYNC=()
275 if vshelper.isEnabled; then
276 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
282 function _generateFlagOptions
286 CHCONTEXT_FLAG_OPTS=()
288 test ! -e "$vdir"/flags || \
297 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
298 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
304 isAvoidNamespace "$vdir" || {
306 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
310 function _generateChcontextOptions
313 local ctx hostname domainname
318 read ctx <"$vdir"/context || :
320 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
321 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
324 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
326 _generateCapabilityOptions "$vdir"
327 _generateFlagOptions "$vdir"
329 CHCONTEXT_OPTS=( $SILENT_OPT \
330 "${CHCONTEXT_FLAG_OPTS[@]}" \
333 ${ctx:+--ctx "$ctx"} \
334 ${hostname:+--hostname "$hostname"} \
335 ${domainname:+--domainname "$domainname"} )
337 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
338 ${ctx:+--xid "$ctx"} )
339 ## put '--secure' at front so that it can be overridden
340 OPTS_VATTRIBUTE=( --secure "${OPTS_VATTRIBUTE[@]}" )
343 function _generateScheduleOptions
346 local f="$vdir"/schedule
347 test -e "$f" || return 0
349 local fill_rate interval tokens tokens_min tokens_max prio_bias
357 read prio_bias || prio_bias=
361 test -n "$prio_bias" || {
362 echo $"Bad content in '$f'; aborting..." >&2
366 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
367 --tokens "$tokens" --tokens_min "$tokens_min" \
368 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
371 function _getInterfaceValue
381 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
384 : ${_giv_tmp:=$_giv_dflt}
385 eval $_giv_val=\$_giv_tmp
388 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
389 function _transformMask2Prefix
393 test -n "$_tm2p_tmp" || {
394 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
401 function _addInterfaceCmd
403 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
404 let ++INTERFACE_CMDS_IDX
407 ## Usage: _generateMac <var> <iface> <ctx>
408 function _generateMac
411 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
415 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
418 ## Usage: _processSingleInterface <interface-directory>
419 function _processSingleInterface
434 _getInterfaceValue ip '' "$iface"
435 _getInterfaceValue extip '' "$iface" "$iface/.."
436 _getInterfaceValue dev '' "$iface" "$iface/.."
437 _getInterfaceValue prefix '' "$iface" "$iface/.."
438 _getInterfaceValue mask '' "$iface" "$iface/.."
439 _getInterfaceValue bcast '' "$iface" "$iface/.."
440 _getInterfaceValue name '' "$iface"
441 _getInterfaceValue scope '' "$iface" "$iface/.."
442 _getInterfaceValue mac '' "$iface"
444 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
445 test -n "$dev" -o -e "$iface"/nodev || {
446 echo $"No device specified for '$iface'" >&2
450 test ! -e "$iface"/down || up=
453 _transformMask2Prefix prefix "$prefix" "$mask"
454 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
456 test ! -e "$iface"/nodev || break
458 test ! -e "$iface"/only_ip || break
462 test -d /proc/net/vlan || {
463 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
466 test -f /proc/net/vlan || {
467 _addInterfaceCmd VCONFIG ${dev/./ }
468 _addInterfaceCmd IP_ADDR 127.0.0.1/8 broadcast 127.255.255.255 dev "$dev"
469 _addInterfaceCmd IP_LINK "$dev" $up
474 if ! test -e "$iface"/indirect; then
475 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} ${name:+label "$dev:$name"} dev "$dev"
476 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
477 _addInterfaceCmd IP_LINK "$dev" $up
478 elif ! test -n "$ctx"; then
479 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
482 test -z "$mac" || _generateMac mac "$(basename $iface)" "$ctx" || return 1
483 _addInterfaceCmd MODPROBE dummy "$dev"
484 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
485 _addInterfaceCmd NAMEIF "$dev" "$mac"
486 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
487 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$ctx" "$extip"
494 ## Usage: _generateInterfaceOptions <vserver-directory>
495 function _generateInterfaceOptions
500 test ! -e "$1"/context || read ctx <"$1"/context
502 for iface in "$1/interfaces/"*; do
503 test -d "$iface" || continue
504 test ! -e "$iface"/disabled || continue
506 _processSingleInterface "$iface"
508 _HAVE_INTERFACE_OPTIONS=1
511 function enableInterfaces
516 lock "$__LOCKDIR"/vserver.interfaces
518 while test $i -lt $INTERFACE_CMDS_IDX; do
519 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
530 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
532 NAMEIF) $_NAMEIF "$@";;
533 VCONFIG) $_VCONFIG add "$@";;
534 IP_ADDR) $_IP addr add "$@";;
535 IP_ADDR_FLUSH) $_IP addr flush "$@";;
536 IP_LINK) $_IP link set "$@";;
537 IP_ROUTE) $_IP route add "$@";;
538 *) echo "Unknown interface-command type '$type'" >&2; false;;
547 function disableInterfaces
549 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
551 local i=$INTERFACE_CMDS_IDX
554 lock "$__LOCKDIR"/vserver.interfaces
556 while test $i -gt 0; do
559 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
566 MODPROBE) $_RMMOD "${2:-$1}";;
568 VCONFIG) $_VCONFIG rem "$@";;
569 IP_ADDR) $_IP addr del "$@";;
571 IP_LINK) ;; ## Ignore the link-down command for now
572 IP_ROUTE) $_IP route del "$@";;
573 *) echo "Unknown interface-command type '$type'" >&2; false;;
580 ## Usage: prepareInit <vserver-directory>
583 pushd "$1/vdir" >/dev/null
586 { find var/run ! -type d -print0; \
587 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_RM
590 $_CHROOT_RM .autofsck forcefsck 2>/dev/null || :
591 : | $_CHROOT_CAT fastboot 2>/dev/null || :
596 "${INITCMD_PREPARE[@]}"
600 ## Usage: prepareInit <vserver-directory>
603 pushd "$1/vdir" >/dev/null
606 export PREVLEVEL=$RUNLEVEL_START # required by Debian's initscripts
609 "${STOPCMD_PREPARE[@]}"
614 function generateOptions
616 _generateInterfaceOptions "$1"
617 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
618 _generateNiceCommand "$1"
619 _generateInitOptions "$1"
620 _generateChcontextOptions "$1"
621 _generateScheduleOptions "$1"
623 if test -n "$_IS_FAKEINIT"; then
624 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
625 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
629 function _mountVserverInternal
632 test -e "$fstab" || return 0
635 pushd "$vdir" >/dev/null
636 "$@" $_SECURE_MOUNT -a --chroot --fstab "$fstab" --rootfs no
644 local fstab="$cfgdir"/fstab
646 test -e "$fstab" || return 0
647 pushd "$vdir" >/dev/null
648 $_SECURE_MOUNT -a --chroot --fstab "$fstab" --rootfs only -n
652 function mountVserver
659 test -e "$cfgdir"/fstab -o \
660 -e "$cfgdir"/fstab.local -o \
661 -e "$cfgdir"/fstab.remote || return 0
663 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
665 pushd "$vdir" >/dev/null
666 $_CHROOT_CAT /etc/mtab <"$mtab_src"
669 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
671 test -z "$NAMESPACE_CLEANUP" || isAvoidNamespace "$cfgdir" || \
672 $_VNAMESPACE --cleanup
674 _mountVserverInternal "$cfgdir"/fstab
675 _mountVserverInternal "$cfgdir"/fstab.local
676 _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}"
678 isAvoidNamespace "$cfgdir" || \
679 $_SECURE_MOUNT --rbind -n "$vdir" "/"
682 function _umountVserverInternal
685 test -e "$fstab" || return 0
690 while read src dst tmp; do
691 test -n "$tmp" || continue
697 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
703 function umountVserver
709 isAvoidNamespace "$cfgdir" || return 0
710 test -e "$cfgdir"/fstab -o \
711 -e "$cfgdir"/fstab.local || return 0
712 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
714 pushd "$vdir/" >/dev/null || return 1
715 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
716 _umountVserverInternal "$cfgdir"/fstab $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
717 popd >/dev/null || return 1
722 ## Usage: waitForSync <vserver> <vshelper-fifo-varname>
725 test -z "$_NEED_VSHELPER_SYNC" || vshelper.initSync "$1" "$2"
728 ## Usage: waitForSync <vserver> [<vshelper-fifo>]
734 if test -n "$_NEED_VSHELPER_SYNC"; then
735 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
737 A timeout or other error occured while waiting for the synchronization
738 signal from vserver '$VSERVER_NAME'.
739 The vserver will be killed nevertheless..."
740 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
741 "${INITCMD_STOP_SYNC[@]}" || \
743 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
744 will be killed nevertheless..."
747 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
753 local vdir name flavor start i already_handled base
757 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
758 function execScriptlets
765 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
766 local DONT_SKIP_DEFAULTS=
767 local already_handled=
769 for i in "$base/$flavor" "$base/$flavor.d"/*; do
770 test -f "$i" -a -r "$i" || continue
773 test -x "$i" || start=_sourceWrap
774 $start "$i" "$flavor" "$name"
777 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
786 ! test -e "$cfgdir"/fstab.local ||
788 WARNING: 'fstab' will *not* be executed in the network context of the
789 vserver anymore. Therefore, 'fstab.local' has the same functionality
790 and is obsoleted. When you need the old behaviour, put the mounts
793 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
795 WARNING: The hostname is now configured in 'uts/nodename' but not in
798 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
800 WARNING: The domainname is now configured in 'uts/domainname' but not
801 in 'domainname'." >&2
805 for i in "$cfgdir"/interfaces/*/only_ip; do
806 if test -e "$i"; then
808 iface=${i##$cfgdir/interfaces/}
809 iface=${iface%%/only_ip}
811 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
816 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
818 vshelper.doSanityCheck
820 $_VSERVER_INFO - VERIFYCAP ||
821 panic $"capabilities are not enabled in kernel-setup"