1 # $Id: vserver.functions 2702 2008-03-11 10:07:26Z hollow $ --*- sh -*--
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 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
321 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
322 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
323 RC_WRAP=/lib/rc/sh/init-vserver.sh
325 panic "init-vserver.sh not found; aborting"
328 INITCMD_START=( env TERM=$TERM $RC_WRAP "$RUNLEVEL_START" )
329 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
330 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
334 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
337 if test x"$INITSTYLE" != xrescue; then
338 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
339 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
340 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
341 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
342 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
345 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
346 INITCMD_START_SYNC=()
351 if vshelper.isEnabled; then
352 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
358 function _generateFlagOptions
362 CHCONTEXT_FLAG_OPTS=()
364 test ! -e "$vdir"/flags || \
373 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
374 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
380 isAvoidNamespace "$vdir" || {
382 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
386 function _generateChcontextOptions
389 local ctx hostname domainname
394 read ctx <"$vdir"/context || :
396 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
397 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
400 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
402 _generateCapabilityOptions "$vdir"
403 _generateFlagOptions "$vdir"
405 CHCONTEXT_OPTS=( $SILENT_OPT \
406 "${CHCONTEXT_FLAG_OPTS[@]}" \
409 ${ctx:+--ctx "$ctx"} \
410 ${hostname:+--hostname "$hostname"} \
411 ${domainname:+--domainname "$domainname"} )
413 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
414 ${ctx:+--xid "$ctx"} )
415 ## put '--secure' at front so that it can be overridden
416 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
419 function _generateScheduleOptions
422 if test -d "$vdir"/sched; then
423 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
427 local f="$vdir"/schedule
428 test -e "$f" || return 0
430 local fill_rate interval tokens tokens_min tokens_max prio_bias
438 read prio_bias || prio_bias=
442 test -n "$prio_bias" || {
443 echo $"Bad content in '$f'; aborting..." >&2
447 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
448 --tokens "$tokens" --tokens_min "$tokens_min" \
449 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
452 function _getInterfaceValue
462 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
465 : ${_giv_tmp:=$_giv_dflt}
466 eval $_giv_val=\$_giv_tmp
469 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
470 function _transformMask2Prefix
474 test -n "$_tm2p_tmp" || {
475 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
482 function _addInterfaceCmd
484 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
485 let ++INTERFACE_CMDS_IDX
488 ## Usage: _generateMac <var> <iface> <ctx>
489 function _generateMac
492 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
496 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
499 function _getVLANInfo
504 creation of VLAN_PLUS_VID devices is not supported; please create them
505 before starting the vserver and use the 'nodev' flag then"
506 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
510 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
511 create them before starting the vserver and use the 'nodev' flag then"
512 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
514 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
515 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
526 test -e "$iface/tun" -o -e "$iface/tap" || return 1
527 test ! -e "$iface/tun" || echo --tun
528 test ! -e "$iface/tap" || echo --tap
529 test ! -e "$iface/nocsum" || echo --~checksum
530 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
531 if test -e "$iface/uid"; then
533 getFileValue uid "$iface/uid"
536 if test -e "$iface/gid"; then
538 getFileValue gid "$iface/gid"
541 if test -e "$iface/linktype"; then
543 getFileValue linktype "$iface/linktype"
544 echo --linktype "$linktype"
549 ## Usage: _processSingleInterface <interface-directory>
550 function _processSingleInterface
565 _getInterfaceValue ip '' "$iface"
566 _getInterfaceValue extip '' "$iface" "$iface/.."
567 _getInterfaceValue dev '' "$iface" "$iface/.."
568 _getInterfaceValue prefix '' "$iface" "$iface/.."
569 _getInterfaceValue mask '' "$iface" "$iface/.."
570 _getInterfaceValue bcast '' "$iface" "$iface/.."
571 _getInterfaceValue name '' "$iface"
572 _getInterfaceValue scope '' "$iface" "$iface/.."
573 _getInterfaceValue mac '' "$iface"
575 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
576 test -n "$dev" -o -e "$iface"/nodev || {
577 echo $"No device specified for '$iface'" >&2
581 test ! -e "$iface"/down || up=
584 _transformMask2Prefix prefix "$prefix" "$mask"
585 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
587 test ! -e "$iface"/nodev || break
589 test ! -e "$iface"/only_ip || break
591 test -e "$iface/vlandev" \
592 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
593 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
594 -a ! -e "$iface/novlandev" \
595 -a ! -e "$iface/../novlandev" \) && {
597 if vlan_info=$(_getVLANInfo "$dev"); then
598 test -d /proc/net/vlan || {
599 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
602 _addInterfaceCmd VCONFIG $vlan_info
606 if ! test -e "$iface"/indirect; then
608 local use_bcast="broadcast ${bcast:-+}"
609 echo "$ip" | $_GREP -q : && use_bcast=
612 if tun_info=$(_getTunInfo "$iface"); then
613 _addInterfaceCmd TUNCTL "$dev" $tun_info
616 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev"
617 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
618 _addInterfaceCmd IP_LINK "$dev" $up
619 elif ! test -n "$N_CONTEXT"; then
620 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
623 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
624 _addInterfaceCmd MODPROBE dummy "$dev"
625 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
626 _addInterfaceCmd NAMEIF "$dev" "$mac"
627 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
628 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
635 ## Usage: _generateInterfaceOptions <vserver-directory>
636 function _generateInterfaceOptions
640 # XXX: This is here instead of in _generateChbindOptions
641 # to avoid a circular dependency
642 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
643 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
645 for iface in "$1/interfaces/"*; do
646 test -d "$iface" || continue
647 test ! -e "$iface"/disabled || continue
649 _processSingleInterface "$iface"
651 _HAVE_INTERFACE_OPTIONS=1
654 function enableInterfaces
659 lock "$__LOCKDIR"/vserver.interfaces
661 while test $i -lt $INTERFACE_CMDS_IDX; do
662 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
673 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
675 NAMEIF) $_NAMEIF "$@";;
676 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
677 $_VCONFIG add "$2" "$3" >/dev/null;;
678 IP_ADDR) $_IP addr add "$@";;
679 IP_ADDR_FLUSH) $_IP addr flush "$@";;
680 IP_LINK) $_IP link set "$@";;
681 IP_ROUTE) $_IP route add "$@";;
685 $_TUNCTL --persist "$@" "$dev"
687 *) echo "Unknown interface-command type '$type'" >&2; false;;
696 function disableInterfaces
698 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
700 local i=$INTERFACE_CMDS_IDX
703 lock "$__LOCKDIR"/vserver.interfaces
705 while test $i -gt 0; do
708 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
715 MODPROBE) $_RMMOD "${2:-$1}";;
717 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
718 IP_ADDR) $_IP addr del "$@";;
720 IP_LINK) ;; ## Ignore the link-down command for now
721 IP_ROUTE) $_IP route del "$@";;
722 TUNCTL) $_TUNCTL --~persist "$1";;
723 *) echo "Unknown interface-command type '$type'" >&2; false;;
730 function _generateTagOptions
735 getFileValue tag "$vdir/tag" "$vdir/context"
736 test -n "$tag" || return 0
738 OPTS_VTAG_CREATE=( --tag "$tag" )
739 OPTS_VTAG_ENTER=( --tag "$tag" )
742 function _generateMemctrlOptions
747 getFileValue badness "$vdir/badness"
748 test -n "$badness" || return 0
750 OPTS_VMEMCTRL=( --badness "$badness" )
753 function _generateSpaceOptions
756 local d="$vdir"/spaces
758 test ! -e "$d"/pid || \
759 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
761 test ! -e "$d"/net || {
762 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
763 # network context and namespace don't make much sense
764 _HAVE_CHBIND_OPTIONS=1
769 getFileValue mask "$d"/mask || \
770 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
773 ## Usage: prepareInit <vserver-directory>
776 pushd "$1/vdir" >/dev/null
779 { find var/run ! -type d -print0; \
780 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
783 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
784 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
789 "${INITCMD_PREPARE[@]}"
793 ## Usage: prepareInit <vserver-directory>
796 pushd "$1/vdir" >/dev/null
799 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
802 "${STOPCMD_PREPARE[@]}"
807 function generateOptions
809 _generateInterfaceOptions "$1"
810 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
811 _generateNiceCommand "$1"
812 _generateInitOptions "$1"
813 _generateChcontextOptions "$1"
814 _generateScheduleOptions "$1"
815 _generatePersonalityOptions "$1"
816 _generateTagOptions "$1"
817 _generateMemctrlOptions "$1"
818 _generateSpaceOptions "$1"
820 if test -n "$_IS_FAKEINIT"; then
821 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
822 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
830 local f="$vdir"/cpuset
834 test -d "$f" || return 0
835 test -e "$f"/name || return 0
837 read cpuset < "$f"/name
838 test -e "$f"/nocreate || {
839 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
840 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
841 if test -e "$f"/"$i"; then
842 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
850 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
851 if [ "$configured" -ne 0 ]; then
853 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
854 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
859 function removeCPUSET
863 local f="$vdir"/cpuset
865 test -d "$f" || return 0
866 test -e "$f"/name || return 0
868 read cpuset < "$f"/name
869 test -e "$f"/nocreate || {
870 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
874 function _mountVserverInternal
879 test -e "$fstab" || return 0
882 pushd "$vdir" >/dev/null
883 # check whether / is mounted readonly or whether there is special
884 # magic regarding the mtab file; when etc/mtab can not be touched,
885 # add the '-n' flag to mount
886 test -w etc -o -w etc/mtab || xflag=-n
887 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
895 local fstab="$cfgdir"/fstab
898 test -e "$fstab" || return 0
899 pushd "$vdir" >/dev/null
900 # check whether / is mounted readonly or whether there is special
901 # magic regarding the mtab file; when etc/mtab can not be touched,
902 # add the '-n' flag to mount
903 test -w etc -o -w etc/mtab || xflag=-n
904 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
908 function mountVserver
915 test -e "$cfgdir"/fstab -o \
916 -e "$cfgdir"/fstab.local -o \
917 -e "$cfgdir"/fstab.remote || return 0
919 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
921 pushd "$vdir" >/dev/null
922 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
925 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
927 _mountVserverInternal "$cfgdir"/fstab
928 _mountVserverInternal "$cfgdir"/fstab.local
929 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
931 isNamespaceCleanup "$cfgdir" && \
932 _namespaceCleanup "$cfgdir"
934 isAvoidNamespace "$cfgdir" || \
935 $_SECURE_MOUNT --rbind -n "$vdir" "/"
938 function _umountVserverInternal
941 test -e "$fstab" || return 0
946 while read src dst tmp; do
947 test -n "$tmp" || continue
953 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
959 function umountVserver
965 isAvoidNamespace "$cfgdir" || return 0
966 test -e "$cfgdir"/fstab -o \
967 -e "$cfgdir"/fstab.local -o \
968 -e "$cfgdir"/fstab.remote || return 0
969 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
971 pushd "$vdir/" >/dev/null || return 1
972 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
973 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
974 _umountVserverInternal "$cfgdir"/fstab || is_ok=
975 popd >/dev/null || return 1
983 local fstab="$cfgdir"/fstab
987 test -e "$fstab" || return 0
989 export FSTAB_FILE="$fstab"
992 test "$fsck_exitcode" -eq 0 -o \
993 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
996 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1000 test -n "$_NEED_VSHELPER_SYNC" && \
1001 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1003 vshelper.initSync "$1" "$3" "$_is_meth"
1006 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1009 if $_VSERVER_INFO - FEATURE vwait; then
1011 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1014 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1015 --status-fd 3 "$2" \
1016 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1019 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1020 $_VPS axf | $_EGREP -e "^[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1021 killContext "$S_CONTEXT" 9
1025 ) 4>$_is_tmpdir/procs &
1027 echo "$!" >$_is_tmpdir/pid
1028 eval "$3"=$_is_tmpdir
1033 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1034 function _waitForVWait
1039 declare -r procs=$(cat $4)
1041 getFileArray status "$2"
1046 'vwait' exited with error '$2' which indicates that vserver could not
1047 be stopped properly"
1050 (KILLED) warning $"\
1051 A timeout occured while waiting for the vserver to finish and it was
1052 killed by sending a SIGKILL signal. Please investigate the reasons
1053 and/or increase the timeout in apps/vshelper/sync-timeout."
1056 (TIMEOUT) warning $"\
1057 A timeout occured while waiting for the vserver to finish and it will
1058 be killed by sending a SIGKILL signal. The following process list
1059 might be useful for finding out the reason of this behavior:
1061 ----------------------------------------------------------------------
1063 }----------------------------------------------------------------------"
1066 (\?\?\?|*) warning $"\
1067 internal error: 'vwait' exited with an unexpected status '$1'; I will
1068 try to continue but be prepared for unexpected events."
1075 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1076 function waitForSync
1080 local vwait_statdir=$3
1083 if test -d "$vwait_statdir"; then
1084 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1085 elif test -n "$_NEED_VSHELPER_SYNC"; then
1086 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1088 A timeout or other error occured while waiting for the synchronization
1089 signal from vserver '$VSERVER_NAME'.
1090 The vserver will be killed nevertheless..."
1091 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1092 "${INITCMD_STOP_SYNC[@]}" || \
1094 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1095 will be killed nevertheless..."
1098 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1102 function _sourceWrap
1104 local vdir name flavor start i already_handled base
1108 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1109 function execScriptlets
1113 declare -r flavor=$3
1116 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1117 local DONT_SKIP_DEFAULTS=
1118 local already_handled=
1120 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1121 isRegularFile "$i" || continue
1122 test -r "$i" || continue
1126 test -x "$i" || start=_sourceWrap
1127 $start "$i" "$flavor" "$name"
1130 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1135 function sanityCheck
1137 declare -r cfgdir=$1
1139 ! test -e "$cfgdir"/fstab.local ||
1141 WARNING: 'fstab' will *not* be executed in the network context of the
1142 vserver anymore. Therefore, 'fstab.local' has the same functionality
1143 and is obsoleted. When you need the old behaviour, put the mounts
1144 into 'fstab.remote'"
1146 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1148 WARNING: The hostname is now configured in 'uts/nodename' but not in
1151 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1153 WARNING: The domainname is now configured in 'uts/domainname' but not
1154 in 'domainname'." >&2
1158 for i in "$cfgdir"/interfaces/*/only_ip; do
1159 if test -e "$i"; then
1161 iface=${i##$cfgdir/interfaces/}
1162 iface=${iface%%/only_ip}
1164 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1169 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1171 WARNING: There is no cachedirectory configured for this vserver;
1172 please create '$cfgdir/cache' e.g. by executing
1174 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1177 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1179 vshelper.doSanityCheck
1181 $_VSERVER_INFO - VERIFYCAP ||
1182 panic $"capabilities are not enabled in kernel-setup"
1184 $_VSERVER_INFO - VERIFYPROC ||
1186 /proc/uptime can not be accessed. Usually, this is caused by
1187 procfs-security. Please read the FAQ for more details
1188 http://linux-vserver.org/Proc-Security"
1190 test -e "$cfgdir"/context || {
1191 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1192 test "$TYPE" != "static" || panic $"\
1193 The kernel does not have dynamic contexts enabled. Please configure
1194 a static one by executing
1196 echo [number between 2 and 49151] > $cfgdir/context"
1201 function _setSingleDiskLimit
1213 getFileValue ctx "$vdir/context"
1214 getFileValue directory "$dlimit/directory" || return 0
1215 getFileValue space_total "$dlimit/space_total" || return 0
1216 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1217 getFileValue reserved "$dlimit/reserved" || return 0
1219 local cachename=$ctx$directory
1220 cachename=dlimits/${cachename//\//_}
1222 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1223 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1224 $_RM -f "$vdir/cache/$cachename"
1226 if test -z "$inodes_used" -o -z "$space_used"; then
1228 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1229 inodes_used=${tmpvdu##* }
1230 space_used=${tmpvdu%% *}
1233 $_VDLIMIT --xid $ctx \
1234 --set space_used=$space_used \
1235 --set space_total=$space_total \
1236 --set inodes_used=$inodes_used \
1237 --set inodes_total=$inodes_total \
1238 --set reserved=$reserved \
1243 function setDiskLimits
1248 # Disk Limits without a static context are useless
1249 test -e "$vdir"/context || return 0
1251 for dlimit in "$vdir/dlimits/"*; do
1252 test -d "$dlimit" || continue
1253 test ! -e "$dlimit/disabled" || continue
1255 _setSingleDiskLimit "$vdir" "$dlimit"
1260 function _saveSingleDiskLimit
1267 getFileValue ctx "$vdir/context"
1268 getFileValue directory "$dlimit/directory" || return 0
1270 local cachename=$ctx$directory
1271 cachename=${cachename//\//_}
1273 # Things are getting ugly here... LFS says that /var/cache (where
1274 # cachename is usually pointing to) can vanish and applications
1275 # have to deal with it. So, we have to interprete the $vdir/cache
1276 # symlink and have to create the needed directories manually.
1277 if test -d "$vdir/cache"; then
1278 : # ok, exists already
1279 elif test -L "$vdir/cache"; then
1280 # it's a dangling symlink
1282 link=$($_READLINK "$vdir/cache")
1283 ( cd $vdir && $_MKDIR -p "$link" )
1288 test -d "$vdir/cache"
1289 $_MKDIR -p "$vdir"/cache/dlimits
1291 $_VDLIMIT --xid $ctx "$directory" | \
1292 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1294 $_VDLIMIT --xid $ctx --remove "$directory"
1298 function saveDiskLimits
1303 test -e "$vdir"/context || return 0
1305 for dlimit in "$vdir/dlimits/"*; do
1306 test -d "$dlimit" || continue
1307 test ! -e "$dlimit/disabled" || continue
1309 _saveSingleDiskLimit "$vdir" "$dlimit"
1313 function _namespaceCleanup
1316 local root=$($_VSERVER_INFO "$1" VDIR 1)
1322 getFileArray skip "$vdir"/namespace-cleanup-skip \
1323 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1325 # these are things that have to be accessible post-cleanup
1326 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1327 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1328 local real=`getPhysicalDir "$i"`
1329 test "$i" != "$real" || real=
1330 for j in "$i" "$real"; do
1331 while test -n "$j"; do
1332 list=( "${list[@]}" "$j" )
1338 local -a list_umount
1339 while read -r dev path opts; do
1340 test -n "$path" || continue
1341 for i in "$root" /dev /proc; do
1342 test "${path#$i}" != "$path" && continue 2
1344 for i in "${list[@]}" /; do
1345 test "$path" = "$i" && continue 2
1347 # unmount them in reverse order so mounts further down the tree get unmounted first
1348 list_umount=( "$path" "${list_umount[@]}" )
1350 # separate loop to avoid races while reading /proc/mounts
1351 for i in "${list_umount[@]}"; do
1356 function handleDeviceMap
1361 local flags device target
1363 test -d "$dir" || return 0
1364 test -n "$xid" || return 0
1366 for i in "$dir"/*; do
1367 test -d "$i" || continue
1369 local -a vdevmap_opts=()
1370 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1371 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1372 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1374 getFileValue flags "$i/flags" || :
1375 getFileValue device "$i/device" || :
1376 getFileValue target "$i/target" || :
1377 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1378 ${device:+--device "$device"} ${target:+--target "$target"} )
1380 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?