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
566 _getInterfaceValue ip '' "$iface"
567 _getInterfaceValue extip '' "$iface" "$iface/.."
568 _getInterfaceValue dev '' "$iface" "$iface/.."
569 _getInterfaceValue prefix '' "$iface" "$iface/.."
570 _getInterfaceValue mask '' "$iface" "$iface/.."
571 _getInterfaceValue bcast '' "$iface" "$iface/.."
572 _getInterfaceValue name '' "$iface"
573 _getInterfaceValue scope '' "$iface" "$iface/.."
574 _getInterfaceValue mac '' "$iface"
575 _getInterfaceValue peer '' "$iface"
577 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
578 test -n "$dev" -o -e "$iface"/nodev || {
579 echo $"No device specified for '$iface'" >&2
583 test ! -e "$iface"/down || up=
586 _transformMask2Prefix prefix "$prefix" "$mask"
587 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
589 test ! -e "$iface"/nodev || break
591 test ! -e "$iface"/only_ip || break
593 test -e "$iface/vlandev" \
594 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
595 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
596 -a ! -e "$iface/novlandev" \
597 -a ! -e "$iface/../novlandev" \) && {
599 if vlan_info=$(_getVLANInfo "$dev"); then
600 test -d /proc/net/vlan || {
601 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
604 _addInterfaceCmd VCONFIG $vlan_info
608 if ! test -e "$iface"/indirect; then
610 local use_bcast="broadcast ${bcast:-+}"
611 echo "$ip" | $_GREP -q : && use_bcast=
614 if tun_info=$(_getTunInfo "$iface"); then
615 _addInterfaceCmd TUNCTL "$dev" $tun_info
618 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
619 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
620 _addInterfaceCmd IP_LINK "$dev" $up
621 elif ! test -n "$N_CONTEXT"; then
622 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
625 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
626 _addInterfaceCmd MODPROBE dummy "$dev"
627 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
628 _addInterfaceCmd NAMEIF "$dev" "$mac"
629 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
630 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
637 ## Usage: _generateInterfaceOptions <vserver-directory>
638 function _generateInterfaceOptions
642 # XXX: This is here instead of in _generateChbindOptions
643 # to avoid a circular dependency
644 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
645 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
647 for iface in "$1/interfaces/"*; do
648 test -d "$iface" || continue
649 test ! -e "$iface"/disabled || continue
651 _processSingleInterface "$iface"
653 _HAVE_INTERFACE_OPTIONS=1
656 function enableInterfaces
661 lock "$__LOCKDIR"/vserver.interfaces
663 while test $i -lt $INTERFACE_CMDS_IDX; do
664 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
675 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
677 NAMEIF) $_NAMEIF "$@";;
678 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
679 $_VCONFIG add "$2" "$3" >/dev/null;;
680 IP_ADDR) $_IP addr add "$@";;
681 IP_ADDR_FLUSH) $_IP addr flush "$@";;
682 IP_LINK) $_IP link set "$@";;
683 IP_ROUTE) $_IP route add "$@";;
687 $_TUNCTL --persist "$@" "$dev"
689 *) echo "Unknown interface-command type '$type'" >&2; false;;
698 function disableInterfaces
700 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
702 local i=$INTERFACE_CMDS_IDX
705 lock "$__LOCKDIR"/vserver.interfaces
707 while test $i -gt 0; do
710 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
717 MODPROBE) $_RMMOD "${2:-$1}";;
719 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
720 IP_ADDR) $_IP addr del "$@";;
722 IP_LINK) ;; ## Ignore the link-down command for now
723 IP_ROUTE) $_IP route del "$@";;
724 TUNCTL) $_TUNCTL --~persist "$1";;
725 *) echo "Unknown interface-command type '$type'" >&2; false;;
732 function _generateTagOptions
737 getFileValue tag "$vdir/tag" "$vdir/context"
738 test -n "$tag" || return 0
740 OPTS_VTAG_CREATE=( --tag "$tag" )
741 OPTS_VTAG_ENTER=( --tag "$tag" )
744 function _generateMemctrlOptions
749 getFileValue badness "$vdir/badness"
750 test -n "$badness" || return 0
752 OPTS_VMEMCTRL=( --badness "$badness" )
755 function _generateSpaceOptions
758 local d="$vdir"/spaces
760 test ! -e "$d"/pid || \
761 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
763 test ! -e "$d"/net || {
764 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
765 # network context and namespace don't make much sense
766 _HAVE_CHBIND_OPTIONS=1
771 getFileValue mask "$d"/mask || \
772 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
775 ## Usage: prepareInit <vserver-directory>
778 pushd "$1/vdir" >/dev/null
781 { find var/run ! -type d -print0; \
782 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
785 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
786 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
791 "${INITCMD_PREPARE[@]}"
795 ## Usage: prepareInit <vserver-directory>
798 pushd "$1/vdir" >/dev/null
801 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
804 "${STOPCMD_PREPARE[@]}"
809 function generateOptions
811 _generateInterfaceOptions "$1"
812 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
813 _generateNiceCommand "$1"
814 _generateInitOptions "$1"
815 _generateChcontextOptions "$1"
816 _generateScheduleOptions "$1"
817 _generatePersonalityOptions "$1"
818 _generateTagOptions "$1"
819 _generateMemctrlOptions "$1"
820 _generateSpaceOptions "$1"
822 if test -n "$_IS_FAKEINIT"; then
823 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
824 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
832 local f="$vdir"/cpuset
836 test -d "$f" || return 0
837 test -e "$f"/name || return 0
839 read cpuset < "$f"/name
840 test -e "$f"/nocreate || {
841 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
842 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
843 if test -e "$f"/"$i"; then
844 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
852 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
853 if [ "$configured" -ne 0 ]; then
855 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
856 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
861 function removeCPUSET
865 local f="$vdir"/cpuset
867 test -d "$f" || return 0
868 test -e "$f"/name || return 0
870 read cpuset < "$f"/name
871 test -e "$f"/nocreate || {
872 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
876 function _mountVserverInternal
881 test -e "$fstab" || return 0
884 pushd "$vdir" >/dev/null
885 # check whether / is mounted readonly or whether there is special
886 # magic regarding the mtab file; when etc/mtab can not be touched,
887 # add the '-n' flag to mount
888 test -w etc -o -w etc/mtab || xflag=-n
889 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
897 local fstab="$cfgdir"/fstab
900 test -e "$fstab" || return 0
901 pushd "$vdir" >/dev/null
902 # check whether / is mounted readonly or whether there is special
903 # magic regarding the mtab file; when etc/mtab can not be touched,
904 # add the '-n' flag to mount
905 test -w etc -o -w etc/mtab || xflag=-n
906 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
910 function mountVserver
917 test -e "$cfgdir"/fstab -o \
918 -e "$cfgdir"/fstab.local -o \
919 -e "$cfgdir"/fstab.remote || return 0
921 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
923 pushd "$vdir" >/dev/null
924 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
927 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
929 _mountVserverInternal "$cfgdir"/fstab
930 _mountVserverInternal "$cfgdir"/fstab.local
931 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
933 isNamespaceCleanup "$cfgdir" && \
934 _namespaceCleanup "$cfgdir"
936 isAvoidNamespace "$cfgdir" || \
937 $_SECURE_MOUNT --rbind -n "$vdir" "/"
940 function _umountVserverInternal
943 test -e "$fstab" || return 0
948 while read src dst tmp; do
949 test -n "$tmp" || continue
955 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
961 function umountVserver
967 isAvoidNamespace "$cfgdir" || return 0
968 test -e "$cfgdir"/fstab -o \
969 -e "$cfgdir"/fstab.local -o \
970 -e "$cfgdir"/fstab.remote || return 0
971 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
973 pushd "$vdir/" >/dev/null || return 1
974 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
975 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
976 _umountVserverInternal "$cfgdir"/fstab || is_ok=
977 popd >/dev/null || return 1
985 local fstab="$cfgdir"/fstab
989 test -e "$fstab" || return 0
991 export FSTAB_FILE="$fstab"
994 test "$fsck_exitcode" -eq 0 -o \
995 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
998 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1002 test -n "$_NEED_VSHELPER_SYNC" && \
1003 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1005 vshelper.initSync "$1" "$3" "$_is_meth"
1008 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1011 if $_VSERVER_INFO - FEATURE vwait; then
1013 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1016 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1017 --status-fd 3 "$2" \
1018 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1021 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1022 $_VPS axf | $_EGREP -e "^[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1023 killContext "$S_CONTEXT" 9
1027 ) 4>$_is_tmpdir/procs &
1029 echo "$!" >$_is_tmpdir/pid
1030 eval "$3"=$_is_tmpdir
1035 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1036 function _waitForVWait
1041 declare -r procs=$(cat $4)
1043 getFileArray status "$2"
1048 'vwait' exited with error '$2' which indicates that vserver could not
1049 be stopped properly"
1052 (KILLED) warning $"\
1053 A timeout occured while waiting for the vserver to finish and it was
1054 killed by sending a SIGKILL signal. Please investigate the reasons
1055 and/or increase the timeout in apps/vshelper/sync-timeout."
1058 (TIMEOUT) warning $"\
1059 A timeout occured while waiting for the vserver to finish and it will
1060 be killed by sending a SIGKILL signal. The following process list
1061 might be useful for finding out the reason of this behavior:
1063 ----------------------------------------------------------------------
1065 }----------------------------------------------------------------------"
1068 (\?\?\?|*) warning $"\
1069 internal error: 'vwait' exited with an unexpected status '$1'; I will
1070 try to continue but be prepared for unexpected events."
1077 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1078 function waitForSync
1082 local vwait_statdir=$3
1085 if test -d "$vwait_statdir"; then
1086 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1087 elif test -n "$_NEED_VSHELPER_SYNC"; then
1088 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1090 A timeout or other error occured while waiting for the synchronization
1091 signal from vserver '$VSERVER_NAME'.
1092 The vserver will be killed nevertheless..."
1093 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1094 "${INITCMD_STOP_SYNC[@]}" || \
1096 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1097 will be killed nevertheless..."
1100 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1104 function _sourceWrap
1106 local vdir name flavor start i already_handled base
1110 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1111 function execScriptlets
1115 declare -r flavor=$3
1118 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1119 local DONT_SKIP_DEFAULTS=
1120 local already_handled=
1122 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1123 isRegularFile "$i" || continue
1124 test -r "$i" || continue
1128 test -x "$i" || start=_sourceWrap
1129 $start "$i" "$flavor" "$name"
1132 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1137 function sanityCheck
1139 declare -r cfgdir=$1
1141 ! test -e "$cfgdir"/fstab.local ||
1143 WARNING: 'fstab' will *not* be executed in the network context of the
1144 vserver anymore. Therefore, 'fstab.local' has the same functionality
1145 and is obsoleted. When you need the old behaviour, put the mounts
1146 into 'fstab.remote'"
1148 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1150 WARNING: The hostname is now configured in 'uts/nodename' but not in
1153 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1155 WARNING: The domainname is now configured in 'uts/domainname' but not
1156 in 'domainname'." >&2
1160 for i in "$cfgdir"/interfaces/*/only_ip; do
1161 if test -e "$i"; then
1163 iface=${i##$cfgdir/interfaces/}
1164 iface=${iface%%/only_ip}
1166 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1171 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1173 WARNING: There is no cachedirectory configured for this vserver;
1174 please create '$cfgdir/cache' e.g. by executing
1176 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1179 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1181 vshelper.doSanityCheck
1183 $_VSERVER_INFO - VERIFYCAP ||
1184 panic $"capabilities are not enabled in kernel-setup"
1186 $_VSERVER_INFO - VERIFYPROC ||
1188 /proc/uptime can not be accessed. Usually, this is caused by
1189 procfs-security. Please read the FAQ for more details
1190 http://linux-vserver.org/Proc-Security"
1192 test -e "$cfgdir"/context || {
1193 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1194 test "$TYPE" != "static" || panic $"\
1195 The kernel does not have dynamic contexts enabled. Please configure
1196 a static one by executing
1198 echo [number between 2 and 49151] > $cfgdir/context"
1203 function _setSingleDiskLimit
1215 getFileValue ctx "$vdir/context"
1216 getFileValue directory "$dlimit/directory" || return 0
1217 getFileValue space_total "$dlimit/space_total" || return 0
1218 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1219 getFileValue reserved "$dlimit/reserved" || return 0
1221 local cachename=$ctx$directory
1222 cachename=dlimits/${cachename//\//_}
1224 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1225 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1226 $_RM -f "$vdir/cache/$cachename"
1228 if test -z "$inodes_used" -o -z "$space_used"; then
1230 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1231 inodes_used=${tmpvdu##* }
1232 space_used=${tmpvdu%% *}
1235 $_VDLIMIT --xid $ctx \
1236 --set space_used=$space_used \
1237 --set space_total=$space_total \
1238 --set inodes_used=$inodes_used \
1239 --set inodes_total=$inodes_total \
1240 --set reserved=$reserved \
1245 function setDiskLimits
1250 # Disk Limits without a static context are useless
1251 test -e "$vdir"/context || return 0
1253 for dlimit in "$vdir/dlimits/"*; do
1254 test -d "$dlimit" || continue
1255 test ! -e "$dlimit/disabled" || continue
1257 _setSingleDiskLimit "$vdir" "$dlimit"
1262 function _saveSingleDiskLimit
1269 getFileValue ctx "$vdir/context"
1270 getFileValue directory "$dlimit/directory" || return 0
1272 local cachename=$ctx$directory
1273 cachename=${cachename//\//_}
1275 # Things are getting ugly here... LFS says that /var/cache (where
1276 # cachename is usually pointing to) can vanish and applications
1277 # have to deal with it. So, we have to interprete the $vdir/cache
1278 # symlink and have to create the needed directories manually.
1279 if test -d "$vdir/cache"; then
1280 : # ok, exists already
1281 elif test -L "$vdir/cache"; then
1282 # it's a dangling symlink
1284 link=$($_READLINK "$vdir/cache")
1285 ( cd $vdir && $_MKDIR -p "$link" )
1290 test -d "$vdir/cache"
1291 $_MKDIR -p "$vdir"/cache/dlimits
1293 $_VDLIMIT --xid $ctx "$directory" | \
1294 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1296 $_VDLIMIT --xid $ctx --remove "$directory"
1300 function saveDiskLimits
1305 test -e "$vdir"/context || return 0
1307 for dlimit in "$vdir/dlimits/"*; do
1308 test -d "$dlimit" || continue
1309 test ! -e "$dlimit/disabled" || continue
1311 _saveSingleDiskLimit "$vdir" "$dlimit"
1315 function _namespaceCleanup
1318 local root=$($_VSERVER_INFO "$1" VDIR 1)
1324 getFileArray skip "$vdir"/namespace-cleanup-skip \
1325 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1327 # these are things that have to be accessible post-cleanup
1328 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1329 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1330 local real=`getPhysicalDir "$i"`
1331 test "$i" != "$real" || real=
1332 for j in "$i" "$real"; do
1333 while test -n "$j"; do
1334 list=( "${list[@]}" "$j" )
1340 local -a list_umount
1341 while read -r dev path opts; do
1342 test -n "$path" || continue
1343 for i in "$root" /dev /proc; do
1344 test "${path#$i}" != "$path" && continue 2
1346 for i in "${list[@]}" /; do
1347 test "$path" = "$i" && continue 2
1349 # unmount them in reverse order so mounts further down the tree get unmounted first
1350 list_umount=( "$path" "${list_umount[@]}" )
1352 # separate loop to avoid races while reading /proc/mounts
1353 for i in "${list_umount[@]}"; do
1358 function handleDeviceMap
1363 local flags device target
1365 test -d "$dir" || return 0
1366 test -n "$xid" || return 0
1368 for i in "$dir"/*; do
1369 test -d "$i" || continue
1371 local -a vdevmap_opts=()
1372 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1373 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1374 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1376 getFileValue flags "$i/flags" || :
1377 getFileValue device "$i/device" || :
1378 getFileValue target "$i/target" || :
1379 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1380 ${device:+--device "$device"} ${target:+--target "$target"} )
1382 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?