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_CMD=()
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=()
45 declare -a OPTS_ENV=()
46 declare -a OPTS_VTAG_CREATE=()
47 declare -a OPTS_VTAG_ENTER=()
48 declare -a OPTS_VMEMCTRL=()
49 declare -a OPTS_VSPACE=()
51 declare -a STOPCMD_PREPARE=()
53 declare -a VSERVER_EXTRA_CMDS=()
56 VSHELPER_SYNC_TIMEOUT=30
61 _HAVE_INTERFACE_OPTIONS=
73 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
75 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
81 function _readFileToArray
88 test -e "$_rfta_f" || return 0
89 while read _rfta_v; do
92 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
97 function _generateChbindOptions
105 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
107 local f="$vdir"/interfaces/bcast
108 getFileValue bcast "$f"
109 f="$vdir"/interfaces/lback
110 getFileValue lback "$f"
112 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
113 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
116 for i in "${INTERFACES[@]}"; do
117 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
120 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
121 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
123 _HAVE_CHBIND_OPTIONS=1
126 function _generateNiceCommand
130 local current_nice=`$_NICE`
132 test -r "$vdir/nice" && read nice <"$vdir"/nice
134 let nice=$nice-$current_nice || :
135 NICE_CMD=( $_NICE -n $nice )
139 function _generatePersonalityOptions
142 local f="$vdir"/personality
145 test -s "$f" || return 0
154 (*) flags=$flags$delim$tmp
161 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
162 --personality-type "$type"
163 ${flags:+--personality-flags "$flags"} )
166 function _generateCCapabilityOptions
170 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
173 function _generateBCapabilityOptions
177 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
180 function _generateCapabilityOptions
185 _generateBCapabilityOptions "$vdir"
186 _generateCCapabilityOptions "$vdir"
188 test -e "$vdir"/capabilities || return 0
197 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
198 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
201 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
204 done <"$vdir"/capabilities
207 function getEnterShell
214 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
216 test -n "$ENTER_SHELL" || {
218 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
220 test -x "$vdir/vdir/$1" || continue
227 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
228 function sendKillSequence
234 while isCtxRunning "$ctx"; do
235 test -z "$wait" || sleep "$wait"
237 killContext "$ctx" "$1"
238 test -n "$2" || break
244 function _generateInitOptions
247 local cfgdir=$vdir/apps/init
252 INITCMD_START_SYNC=()
257 INITKILL_SEQ=( 15 5 9 )
258 CHCONTEXT_INIT_OPTS=()
261 test x"$INITSTYLE" = xrescue || \
262 getFileValue INITSTYLE "$cfgdir"/style
263 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
264 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
265 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
266 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
268 findFile _gio_env "$cfgdir"/environment \
269 "$__CONFDIR"/.defaults/apps/init/environment \
270 "$__PKGLIBDEFAULTDIR"/environment
271 getFileArray OPTS_ENV "$_gio_env" || :
273 case x"$INITSTYLE" in
275 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
276 INITCMD_STOP=( /sbin/killall5 )
280 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
281 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
283 for i in /etc/init.d/rc /etc/rc.d/rc; do
284 test -x "$vdir/vdir/$i" || continue
285 INITCMD_START=( "$i" "$RUNLEVEL_START" )
286 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
288 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
289 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
290 if test -n "$OPTION_DEBUG_SYSV"; then
291 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
292 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
297 INITCMD_START=( /sbin/init )
298 INITCMD_STOP=( /sbin/init )
300 _NEED_VSHELPER_SYNC=1
301 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
302 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
306 INITCMD_START=( /sbin/minit-start )
307 INITCMD_STOP=( /sbin/minit-stop )
309 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
310 _NEED_VSHELPER_SYNC=1
311 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
312 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
313 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
317 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
318 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
320 INITCMD_START=( env TERM=$TERM /lib/rcscripts/sh/init-vserver.sh "$RUNLEVEL_START" )
321 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
322 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
326 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
329 if test x"$INITSTYLE" != xrescue; then
330 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
331 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
332 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
333 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
334 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
337 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
338 INITCMD_START_SYNC=()
343 if vshelper.isEnabled; then
344 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
350 function _generateFlagOptions
354 CHCONTEXT_FLAG_OPTS=()
356 test ! -e "$vdir"/flags || \
365 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
366 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
372 isAvoidNamespace "$vdir" || {
374 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
378 function _generateChcontextOptions
381 local ctx hostname domainname
386 read ctx <"$vdir"/context || :
388 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
389 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
392 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
394 _generateCapabilityOptions "$vdir"
395 _generateFlagOptions "$vdir"
397 CHCONTEXT_OPTS=( $SILENT_OPT \
398 "${CHCONTEXT_FLAG_OPTS[@]}" \
401 ${ctx:+--ctx "$ctx"} \
402 ${hostname:+--hostname "$hostname"} \
403 ${domainname:+--domainname "$domainname"} )
405 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
406 ${ctx:+--xid "$ctx"} )
407 ## put '--secure' at front so that it can be overridden
408 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
411 function _generateScheduleOptions
414 if test -d "$vdir"/sched; then
415 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
419 local f="$vdir"/schedule
420 test -e "$f" || return 0
422 local fill_rate interval tokens tokens_min tokens_max prio_bias
430 read prio_bias || prio_bias=
434 test -n "$prio_bias" || {
435 echo $"Bad content in '$f'; aborting..." >&2
439 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
440 --tokens "$tokens" --tokens_min "$tokens_min" \
441 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
444 function _getInterfaceValue
454 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
457 : ${_giv_tmp:=$_giv_dflt}
458 eval $_giv_val=\$_giv_tmp
461 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
462 function _transformMask2Prefix
466 test -n "$_tm2p_tmp" || {
467 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
474 function _addInterfaceCmd
476 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
477 let ++INTERFACE_CMDS_IDX
480 ## Usage: _generateMac <var> <iface> <ctx>
481 function _generateMac
484 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
488 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
491 function _getVLANInfo
496 creation of VLAN_PLUS_VID devices is not supported; please create them
497 before starting the vserver and use the 'nodev' flag then"
498 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
502 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
503 create them before starting the vserver and use the 'nodev' flag then"
504 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
506 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
507 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
518 test -e "$iface/tun" -o -e "$iface/tap" || return 1
519 test ! -e "$iface/tun" || echo --tun
520 test ! -e "$iface/tap" || echo --tap
521 test ! -e "$iface/nocsum" || echo --~checksum
522 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
523 if test -e "$iface/uid"; then
525 getFileValue uid "$iface/uid"
528 if test -e "$iface/gid"; then
530 getFileValue gid "$iface/gid"
533 if test -e "$iface/linktype"; then
535 getFileValue linktype "$iface/linktype"
536 echo --linktype "$linktype"
541 ## Usage: _processSingleInterface <interface-directory>
542 function _processSingleInterface
557 _getInterfaceValue ip '' "$iface"
558 _getInterfaceValue extip '' "$iface" "$iface/.."
559 _getInterfaceValue dev '' "$iface" "$iface/.."
560 _getInterfaceValue prefix '' "$iface" "$iface/.."
561 _getInterfaceValue mask '' "$iface" "$iface/.."
562 _getInterfaceValue bcast '' "$iface" "$iface/.."
563 _getInterfaceValue name '' "$iface"
564 _getInterfaceValue scope '' "$iface" "$iface/.."
565 _getInterfaceValue mac '' "$iface"
567 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
568 test -n "$dev" -o -e "$iface"/nodev || {
569 echo $"No device specified for '$iface'" >&2
573 test ! -e "$iface"/down || up=
576 _transformMask2Prefix prefix "$prefix" "$mask"
577 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
579 test ! -e "$iface"/nodev || break
581 test ! -e "$iface"/only_ip || break
583 test -e "$iface/vlandev" \
584 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
585 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
586 -a ! -e "$iface/novlandev" \
587 -a ! -e "$iface/../novlandev" \) && {
589 if vlan_info=$(_getVLANInfo "$dev"); then
590 test -d /proc/net/vlan || {
591 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
594 _addInterfaceCmd VCONFIG $vlan_info
598 if ! test -e "$iface"/indirect; then
600 local use_bcast="broadcast ${bcast:-+}"
601 echo "$ip" | $_GREP -q : && use_bcast=
604 if tun_info=$(_getTunInfo "$iface"); then
605 _addInterfaceCmd TUNCTL "$dev" $tun_info
608 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev"
609 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
610 _addInterfaceCmd IP_LINK "$dev" $up
611 elif ! test -n "$N_CONTEXT"; then
612 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
615 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
616 _addInterfaceCmd MODPROBE dummy "$dev"
617 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
618 _addInterfaceCmd NAMEIF "$dev" "$mac"
619 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
620 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
627 ## Usage: _generateInterfaceOptions <vserver-directory>
628 function _generateInterfaceOptions
632 # XXX: This is here instead of in _generateChbindOptions
633 # to avoid a circular dependency
634 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
635 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
637 for iface in "$1/interfaces/"*; do
638 test -d "$iface" || continue
639 test ! -e "$iface"/disabled || continue
641 _processSingleInterface "$iface"
643 _HAVE_INTERFACE_OPTIONS=1
646 function enableInterfaces
651 lock "$__LOCKDIR"/vserver.interfaces
653 while test $i -lt $INTERFACE_CMDS_IDX; do
654 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
665 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
667 NAMEIF) $_NAMEIF "$@";;
668 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
669 $_VCONFIG add "$2" "$3" >/dev/null;;
670 IP_ADDR) $_IP addr add "$@";;
671 IP_ADDR_FLUSH) $_IP addr flush "$@";;
672 IP_LINK) $_IP link set "$@";;
673 IP_ROUTE) $_IP route add "$@";;
677 $_TUNCTL --persist "$@" "$dev"
679 *) echo "Unknown interface-command type '$type'" >&2; false;;
688 function disableInterfaces
690 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
692 local i=$INTERFACE_CMDS_IDX
695 lock "$__LOCKDIR"/vserver.interfaces
697 while test $i -gt 0; do
700 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
707 MODPROBE) $_RMMOD "${2:-$1}";;
709 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
710 IP_ADDR) $_IP addr del "$@";;
712 IP_LINK) ;; ## Ignore the link-down command for now
713 IP_ROUTE) $_IP route del "$@";;
714 TUNCTL) $_TUNCTL --~persist "$1";;
715 *) echo "Unknown interface-command type '$type'" >&2; false;;
722 function _generateTagOptions
727 getFileValue tag "$vdir/tag" "$vdir/context"
728 test -n "$tag" || return 0
730 OPTS_VTAG_CREATE=( --tag "$tag" )
731 OPTS_VTAG_ENTER=( --tag "$tag" )
734 function _generateMemctrlOptions
739 getFileValue badness "$vdir/badness"
740 test -n "$badness" || return 0
742 OPTS_VMEMCTRL=( --badness "$badness" )
745 function _generateSpaceOptions
748 local d="$vdir"/spaces
750 test ! -e "$d"/pid || \
751 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
753 test ! -e "$d"/net || {
754 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
755 # network context and namespace don't make much sense
756 _HAVE_CHBIND_OPTIONS=1
761 getFileValue mask "$d"/mask || \
762 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
765 ## Usage: prepareInit <vserver-directory>
768 pushd "$1/vdir" >/dev/null
771 { find var/run ! -type d -print0; \
772 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
775 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
776 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
781 "${INITCMD_PREPARE[@]}"
785 ## Usage: prepareInit <vserver-directory>
788 pushd "$1/vdir" >/dev/null
791 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
794 "${STOPCMD_PREPARE[@]}"
799 function generateOptions
801 _generateInterfaceOptions "$1"
802 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
803 _generateNiceCommand "$1"
804 _generateInitOptions "$1"
805 _generateChcontextOptions "$1"
806 _generateScheduleOptions "$1"
807 _generatePersonalityOptions "$1"
808 _generateTagOptions "$1"
809 _generateMemctrlOptions "$1"
810 _generateSpaceOptions "$1"
812 if test -n "$_IS_FAKEINIT"; then
813 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
814 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
822 local f="$vdir"/cpuset
826 test -d "$f" || return 0
827 test -e "$f"/name || return 0
829 read cpuset < "$f"/name
830 test -e "$f"/nocreate || {
831 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
832 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
833 if test -e "$f"/"$i"; then
834 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
842 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
843 if [ "$configured" -ne 0 ]; then
845 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
846 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
851 function removeCPUSET
855 local f="$vdir"/cpuset
857 test -d "$f" || return 0
858 test -e "$f"/name || return 0
860 read cpuset < "$f"/name
861 test -e "$f"/nocreate || {
862 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
866 function _mountVserverInternal
871 test -e "$fstab" || return 0
874 pushd "$vdir" >/dev/null
875 # check whether / is mounted readonly or whether there is special
876 # magic regarding the mtab file; when etc/mtab can not be touched,
877 # add the '-n' flag to mount
878 test -w etc -o -w etc/mtab || xflag=-n
879 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
887 local fstab="$cfgdir"/fstab
890 test -e "$fstab" || return 0
891 pushd "$vdir" >/dev/null
892 # check whether / is mounted readonly or whether there is special
893 # magic regarding the mtab file; when etc/mtab can not be touched,
894 # add the '-n' flag to mount
895 test -w etc -o -w etc/mtab || xflag=-n
896 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
900 function mountVserver
907 test -e "$cfgdir"/fstab -o \
908 -e "$cfgdir"/fstab.local -o \
909 -e "$cfgdir"/fstab.remote || return 0
911 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
913 pushd "$vdir" >/dev/null
914 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
917 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
919 _mountVserverInternal "$cfgdir"/fstab
920 _mountVserverInternal "$cfgdir"/fstab.local
921 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
923 isNamespaceCleanup "$cfgdir" && \
924 _namespaceCleanup "$cfgdir"
926 isAvoidNamespace "$cfgdir" || \
927 $_SECURE_MOUNT --rbind -n "$vdir" "/"
930 function _umountVserverInternal
933 test -e "$fstab" || return 0
938 while read src dst tmp; do
939 test -n "$tmp" || continue
945 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
951 function umountVserver
957 isAvoidNamespace "$cfgdir" || return 0
958 test -e "$cfgdir"/fstab -o \
959 -e "$cfgdir"/fstab.local -o \
960 -e "$cfgdir"/fstab.remote || return 0
961 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
963 pushd "$vdir/" >/dev/null || return 1
964 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
965 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
966 _umountVserverInternal "$cfgdir"/fstab || is_ok=
967 popd >/dev/null || return 1
975 local fstab="$cfgdir"/fstab
979 test -e "$fstab" || return 0
981 export FSTAB_FILE="$fstab"
984 test "$fsck_exitcode" -eq 0 -o \
985 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
988 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
992 test -n "$_NEED_VSHELPER_SYNC" && \
993 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
995 vshelper.initSync "$1" "$3" "$_is_meth"
998 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1001 if $_VSERVER_INFO - FEATURE vwait; then
1003 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1006 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1007 --status-fd 3 "$2" \
1008 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1011 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1012 $_VPS axf | $_EGREP -e "^[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1013 killContext "$S_CONTEXT" 9
1017 ) 4>$_is_tmpdir/procs &
1019 echo "$!" >$_is_tmpdir/pid
1020 eval "$3"=$_is_tmpdir
1025 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1026 function _waitForVWait
1031 declare -r procs=$(cat $4)
1033 getFileArray status "$2"
1038 'vwait' exited with error '$2' which indicates that vserver could not
1039 be stopped properly"
1042 (KILLED) warning $"\
1043 A timeout occured while waiting for the vserver to finish and it was
1044 killed by sending a SIGKILL signal. Please investigate the reasons
1045 and/or increase the timeout in apps/vshelper/sync-timeout."
1048 (TIMEOUT) warning $"\
1049 A timeout occured while waiting for the vserver to finish and it will
1050 be killed by sending a SIGKILL signal. The following process list
1051 might be useful for finding out the reason of this behavior:
1053 ----------------------------------------------------------------------
1055 }----------------------------------------------------------------------"
1058 (\?\?\?|*) warning $"\
1059 internal error: 'vwait' exited with an unexpected status '$1'; I will
1060 try to continue but be prepared for unexpected events."
1067 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1068 function waitForSync
1072 local vwait_statdir=$3
1075 if test -d "$vwait_statdir"; then
1076 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1077 elif test -n "$_NEED_VSHELPER_SYNC"; then
1078 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1080 A timeout or other error occured while waiting for the synchronization
1081 signal from vserver '$VSERVER_NAME'.
1082 The vserver will be killed nevertheless..."
1083 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1084 "${INITCMD_STOP_SYNC[@]}" || \
1086 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1087 will be killed nevertheless..."
1090 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1094 function _sourceWrap
1096 local vdir name flavor start i already_handled base
1100 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1101 function execScriptlets
1105 declare -r flavor=$3
1108 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1109 local DONT_SKIP_DEFAULTS=
1110 local already_handled=
1112 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1113 isRegularFile "$i" || continue
1114 test -r "$i" || continue
1118 test -x "$i" || start=_sourceWrap
1119 $start "$i" "$flavor" "$name"
1122 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1127 function sanityCheck
1129 declare -r cfgdir=$1
1131 ! test -e "$cfgdir"/fstab.local ||
1133 WARNING: 'fstab' will *not* be executed in the network context of the
1134 vserver anymore. Therefore, 'fstab.local' has the same functionality
1135 and is obsoleted. When you need the old behaviour, put the mounts
1136 into 'fstab.remote'"
1138 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1140 WARNING: The hostname is now configured in 'uts/nodename' but not in
1143 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1145 WARNING: The domainname is now configured in 'uts/domainname' but not
1146 in 'domainname'." >&2
1150 for i in "$cfgdir"/interfaces/*/only_ip; do
1151 if test -e "$i"; then
1153 iface=${i##$cfgdir/interfaces/}
1154 iface=${iface%%/only_ip}
1156 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1161 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1163 WARNING: There is no cachedirectory configured for this vserver;
1164 please create '$cfgdir/cache' e.g. by executing
1166 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1169 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1171 vshelper.doSanityCheck
1173 $_VSERVER_INFO - VERIFYCAP ||
1174 panic $"capabilities are not enabled in kernel-setup"
1176 $_VSERVER_INFO - VERIFYPROC ||
1178 /proc/uptime can not be accessed. Usually, this is caused by
1179 procfs-security. Please read the FAQ for more details
1180 http://linux-vserver.org/Proc-Security"
1182 test -e "$cfgdir"/context || {
1183 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1184 test "$TYPE" != "static" || panic $"\
1185 The kernel does not have dynamic contexts enabled. Please configure
1186 a static one by executing
1188 echo [number between 2 and 49151] > $cfgdir/context"
1193 function _setSingleDiskLimit
1205 getFileValue ctx "$vdir/context"
1206 getFileValue directory "$dlimit/directory" || return 0
1207 getFileValue space_total "$dlimit/space_total" || return 0
1208 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1209 getFileValue reserved "$dlimit/reserved" || return 0
1211 local cachename=$ctx$directory
1212 cachename=dlimits/${cachename//\//_}
1214 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1215 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1216 $_RM -f "$vdir/cache/$cachename"
1218 if test -z "$inodes_used" -o -z "$space_used"; then
1220 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1221 inodes_used=${tmpvdu##* }
1222 space_used=${tmpvdu%% *}
1225 $_VDLIMIT --xid $ctx \
1226 --set space_used=$space_used \
1227 --set space_total=$space_total \
1228 --set inodes_used=$inodes_used \
1229 --set inodes_total=$inodes_total \
1230 --set reserved=$reserved \
1235 function setDiskLimits
1240 # Disk Limits without a static context are useless
1241 test -e "$vdir"/context || return 0
1243 for dlimit in "$vdir/dlimits/"*; do
1244 test -d "$dlimit" || continue
1245 test ! -e "$dlimit/disabled" || continue
1247 _setSingleDiskLimit "$vdir" "$dlimit"
1252 function _saveSingleDiskLimit
1259 getFileValue ctx "$vdir/context"
1260 getFileValue directory "$dlimit/directory" || return 0
1262 local cachename=$ctx$directory
1263 cachename=${cachename//\//_}
1265 # Things are getting ugly here... LFS says that /var/cache (where
1266 # cachename is usually pointing to) can vanish and applications
1267 # have to deal with it. So, we have to interprete the $vdir/cache
1268 # symlink and have to create the needed directories manually.
1269 if test -d "$vdir/cache"; then
1270 : # ok, exists already
1271 elif test -L "$vdir/cache"; then
1272 # it's a dangling symlink
1274 link=$($_READLINK "$vdir/cache")
1275 ( cd $vdir && $_MKDIR -p "$link" )
1280 test -d "$vdir/cache"
1281 $_MKDIR -p "$vdir"/cache/dlimits
1283 $_VDLIMIT --xid $ctx "$directory" | \
1284 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1286 $_VDLIMIT --xid $ctx --remove "$directory"
1290 function saveDiskLimits
1295 test -e "$vdir"/context || return 0
1297 for dlimit in "$vdir/dlimits/"*; do
1298 test -d "$dlimit" || continue
1299 test ! -e "$dlimit/disabled" || continue
1301 _saveSingleDiskLimit "$vdir" "$dlimit"
1305 function _namespaceCleanup
1308 local root=$($_VSERVER_INFO "$1" VDIR 1)
1314 getFileArray skip "$vdir"/namespace-cleanup-skip \
1315 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1317 # these are things that have to be accessible post-cleanup
1318 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1319 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1320 local real=`getPhysicalDir "$i"`
1321 test "$i" != "$real" || real=
1322 for j in "$i" "$real"; do
1323 while test -n "$j"; do
1324 list=( "${list[@]}" "$j" )
1330 local -a list_umount
1331 while read -r dev path opts; do
1332 test -n "$path" || continue
1333 for i in "$root" /dev /proc; do
1334 test "${path#$i}" != "$path" && continue 2
1336 for i in "${list[@]}" /; do
1337 test "$path" = "$i" && continue 2
1339 # unmount them in reverse order so mounts further down the tree get unmounted first
1340 list_umount=( "$path" "${list_umount[@]}" )
1342 # separate loop to avoid races while reading /proc/mounts
1343 for i in "${list_umount[@]}"; do
1348 function handleDeviceMap
1353 local flags device target
1355 test -d "$dir" || return 0
1356 test -n "$xid" || return 0
1358 for i in "$dir"/*; do
1359 test -d "$i" || continue
1361 local -a vdevmap_opts=()
1362 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1363 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1364 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1366 getFileValue flags "$i/flags" || :
1367 getFileValue device "$i/device" || :
1368 getFileValue target "$i/target" || :
1369 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1370 ${device:+--device "$device"} ${target:+--target "$target"} )
1372 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?