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 IONICE_CMD=()
24 declare -a CHBIND_CMD=()
25 declare -a CAP_OPTS=()
26 declare -a CHCONTEXT_INIT_OPTS=()
27 declare -a CHCONTEXT_FLAG_OPTS=()
28 declare -a CHCONTEXT_OPTS=()
29 declare -a CAPCHROOT_OPTS=()
30 declare -a INTERFACES=()
32 declare -a INITCMD_RESCUE=( /bin/sleep 900 )
33 declare -a INITCMD_START=()
34 declare -a INITCMD_START_SYNC=()
35 declare -a INITCMD_STOP=()
36 declare -a INITCMD_STOP_SYNC=()
37 declare -a INITCMD_PREPARE=()
38 declare -a INITKILL_SEQ=()
39 declare -a ENTER_SHELL=()
41 declare -a OPTS_VCONTEXT_CREATE=()
42 declare -a OPTS_VCONTEXT_MIGRATE=()
43 declare -a OPTS_VCONTEXT_ENTER=()
44 OPT_VCONTEXT_CHROOT=--chroot
45 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
46 declare -a OPTS_VSCHED=()
47 declare -a OPTS_ENV=()
48 declare -a OPTS_VTAG_CREATE=()
49 declare -a OPTS_VTAG_ENTER=()
50 declare -a OPTS_VMEMCTRL=()
51 declare -a OPTS_VSPACE=( --default )
52 declare -a OPTS_VSPACE_SHARED=()
53 declare -a VSPACE_SHARED_CMD=()
55 declare -a STOPCMD_PREPARE=()
57 declare -a VSERVER_EXTRA_CMDS=()
60 VSHELPER_SYNC_TIMEOUT=30
65 _HAVE_INTERFACE_OPTIONS=
77 CGROUP_MNT=/dev/cgroup
78 declare -a CGROUP_SUBSYS=()
79 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
83 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
85 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
91 function _readFileToArray
98 test -e "$_rfta_f" || return 0
99 while read _rfta_v; do
102 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
107 function _generateChbindOptions
115 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
117 if test -e "$vdir"/noncontext -o \
118 \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
119 _HAVE_CHBIND_OPTIONS=1
123 local f="$vdir"/interfaces/bcast
124 getFileValue bcast "$f"
125 f="$vdir"/interfaces/lback
126 getFileValue lback "$f"
128 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
129 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
132 for i in "${INTERFACES[@]}"; do
133 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
136 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
137 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
139 _HAVE_CHBIND_OPTIONS=1
142 function _generateNiceCommand
146 local current_nice=`$_NICE`
148 test -r "$vdir/nice" && read nice <"$vdir"/nice
150 let nice=$nice-$current_nice || :
151 NICE_CMD=( $_NICE -n $nice )
154 function _generateIONiceCommand
158 local ionice_priority=0
160 test -n "$_IONICE" || return 0
162 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
163 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
165 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
168 function _generatePersonalityOptions
171 local f="$vdir"/personality
174 test -s "$f" || return 0
183 (*) flags=$flags$delim$tmp
190 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
191 --personality-type "$type"
192 ${flags:+--personality-flags "$flags"} )
195 function _generateCCapabilityOptions
199 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
202 function _generateBCapabilityOptions
206 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
209 function _generateUMaskOptions
213 _readFileToArray "$vdir"/umask OPTS_VATTRIBUTE --umask
216 function _generateCapabilityOptions
221 _generateBCapabilityOptions "$vdir"
222 _generateCCapabilityOptions "$vdir"
224 test -e "$vdir"/capabilities || return 0
233 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
234 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
237 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
240 done <"$vdir"/capabilities
243 function getEnterShell
250 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
252 test -n "$ENTER_SHELL" || {
254 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
256 test -x "$vdir/vdir/$1" || continue
263 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
264 function sendKillSequence
270 while isCtxRunning "$ctx"; do
271 test -z "$wait" || sleep "$wait"
273 killContext "$ctx" "$1"
274 test -n "$2" || break
280 function _generateInitOptions
283 local cfgdir=$vdir/apps/init
288 INITCMD_START_SYNC=()
293 INITKILL_SEQ=( 15 5 9 )
294 CHCONTEXT_INIT_OPTS=()
297 test x"$INITSTYLE" = xrescue || \
298 getFileValue INITSTYLE "$cfgdir"/style
299 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
300 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
301 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
302 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
304 findFile _gio_env "$cfgdir"/environment \
305 "$__CONFDIR"/.defaults/apps/init/environment \
306 "$__PKGLIBDEFAULTDIR"/environment
307 getFileArray OPTS_ENV "$_gio_env" || :
309 case x"$INITSTYLE" in
311 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
312 INITCMD_STOP=( /sbin/killall5 )
316 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
317 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
319 for i in /etc/init.d/rc /etc/rc.d/rc; do
320 test -x "$vdir/vdir/$i" || continue
321 INITCMD_START=( "$i" "$RUNLEVEL_START" )
322 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
324 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
325 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
326 if test -n "$OPTION_DEBUG_SYSV"; then
327 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
328 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
333 INITCMD_START=( /sbin/init )
334 INITCMD_STOP=( /sbin/init )
336 _NEED_VSHELPER_SYNC=1
337 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
338 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
342 INITCMD_START=( /sbin/minit-start )
343 INITCMD_STOP=( /sbin/minit-stop )
345 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
346 _NEED_VSHELPER_SYNC=1
347 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
348 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
349 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
353 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
354 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
356 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
357 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
358 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
359 RC_WRAP=/lib/rc/sh/init-vserver.sh
361 panic "init-vserver.sh not found; aborting"
364 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
365 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
366 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
367 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
371 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
372 INITCMD_START=( /etc/rc.multi )
373 INITCMD_STOP=( /etc/rc.shutdown )
374 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
378 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
381 if test x"$INITSTYLE" != xrescue; then
382 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
383 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
384 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
385 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
386 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
389 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
390 INITCMD_START_SYNC=()
395 if vshelper.isEnabled; then
396 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
402 function _generateFlagOptions
407 CHCONTEXT_FLAG_OPTS=()
409 findFile file "$vdir"/cflags "$vdir"/flags ""
419 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
420 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
426 isAvoidNamespace "$vdir" || {
428 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
429 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
430 OPT_VCONTEXT_CHROOT=--pivot-root
434 function _generateChcontextOptions
437 local ctx hostname domainname
442 read ctx <"$vdir"/context || :
444 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
445 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
448 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
450 _generateCapabilityOptions "$vdir"
451 _generateFlagOptions "$vdir"
452 _generateUMaskOptions "$vdir"
454 CHCONTEXT_OPTS=( $SILENT_OPT \
455 "${CHCONTEXT_FLAG_OPTS[@]}" \
458 ${ctx:+--ctx "$ctx"} \
459 ${hostname:+--hostname "$hostname"} \
460 ${domainname:+--domainname "$domainname"} )
462 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
463 ${ctx:+--xid "$ctx"} )
464 ## put '--secure' at front so that it can be overridden
465 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
468 function _generateScheduleOptions
471 if test -d "$vdir"/sched; then
472 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
476 local f="$vdir"/schedule
477 test -e "$f" || return 0
479 local fill_rate interval tokens tokens_min tokens_max prio_bias
487 read prio_bias || prio_bias=
491 test -n "$prio_bias" || {
492 echo $"Bad content in '$f'; aborting..." >&2
496 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
497 --tokens "$tokens" --tokens_min "$tokens_min" \
498 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
501 function _getInterfaceValue
511 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
514 : ${_giv_tmp:=$_giv_dflt}
515 eval $_giv_val=\$_giv_tmp
518 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
519 function _transformMask2Prefix
523 test -n "$_tm2p_tmp" || {
524 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
531 function _addInterfaceCmd
533 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
534 let ++INTERFACE_CMDS_IDX
537 ## Usage: _generateMac <var> <iface> <ctx>
538 function _generateMac
541 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
545 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
548 function _getVLANInfo
553 creation of VLAN_PLUS_VID devices is not supported; please create them
554 before starting the vserver and use the 'nodev' flag then"
555 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
559 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
560 create them before starting the vserver and use the 'nodev' flag then"
561 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
563 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
564 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
575 test -e "$iface/tun" -o -e "$iface/tap" || return 1
576 test ! -e "$iface/tun" || echo --tun
577 test ! -e "$iface/tap" || echo --tap
578 test ! -e "$iface/nocsum" || echo --~checksum
579 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
580 if test -e "$iface/uid"; then
582 getFileValue uid "$iface/uid"
585 if test -e "$iface/gid"; then
587 getFileValue gid "$iface/gid"
590 if test -e "$iface/linktype"; then
592 getFileValue linktype "$iface/linktype"
593 echo --linktype "$linktype"
598 ## Usage: _processSingleInterface <interface-directory>
599 function _processSingleInterface
615 _getInterfaceValue ip '' "$iface"
616 _getInterfaceValue extip '' "$iface" "$iface/.."
617 _getInterfaceValue dev '' "$iface" "$iface/.."
618 _getInterfaceValue prefix '' "$iface" "$iface/.."
619 _getInterfaceValue mask '' "$iface" "$iface/.."
620 _getInterfaceValue bcast '' "$iface" "$iface/.."
621 _getInterfaceValue name '' "$iface"
622 _getInterfaceValue scope '' "$iface" "$iface/.."
623 _getInterfaceValue mac '' "$iface"
624 _getInterfaceValue peer '' "$iface"
626 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
627 test -n "$dev" -o -e "$iface"/nodev || {
628 echo $"No device specified for '$iface'" >&2
632 test ! -e "$iface"/down || up=
635 _transformMask2Prefix prefix "$prefix" "$mask"
636 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
638 test ! -e "$iface"/nodev || break
640 test ! -e "$iface"/only_ip || break
642 test -e "$iface/vlandev" \
643 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
644 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
645 -a ! -e "$iface/novlandev" \
646 -a ! -e "$iface/../novlandev" \) && {
648 if vlan_info=$(_getVLANInfo "$dev"); then
649 test -d /proc/net/vlan || {
650 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
653 _addInterfaceCmd VCONFIG $vlan_info
657 if ! test -e "$iface"/indirect; then
659 local use_bcast="broadcast ${bcast:-+}"
660 echo "$ip" | $_GREP -q : && use_bcast=
663 if tun_info=$(_getTunInfo "$iface"); then
664 _addInterfaceCmd TUNCTL "$dev" $tun_info
667 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
668 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
669 _addInterfaceCmd IP_LINK "$dev" $up
670 elif ! test -n "$N_CONTEXT"; then
671 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
674 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
675 _addInterfaceCmd MODPROBE dummy "$dev"
676 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
677 _addInterfaceCmd NAMEIF "$dev" "$mac"
678 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
679 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
686 ## Usage: _generateInterfaceOptions <vserver-directory>
687 function _generateInterfaceOptions
691 # XXX: This is here instead of in _generateChbindOptions
692 # to avoid a circular dependency
693 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
694 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
696 for iface in "$1/interfaces/"*; do
697 test -d "$iface" || continue
698 test ! -e "$iface"/disabled || continue
700 _processSingleInterface "$iface"
702 _HAVE_INTERFACE_OPTIONS=1
705 function enableInterfaces
710 lock "$__LOCKDIR"/vserver.interfaces
712 while test $i -lt $INTERFACE_CMDS_IDX; do
713 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
724 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
726 NAMEIF) $_NAMEIF "$@";;
727 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
728 $_VCONFIG add "$2" "$3" >/dev/null;;
729 IP_ADDR) $_IP addr add "$@";;
730 IP_ADDR_FLUSH) $_IP addr flush "$@";;
731 IP_LINK) $_IP link set "$@";;
732 IP_ROUTE) $_IP route add "$@";;
736 $_TUNCTL --persist "$@" "$dev"
738 *) echo "Unknown interface-command type '$type'" >&2; false;;
747 function disableInterfaces
749 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
751 local i=$INTERFACE_CMDS_IDX
754 lock "$__LOCKDIR"/vserver.interfaces
756 while test $i -gt 0; do
759 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
766 MODPROBE) $_RMMOD "${2:-$1}";;
768 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
769 IP_ADDR) $_IP addr del "$@";;
771 IP_LINK) ;; ## Ignore the link-down command for now
772 IP_ROUTE) $_IP route del "$@";;
776 $_TUNCTL --~persist "$@" "$dev"
778 *) echo "Unknown interface-command type '$type'" >&2; false;;
785 function _generateTagOptions
790 getFileValue tag "$vdir/tag" "$vdir/context"
791 test -n "$tag" || return 0
793 OPTS_VTAG_CREATE=( --tag "$tag" )
794 OPTS_VTAG_ENTER=( --tag "$tag" )
797 function _generateMemctrlOptions
802 getFileValue badness "$vdir/badness"
803 test -n "$badness" || return 0
805 OPTS_VMEMCTRL=( --badness "$badness" )
808 function _generateSpaceOptions
811 local d="$vdir"/spaces
815 for space in pid net; do
816 if test -e "$d"/$space; then
817 getFileValue shared "$d"/$space || shared=""
818 if test -z "$shared"; then
819 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
820 elif test "$shared" = "0"; then
823 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
824 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
830 getFileValue mask "$d"/mask || \
831 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
834 ## Usage: prepareInit <vserver-directory>
837 pushd "$1/vdir" >/dev/null
840 { $_FIND var/run ! -type d -print0; \
841 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
844 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
845 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
850 "${INITCMD_PREPARE[@]}"
854 ## Usage: prepareInit <vserver-directory>
857 pushd "$1/vdir" >/dev/null
860 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
863 "${STOPCMD_PREPARE[@]}"
868 function generateOptions
870 _generateInterfaceOptions "$1"
871 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
872 _generateNiceCommand "$1"
873 _generateIONiceCommand "$1"
874 _generateInitOptions "$1"
875 _generateChcontextOptions "$1"
876 _generateScheduleOptions "$1"
877 _generatePersonalityOptions "$1"
878 _generateTagOptions "$1"
879 _generateMemctrlOptions "$1"
880 _generateSpaceOptions "$1"
881 _generateCgroupOptions
883 if test -n "$_IS_FAKEINIT"; then
884 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
885 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
893 local f="$vdir"/cpuset
897 test -d "$f" || return 0
898 test -e "$f"/name || return 0
900 read cpuset < "$f"/name
901 test -e "$f"/nocreate || {
902 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
903 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
904 if test -e "$f"/"$i"; then
905 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
913 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
914 if [ "$configured" -ne 0 ]; then
916 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
917 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
922 function removeCPUSET
926 local f="$vdir"/cpuset
928 test -d "$f" || return 0
929 test -e "$f"/name || return 0
931 read cpuset < "$f"/name
932 test -e "$f"/nocreate || {
933 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
937 function _mountVserverInternal
942 test -e "$fstab" || return 0
945 pushd "$vdir" >/dev/null
946 # check whether / is mounted readonly or whether there is special
947 # magic regarding the mtab file; when etc/mtab can not be touched,
948 # add the '-n' flag to mount
949 test -w etc -o -w etc/mtab || xflag=-n
950 if test -h etc/mtab; then
951 local l=$($_READLINK etc/mtab)
952 test "${l##/proc/}" = "$l" || xflag=-n
954 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
962 local fstab="$cfgdir"/fstab
965 test -e "$fstab" || return 0
966 pushd "$vdir" >/dev/null
967 # check whether / is mounted readonly or whether there is special
968 # magic regarding the mtab file; when etc/mtab can not be touched,
969 # add the '-n' flag to mount
970 test -w etc -o -w etc/mtab || xflag=-n
971 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
975 function mountVserver
984 test -e "$cfgdir"/fstab -o \
985 -e "$cfgdir"/fstab.local -o \
986 -e "$cfgdir"/fstab.remote || return 0
988 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
990 pushd "$vdir" >/dev/null
991 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
994 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
996 _mountVserverInternal "$cfgdir"/fstab
997 _mountVserverInternal "$cfgdir"/fstab.local
998 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
1000 isNamespaceCleanup "$cfgdir" && \
1001 _namespaceCleanup "$cfgdir"
1003 real_vdir=$(getPhysicalDir "$vdir")
1004 isAvoidNamespace "$cfgdir" || \
1005 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
1006 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
1007 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
1010 function _umountVserverInternal
1013 test -e "$fstab" || return 0
1018 while read src dst tmp; do
1019 test -n "$tmp" || continue
1025 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1031 function umountVserver
1037 isAvoidNamespace "$cfgdir" || return 0
1038 test -e "$cfgdir"/fstab -o \
1039 -e "$cfgdir"/fstab.local -o \
1040 -e "$cfgdir"/fstab.remote || return 0
1041 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1043 pushd "$vdir/" >/dev/null || return 1
1044 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1045 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1046 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1047 popd >/dev/null || return 1
1055 local fstab="$cfgdir"/fstab
1059 test -e "$fstab" || return 0
1061 export FSTAB_FILE="$fstab"
1064 test "$fsck_exitcode" -eq 0 -o \
1065 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1068 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1072 test -n "$_NEED_VSHELPER_SYNC" && \
1073 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1075 vshelper.initSync "$1" "$3" "$_is_meth"
1078 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1081 if $_VSERVER_INFO - FEATURE vwait; then
1083 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1086 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1087 --status-fd 3 "$2" \
1088 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1091 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1092 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1093 killContext "$S_CONTEXT" 9
1097 ) 4>$_is_tmpdir/procs &
1099 echo "$!" >$_is_tmpdir/pid
1100 eval "$3"=$_is_tmpdir
1105 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1106 function _waitForVWait
1111 declare -r procs=$(cat $4)
1113 getFileArray status "$2"
1118 'vwait' exited with error '$2' which indicates that vserver could not
1119 be stopped properly"
1122 (KILLED) warning $"\
1123 A timeout occured while waiting for the vserver to finish and it was
1124 killed by sending a SIGKILL signal. Please investigate the reasons
1125 and/or increase the timeout in apps/vshelper/sync-timeout."
1128 (TIMEOUT) warning $"\
1129 A timeout occured while waiting for the vserver to finish and it will
1130 be killed by sending a SIGKILL signal. The following process list
1131 might be useful for finding out the reason of this behavior:
1133 ----------------------------------------------------------------------
1135 }----------------------------------------------------------------------"
1138 (\?\?\?|*) warning $"\
1139 internal error: 'vwait' exited with an unexpected status '$1'; I will
1140 try to continue but be prepared for unexpected events."
1147 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1148 function waitForSync
1152 local vwait_statdir=$3
1155 if test -d "$vwait_statdir"; then
1156 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1157 elif test -n "$_NEED_VSHELPER_SYNC"; then
1158 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1160 A timeout or other error occured while waiting for the synchronization
1161 signal from vserver '$VSERVER_NAME'.
1162 The vserver will be killed nevertheless..."
1163 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1164 "${INITCMD_STOP_SYNC[@]}" || \
1166 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1167 will be killed nevertheless..."
1170 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1174 function _sourceWrap
1176 local vdir name flavor start i already_handled base
1180 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1181 function execScriptlets
1185 declare -r flavor=$3
1188 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1189 local DONT_SKIP_DEFAULTS=
1190 local already_handled=
1192 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1193 isRegularFile "$i" || continue
1194 test -r "$i" || continue
1198 test -x "$i" || start=_sourceWrap
1199 $start "$i" "$flavor" "$name"
1202 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1207 function sanityCheck
1209 declare -r cfgdir=$1
1211 ! test -e "$cfgdir"/fstab.local ||
1213 WARNING: 'fstab' will *not* be executed in the network context of the
1214 vserver anymore. Therefore, 'fstab.local' has the same functionality
1215 and is obsoleted. When you need the old behaviour, put the mounts
1216 into 'fstab.remote'"
1218 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1220 WARNING: The hostname is now configured in 'uts/nodename' but not in
1223 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1225 WARNING: The domainname is now configured in 'uts/domainname' but not
1226 in 'domainname'." >&2
1230 for i in "$cfgdir"/interfaces/*/only_ip; do
1231 if test -e "$i"; then
1233 iface=${i##$cfgdir/interfaces/}
1234 iface=${iface%%/only_ip}
1236 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1241 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1243 WARNING: There is no cachedirectory configured for this vserver;
1244 please create '$cfgdir/cache' e.g. by executing
1246 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1249 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1251 vshelper.doSanityCheck
1253 $_VSERVER_INFO - VERIFYCAP ||
1254 panic $"capabilities are not enabled in kernel-setup"
1256 $_VSERVER_INFO - VERIFYPROC ||
1258 /proc/uptime can not be accessed. Usually, this is caused by
1259 procfs-security. Please read the FAQ for more details
1260 http://linux-vserver.org/Proc-Security"
1262 test -e "$cfgdir"/context || {
1263 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1264 test "$TYPE" != "static" || panic $"\
1265 The kernel does not have dynamic contexts enabled. Please configure
1266 a static one by executing
1268 echo [number between 2 and 49151] > $cfgdir/context"
1273 function _setSingleDiskLimit
1285 getFileValue ctx "$vdir/context"
1286 getFileValue directory "$dlimit/directory" || return 0
1287 getFileValue space_total "$dlimit/space_total" || return 0
1288 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1289 getFileValue reserved "$dlimit/reserved" || return 0
1291 local cachename=$ctx$directory
1292 cachename=dlimits/${cachename//\//_}
1294 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1295 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1296 $_RM -f "$vdir/cache/$cachename"
1298 if test -z "$inodes_used" -o -z "$space_used"; then
1300 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1301 inodes_used=${tmpvdu##* }
1302 space_used=${tmpvdu%% *}
1305 $_VDLIMIT --xid $ctx \
1306 --set space_used=$space_used \
1307 --set space_total=$space_total \
1308 --set inodes_used=$inodes_used \
1309 --set inodes_total=$inodes_total \
1310 --set reserved=$reserved \
1315 function setDiskLimits
1320 # Disk Limits without a static context are useless
1321 test -e "$vdir"/context || return 0
1323 for dlimit in "$vdir/dlimits/"*; do
1324 test -d "$dlimit" || continue
1325 test ! -e "$dlimit/disabled" || continue
1327 _setSingleDiskLimit "$vdir" "$dlimit"
1332 function _saveSingleDiskLimit
1339 getFileValue ctx "$vdir/context"
1340 getFileValue directory "$dlimit/directory" || return 0
1342 local cachename=$ctx$directory
1343 cachename=${cachename//\//_}
1345 # Things are getting ugly here... LFS says that /var/cache (where
1346 # cachename is usually pointing to) can vanish and applications
1347 # have to deal with it. So, we have to interprete the $vdir/cache
1348 # symlink and have to create the needed directories manually.
1349 if test -d "$vdir/cache"; then
1350 : # ok, exists already
1351 elif test -L "$vdir/cache"; then
1352 # it's a dangling symlink
1354 link=$($_READLINK "$vdir/cache")
1355 ( cd $vdir && $_MKDIR -p "$link" )
1360 test -d "$vdir/cache"
1361 $_MKDIR -p "$vdir"/cache/dlimits
1363 $_VDLIMIT --xid $ctx "$directory" | \
1364 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1366 $_VDLIMIT --xid $ctx --remove "$directory"
1370 function saveDiskLimits
1375 test -e "$vdir"/context || return 0
1377 for dlimit in "$vdir/dlimits/"*; do
1378 test -d "$dlimit" || continue
1379 test ! -e "$dlimit/disabled" || continue
1381 _saveSingleDiskLimit "$vdir" "$dlimit"
1385 function _namespaceCleanup
1388 local root=$($_VSERVER_INFO "$1" VDIR 1)
1394 getFileArray skip "$vdir"/namespace-cleanup-skip \
1395 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1397 # these are things that have to be accessible post-cleanup
1398 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1399 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1400 local real=`getPhysicalDir "$i"`
1401 test "$i" != "$real" || real=
1402 for j in "$i" "$real"; do
1403 while test -n "$j"; do
1404 list=( "${list[@]}" "$j" )
1410 local -a list_umount
1411 while read -r dev path opts; do
1412 test -n "$path" || continue
1413 for i in "$root" /dev /proc; do
1415 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1417 for i in "${list[@]}" /; do
1418 test "$path" = "$i" && continue 2
1420 # unmount them in reverse order so mounts further down the tree get unmounted first
1421 list_umount=( "$path" "${list_umount[@]}" )
1423 # separate loop to avoid races while reading /proc/mounts
1424 for i in "${list_umount[@]}"; do
1425 $_UMOUNT -l -n -i "$i"
1429 function handleDeviceMap
1434 local flags device target
1436 test -d "$dir" || return 0
1437 test -n "$xid" || return 0
1439 for i in "$dir"/*; do
1440 test -d "$i" || continue
1442 local -a vdevmap_opts=()
1443 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1444 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1445 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1447 getFileValue flags "$i/flags" || :
1448 getFileValue device "$i/device" || :
1449 getFileValue target "$i/target" || :
1450 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1451 ${device:+--device "$device"} ${target:+--target "$target"} )
1453 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1459 $_GREP -q "cgroup" /proc/filesystems
1462 function _generateCgroupOptions
1466 hasCgroup || return 0
1468 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1469 if test -n "$file"; then
1470 read CGROUP_MNT < "$file"
1472 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1473 if test -n "$file"; then
1474 _readFileToArray CGROUP_SUBSYS "$file"
1476 CGROUP_SUBSYS=( $($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups) )
1478 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1479 if test -n "$file"; then
1480 _readFileToArray CGROUP_INHERIT "$file" ""
1482 findFile file "$__CONFDIR/.defaults/cgroup/base" ""
1483 if test -n "$file"; then
1484 read CGROUP_BASE < "$file"
1485 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
1486 CGROUP_BASE="${CGROUP_BASE}/"
1488 findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
1489 if test -n "$file"; then
1498 hasCgroup || return 1
1499 if test -n "$CGROUP_MNT_PER_SS"; then
1502 for ss in "${CGROUP_SUBSYS[@]}"; do
1503 if test -e "$CGROUP_MNT/$ss/tasks"; then
1504 let existing=${existing}+1
1507 test "$existing" -gt 0 || return 1
1509 test -e "$CGROUP_MNT/tasks" || return 1
1512 if $_VSERVER_INFO - FEATURE memcg; then
1515 test -d "$1/cgroup" -o \
1516 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
1517 ! -e "$1/nocgroup" \)
1520 function _handleCgroup
1532 useCgroup "$vdir" || return 0
1534 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1536 if test -n "$dir" -a -r "$dir"/name; then
1537 read name < "$dir"/name
1539 name="$VSERVER_NAME"
1542 if test -n "$CGROUP_MNT_PER_SS"; then
1544 for ss in "${CGROUP_SUBSYS[@]}"; do
1545 mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
1548 mnts=( "$CGROUP_MNT" )
1550 for mnt in "${mnts[@]}"; do
1551 test -d "$mnt" || continue
1552 if test "$action" = "attach"; then
1553 if test -n "$CGROUP_BASE"; then
1555 i="$mnt/$CGROUP_BASE"
1556 while test "$mnt" != "$i"; do
1557 dirs=( "$i" "${dirs[@]}" )
1560 for i in "${dirs[@]}"; do
1561 if mkdir "$i" 2>/dev/null; then
1563 for j in "${CGROUP_INHERIT[@]}"; do
1564 test -f "$parent/$j" || continue
1565 cat "$parent/$j" > "$i/$j"
1570 if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
1571 parent="$mnt/$CGROUP_BASE$name"
1572 parent="${parent%/*}"
1573 for i in "${CGROUP_INHERIT[@]}"; do
1574 test -f "$parent/$i" || continue
1575 cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i"
1578 if test -n "$dir"; then
1580 for i in "$dir"/*; do
1582 test "$f" != mnt -a "$f" != subsys -a \
1583 "$f" != inherit -a "$f" != name -a "$f" != base -a \
1586 if test -n "$CGROUP_MNT_PER_SS"; then
1588 test "$ss" = "${mnt##*/}" || continue
1590 cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
1594 echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
1595 elif test "$action" = "destroy"; then
1596 rmdir "$mnt/$name" 2>/dev/null || :
1603 function attachToCgroup
1605 _handleCgroup attach "$@"
1608 function destroyCgroup
1610 _handleCgroup destroy "$@"