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=
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 test -n "$ionice_class$ionice_priority" || return 0
167 if test -z "$ionice_class" -a -n "$ionice_priority"; then
168 IONICE_CMD=( $_IONICE -c2 -n"$ionice_priority" )
170 IONICE_CMD=( $_IONICE ${ionice_class:+-c$ionice_class} ${ionice_priority:+-n$ionice_priority} )
174 function _generatePersonalityOptions
177 local f="$vdir"/personality
180 test -s "$f" || return 0
189 (*) flags=$flags$delim$tmp
196 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
197 --personality-type "$type"
198 ${flags:+--personality-flags "$flags"} )
201 function _generateCCapabilityOptions
205 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
208 function _generateBCapabilityOptions
212 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
215 function _generateUMaskOptions
219 _readFileToArray "$vdir"/umask OPTS_VATTRIBUTE --umask
222 function _generateCapabilityOptions
227 _generateBCapabilityOptions "$vdir"
228 _generateCCapabilityOptions "$vdir"
230 test -e "$vdir"/capabilities || return 0
239 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
240 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
243 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
246 done <"$vdir"/capabilities
249 function getEnterShell
256 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
258 test -n "$ENTER_SHELL" || {
260 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
262 test -x "$vdir/vdir/$1" || continue
269 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
270 function sendKillSequence
276 while isCtxRunning "$ctx"; do
277 test -z "$wait" || sleep "$wait"
279 killContext "$ctx" "$1"
280 test -n "$2" || break
286 function _generateInitOptions
289 local cfgdir=$vdir/apps/init
294 INITCMD_START_SYNC=()
299 INITKILL_SEQ=( 15 5 9 )
300 CHCONTEXT_INIT_OPTS=()
303 test x"$INITSTYLE" = xrescue || \
304 getFileValue INITSTYLE "$cfgdir"/style
305 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
306 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
307 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
308 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
310 findFile _gio_env "$cfgdir"/environment \
311 "$__CONFDIR"/.defaults/apps/init/environment \
312 "$__PKGLIBDEFAULTDIR"/environment
313 getFileArray OPTS_ENV "$_gio_env" || :
315 case x"$INITSTYLE" in
317 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
318 INITCMD_STOP=( /sbin/killall5 )
322 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
323 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
325 for i in /etc/init.d/rc /etc/rc.d/rc; do
326 test -x "$vdir/vdir/$i" || continue
327 INITCMD_START=( "$i" "$RUNLEVEL_START" )
328 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
330 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
331 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
332 if test -n "$OPTION_DEBUG_SYSV"; then
333 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
334 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
339 INITCMD_START=( /sbin/init )
340 INITCMD_STOP=( /sbin/init )
342 _NEED_VSHELPER_SYNC=1
343 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
344 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
348 INITCMD_START=( /sbin/minit-start )
349 INITCMD_STOP=( /sbin/minit-stop )
351 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
352 _NEED_VSHELPER_SYNC=1
353 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
354 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
355 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
359 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
360 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
362 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
363 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
364 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
365 RC_WRAP=/lib/rc/sh/init-vserver.sh
367 panic "init-vserver.sh not found; aborting"
370 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
371 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
372 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
373 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
377 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
378 INITCMD_START=( /etc/rc.multi )
379 INITCMD_STOP=( /etc/rc.shutdown )
380 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
384 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
387 if test x"$INITSTYLE" != xrescue; then
388 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
389 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
390 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
391 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
392 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
395 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
396 INITCMD_START_SYNC=()
401 if vshelper.isEnabled; then
402 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
408 function _generateFlagOptions
413 CHCONTEXT_FLAG_OPTS=()
415 findFile file "$vdir"/cflags "$vdir"/flags ""
425 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
426 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
432 isAvoidNamespace "$vdir" || {
434 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
435 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
436 OPT_VCONTEXT_CHROOT=--pivot-root
440 function _generateChcontextOptions
443 local ctx hostname domainname
448 read ctx <"$vdir"/context || :
450 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
451 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
454 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
456 _generateCapabilityOptions "$vdir"
457 _generateFlagOptions "$vdir"
458 _generateUMaskOptions "$vdir"
460 CHCONTEXT_OPTS=( $SILENT_OPT \
461 "${CHCONTEXT_FLAG_OPTS[@]}" \
464 ${ctx:+--ctx "$ctx"} \
465 ${hostname:+--hostname "$hostname"} \
466 ${domainname:+--domainname "$domainname"} )
468 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
469 ${ctx:+--xid "$ctx"} )
470 ## put '--secure' at front so that it can be overridden
471 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
474 function _generateScheduleOptions
477 if test -d "$vdir"/sched; then
478 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
482 local f="$vdir"/schedule
483 test -e "$f" || return 0
485 local fill_rate interval tokens tokens_min tokens_max prio_bias
493 read prio_bias || prio_bias=
497 test -n "$prio_bias" || {
498 echo $"Bad content in '$f'; aborting..." >&2
502 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
503 --tokens "$tokens" --tokens_min "$tokens_min" \
504 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
507 function _getInterfaceValue
517 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
520 : ${_giv_tmp:=$_giv_dflt}
521 eval $_giv_val=\$_giv_tmp
524 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
525 function _transformMask2Prefix
529 test -n "$_tm2p_tmp" || {
530 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
537 function _addInterfaceCmd
539 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
540 let ++INTERFACE_CMDS_IDX
543 ## Usage: _generateMac <var> <iface> <ctx>
544 function _generateMac
547 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
551 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
554 function _getVLANInfo
559 creation of VLAN_PLUS_VID devices is not supported; please create them
560 before starting the vserver and use the 'nodev' flag then"
561 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
565 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
566 create them before starting the vserver and use the 'nodev' flag then"
567 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
569 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
570 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
581 test -e "$iface/tun" -o -e "$iface/tap" || return 1
582 test ! -e "$iface/tun" || echo --tun
583 test ! -e "$iface/tap" || echo --tap
584 test ! -e "$iface/nocsum" || echo --~checksum
585 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
586 if test -e "$iface/uid"; then
588 getFileValue uid "$iface/uid"
591 if test -e "$iface/gid"; then
593 getFileValue gid "$iface/gid"
596 if test -e "$iface/linktype"; then
598 getFileValue linktype "$iface/linktype"
599 echo --linktype "$linktype"
604 ## Usage: _processSingleInterface <interface-directory>
605 function _processSingleInterface
621 _getInterfaceValue ip '' "$iface"
622 _getInterfaceValue extip '' "$iface" "$iface/.."
623 _getInterfaceValue dev '' "$iface" "$iface/.."
624 _getInterfaceValue prefix '' "$iface" "$iface/.."
625 _getInterfaceValue mask '' "$iface" "$iface/.."
626 _getInterfaceValue bcast '' "$iface" "$iface/.."
627 _getInterfaceValue name '' "$iface"
628 _getInterfaceValue scope '' "$iface" "$iface/.."
629 _getInterfaceValue mac '' "$iface"
630 _getInterfaceValue peer '' "$iface"
632 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
633 test -n "$dev" -o -e "$iface"/nodev || {
634 echo $"No device specified for '$iface'" >&2
638 test ! -e "$iface"/down || up=
641 _transformMask2Prefix prefix "$prefix" "$mask"
642 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
644 test ! -e "$iface"/nodev || break
646 test ! -e "$iface"/only_ip || break
648 test -e "$iface/vlandev" \
649 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
650 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
651 -a ! -e "$iface/novlandev" \
652 -a ! -e "$iface/../novlandev" \) && {
654 if vlan_info=$(_getVLANInfo "$dev"); then
655 test -d /proc/net/vlan || {
656 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
659 _addInterfaceCmd VCONFIG $vlan_info
663 if ! test -e "$iface"/indirect; then
665 local use_bcast="broadcast ${bcast:-+}"
666 echo "$ip" | $_GREP -q : && use_bcast=
669 if tun_info=$(_getTunInfo "$iface"); then
670 _addInterfaceCmd TUNCTL "$dev" $tun_info
673 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
674 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
675 _addInterfaceCmd IP_LINK "$dev" $up
676 elif ! test -n "$N_CONTEXT"; then
677 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
680 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
681 _addInterfaceCmd MODPROBE dummy "$dev"
682 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
683 _addInterfaceCmd NAMEIF "$dev" "$mac"
684 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
685 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
692 ## Usage: _generateInterfaceOptions <vserver-directory>
693 function _generateInterfaceOptions
697 # XXX: This is here instead of in _generateChbindOptions
698 # to avoid a circular dependency
699 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
700 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
702 for iface in "$1/interfaces/"*; do
703 test -d "$iface" || continue
704 test ! -e "$iface"/disabled || continue
706 _processSingleInterface "$iface"
708 _HAVE_INTERFACE_OPTIONS=1
711 function enableInterfaces
716 lock "$__LOCKDIR"/vserver.interfaces
718 while test $i -lt $INTERFACE_CMDS_IDX; do
719 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
730 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
732 NAMEIF) $_NAMEIF "$@";;
733 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
734 $_VCONFIG add "$2" "$3" >/dev/null;;
735 IP_ADDR) $_IP addr add "$@";;
736 IP_ADDR_FLUSH) $_IP addr flush "$@";;
737 IP_LINK) $_IP link set "$@";;
738 IP_ROUTE) $_IP route add "$@";;
742 $_TUNCTL --persist "$@" "$dev"
744 *) echo "Unknown interface-command type '$type'" >&2; false;;
753 function disableInterfaces
755 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
757 local i=$INTERFACE_CMDS_IDX
760 lock "$__LOCKDIR"/vserver.interfaces
762 while test $i -gt 0; do
765 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
772 MODPROBE) $_RMMOD "${2:-$1}";;
774 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
775 IP_ADDR) $_IP addr del "$@";;
777 IP_LINK) ;; ## Ignore the link-down command for now
778 IP_ROUTE) $_IP route del "$@";;
782 $_TUNCTL --~persist "$@" "$dev"
784 *) echo "Unknown interface-command type '$type'" >&2; false;;
791 function _generateTagOptions
796 getFileValue tag "$vdir/tag" "$vdir/context"
797 test -n "$tag" || return 0
799 OPTS_VTAG_CREATE=( --tag "$tag" )
800 OPTS_VTAG_ENTER=( --tag "$tag" )
803 function _generateMemctrlOptions
808 getFileValue badness "$vdir/badness"
809 test -n "$badness" || return 0
811 OPTS_VMEMCTRL=( --badness "$badness" )
814 function _generateSpaceOptions
817 local d="$vdir"/spaces
821 for space in pid net; do
822 if test -e "$d"/$space; then
823 getFileValue shared "$d"/$space || shared=""
824 if test -z "$shared"; then
825 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
826 elif test "$shared" = "0"; then
829 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
830 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
836 getFileValue mask "$d"/mask || \
837 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
840 ## Usage: prepareInit <vserver-directory>
843 pushd "$1/vdir" >/dev/null
846 { $_FIND var/run ! -type d -print0; \
847 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
850 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
851 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
856 "${INITCMD_PREPARE[@]}"
860 ## Usage: prepareInit <vserver-directory>
863 pushd "$1/vdir" >/dev/null
866 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
869 "${STOPCMD_PREPARE[@]}"
874 function generateOptions
876 _generateInterfaceOptions "$1"
877 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
878 _generateNiceCommand "$1"
879 _generateIONiceCommand "$1"
880 _generateInitOptions "$1"
881 _generateChcontextOptions "$1"
882 _generateScheduleOptions "$1"
883 _generatePersonalityOptions "$1"
884 _generateTagOptions "$1"
885 _generateMemctrlOptions "$1"
886 _generateSpaceOptions "$1"
887 _generateCgroupOptions
889 if test -n "$_IS_FAKEINIT"; then
890 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
891 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
899 local f="$vdir"/cpuset
903 test -d "$f" || return 0
904 test -e "$f"/name || return 0
906 read cpuset < "$f"/name
907 test -e "$f"/nocreate || {
908 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
909 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
910 if test -e "$f"/"$i"; then
911 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
919 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
920 if [ "$configured" -ne 0 ]; then
922 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
923 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
928 function removeCPUSET
932 local f="$vdir"/cpuset
934 test -d "$f" || return 0
935 test -e "$f"/name || return 0
937 read cpuset < "$f"/name
938 test -e "$f"/nocreate || {
939 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
943 function _mountVserverInternal
948 test -e "$fstab" || return 0
951 pushd "$vdir" >/dev/null
952 # check whether / is mounted readonly or whether there is special
953 # magic regarding the mtab file; when etc/mtab can not be touched,
954 # add the '-n' flag to mount
955 test -w etc -o -w etc/mtab || xflag=-n
956 if test -h etc/mtab; then
957 local l=$($_READLINK etc/mtab)
958 test "${l##/proc/}" = "$l" || xflag=-n
960 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
968 local fstab="$cfgdir"/fstab
971 test -e "$fstab" || return 0
972 pushd "$vdir" >/dev/null
973 # check whether / is mounted readonly or whether there is special
974 # magic regarding the mtab file; when etc/mtab can not be touched,
975 # add the '-n' flag to mount
976 test -w etc -o -w etc/mtab || xflag=-n
977 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
981 function mountVserver
990 test -e "$cfgdir"/fstab -o \
991 -e "$cfgdir"/fstab.local -o \
992 -e "$cfgdir"/fstab.remote || return 0
994 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
996 pushd "$vdir" >/dev/null
997 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
1000 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1002 _mountVserverInternal "$cfgdir"/fstab
1003 _mountVserverInternal "$cfgdir"/fstab.local
1004 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
1006 isNamespaceCleanup "$cfgdir" && \
1007 _namespaceCleanup "$cfgdir"
1009 real_vdir=$(getPhysicalDir "$vdir")
1010 isAvoidNamespace "$cfgdir" || \
1011 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
1012 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
1013 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
1016 function _umountVserverInternal
1019 test -e "$fstab" || return 0
1024 while read src dst tmp; do
1025 test -n "$tmp" || continue
1031 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1037 function umountVserver
1043 isAvoidNamespace "$cfgdir" || return 0
1044 test -e "$cfgdir"/fstab -o \
1045 -e "$cfgdir"/fstab.local -o \
1046 -e "$cfgdir"/fstab.remote || return 0
1047 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1049 pushd "$vdir/" >/dev/null || return 1
1050 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1051 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1052 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1053 popd >/dev/null || return 1
1061 local fstab="$cfgdir"/fstab
1065 test -e "$fstab" || return 0
1067 export FSTAB_FILE="$fstab"
1070 test "$fsck_exitcode" -eq 0 -o \
1071 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1074 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1078 test -n "$_NEED_VSHELPER_SYNC" && \
1079 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1081 vshelper.initSync "$1" "$3" "$_is_meth"
1084 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1087 if $_VSERVER_INFO - FEATURE vwait; then
1089 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1092 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1093 --status-fd 3 "$2" \
1094 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1097 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1098 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1099 killContext "$S_CONTEXT" 9
1103 ) 4>$_is_tmpdir/procs &
1105 echo "$!" >$_is_tmpdir/pid
1106 eval "$3"=$_is_tmpdir
1111 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1112 function _waitForVWait
1117 declare -r procs=$(cat $4)
1119 getFileArray status "$2"
1124 'vwait' exited with error '$2' which indicates that vserver could not
1125 be stopped properly"
1128 (KILLED) warning $"\
1129 A timeout occured while waiting for the vserver to finish and it was
1130 killed by sending a SIGKILL signal. Please investigate the reasons
1131 and/or increase the timeout in apps/vshelper/sync-timeout."
1134 (TIMEOUT) warning $"\
1135 A timeout occured while waiting for the vserver to finish and it will
1136 be killed by sending a SIGKILL signal. The following process list
1137 might be useful for finding out the reason of this behavior:
1139 ----------------------------------------------------------------------
1141 }----------------------------------------------------------------------"
1144 (\?\?\?|*) warning $"\
1145 internal error: 'vwait' exited with an unexpected status '$1'; I will
1146 try to continue but be prepared for unexpected events."
1153 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1154 function waitForSync
1158 local vwait_statdir=$3
1161 if test -d "$vwait_statdir"; then
1162 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1163 elif test -n "$_NEED_VSHELPER_SYNC"; then
1164 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1166 A timeout or other error occured while waiting for the synchronization
1167 signal from vserver '$VSERVER_NAME'.
1168 The vserver will be killed nevertheless..."
1169 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1170 "${INITCMD_STOP_SYNC[@]}" || \
1172 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1173 will be killed nevertheless..."
1176 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1180 function _sourceWrap
1182 local vdir name flavor start i already_handled base
1186 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1187 function execScriptlets
1191 declare -r flavor=$3
1194 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1195 local DONT_SKIP_DEFAULTS=
1196 local already_handled=
1198 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1199 isRegularFile "$i" || continue
1200 test -r "$i" || continue
1204 test -x "$i" || start=_sourceWrap
1205 $start "$i" "$flavor" "$name"
1208 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1213 function sanityCheck
1215 declare -r cfgdir=$1
1217 ! test -e "$cfgdir"/fstab.local ||
1219 WARNING: 'fstab' will *not* be executed in the network context of the
1220 vserver anymore. Therefore, 'fstab.local' has the same functionality
1221 and is obsoleted. When you need the old behaviour, put the mounts
1222 into 'fstab.remote'"
1224 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1226 WARNING: The hostname is now configured in 'uts/nodename' but not in
1229 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1231 WARNING: The domainname is now configured in 'uts/domainname' but not
1232 in 'domainname'." >&2
1236 for i in "$cfgdir"/interfaces/*/only_ip; do
1237 if test -e "$i"; then
1239 iface=${i##$cfgdir/interfaces/}
1240 iface=${iface%%/only_ip}
1242 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1247 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1249 WARNING: There is no cachedirectory configured for this vserver;
1250 please create '$cfgdir/cache' e.g. by executing
1252 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1255 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1257 vshelper.doSanityCheck
1259 $_VSERVER_INFO - VERIFYCAP ||
1260 panic $"capabilities are not enabled in kernel-setup"
1262 $_VSERVER_INFO - VERIFYPROC ||
1264 /proc/uptime can not be accessed. Usually, this is caused by
1265 procfs-security. Please read the FAQ for more details
1266 http://linux-vserver.org/Proc-Security"
1268 test -e "$cfgdir"/context || {
1269 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1270 test "$TYPE" != "static" || panic $"\
1271 The kernel does not have dynamic contexts enabled. Please configure
1272 a static one by executing
1274 echo [number between 2 and 49151] > $cfgdir/context"
1279 function _setSingleDiskLimit
1291 getFileValue ctx "$vdir/context"
1292 getFileValue directory "$dlimit/directory" || return 0
1293 getFileValue space_total "$dlimit/space_total" || return 0
1294 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1295 getFileValue reserved "$dlimit/reserved" || return 0
1297 local cachename=$ctx$directory
1298 cachename=dlimits/${cachename//\//_}
1300 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1301 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1302 $_RM -f "$vdir/cache/$cachename"
1304 if test -z "$inodes_used" -o -z "$space_used"; then
1306 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1307 inodes_used=${tmpvdu##* }
1308 space_used=${tmpvdu%% *}
1311 $_VDLIMIT --xid $ctx \
1312 --set space_used=$space_used \
1313 --set space_total=$space_total \
1314 --set inodes_used=$inodes_used \
1315 --set inodes_total=$inodes_total \
1316 --set reserved=$reserved \
1321 function setDiskLimits
1326 # Disk Limits without a static context are useless
1327 test -e "$vdir"/context || return 0
1329 for dlimit in "$vdir/dlimits/"*; do
1330 test -d "$dlimit" || continue
1331 test ! -e "$dlimit/disabled" || continue
1333 _setSingleDiskLimit "$vdir" "$dlimit"
1338 function _saveSingleDiskLimit
1345 getFileValue ctx "$vdir/context"
1346 getFileValue directory "$dlimit/directory" || return 0
1348 local cachename=$ctx$directory
1349 cachename=${cachename//\//_}
1351 # Things are getting ugly here... LFS says that /var/cache (where
1352 # cachename is usually pointing to) can vanish and applications
1353 # have to deal with it. So, we have to interprete the $vdir/cache
1354 # symlink and have to create the needed directories manually.
1355 if test -d "$vdir/cache"; then
1356 : # ok, exists already
1357 elif test -L "$vdir/cache"; then
1358 # it's a dangling symlink
1360 link=$($_READLINK "$vdir/cache")
1361 ( cd $vdir && $_MKDIR -p "$link" )
1366 test -d "$vdir/cache"
1367 $_MKDIR -p "$vdir"/cache/dlimits
1369 $_VDLIMIT --xid $ctx "$directory" | \
1370 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1372 $_VDLIMIT --xid $ctx --remove "$directory"
1376 function saveDiskLimits
1381 test -e "$vdir"/context || return 0
1383 for dlimit in "$vdir/dlimits/"*; do
1384 test -d "$dlimit" || continue
1385 test ! -e "$dlimit/disabled" || continue
1387 _saveSingleDiskLimit "$vdir" "$dlimit"
1391 function _namespaceCleanup
1394 local root=$($_VSERVER_INFO "$1" VDIR 1)
1400 getFileArray skip "$vdir"/namespace-cleanup-skip \
1401 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1403 # these are things that have to be accessible post-cleanup
1404 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1405 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1406 local real=`getPhysicalDir "$i"`
1407 test "$i" != "$real" || real=
1408 for j in "$i" "$real"; do
1409 while test -n "$j"; do
1410 list=( "${list[@]}" "$j" )
1416 local -a list_umount
1417 while read -r dev path opts; do
1418 test -n "$path" || continue
1419 for i in "$root" /dev /proc; do
1421 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1423 for i in "${list[@]}" /; do
1424 test "$path" = "$i" && continue 2
1426 # unmount them in reverse order so mounts further down the tree get unmounted first
1427 list_umount=( "$path" "${list_umount[@]}" )
1429 # separate loop to avoid races while reading /proc/mounts
1430 for i in "${list_umount[@]}"; do
1431 $_UMOUNT -l -n -i "$i"
1435 function handleDeviceMap
1440 local flags device target
1442 test -d "$dir" || return 0
1443 test -n "$xid" || return 0
1445 for i in "$dir"/*; do
1446 test -d "$i" || continue
1448 local -a vdevmap_opts=()
1449 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1450 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1451 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1453 getFileValue flags "$i/flags" || :
1454 getFileValue device "$i/device" || :
1455 getFileValue target "$i/target" || :
1456 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1457 ${device:+--device "$device"} ${target:+--target "$target"} )
1459 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1465 $_GREP -q "cgroup" /proc/filesystems
1468 function _generateCgroupOptions
1472 hasCgroup || return 0
1474 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1475 if test -n "$file"; then
1476 read CGROUP_MNT < "$file"
1478 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1479 if test -n "$file"; then
1480 _readFileToArray CGROUP_SUBSYS "$file"
1482 CGROUP_SUBSYS=( $($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups) )
1484 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1485 if test -n "$file"; then
1486 _readFileToArray CGROUP_INHERIT "$file" ""
1488 findFile file "$__CONFDIR/.defaults/cgroup/base" ""
1489 if test -n "$file"; then
1490 read CGROUP_BASE < "$file"
1491 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
1492 CGROUP_BASE="${CGROUP_BASE}/"
1494 findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
1495 if test -n "$file"; then
1504 hasCgroup || return 1
1505 if test -n "$CGROUP_MNT_PER_SS"; then
1508 for ss in "${CGROUP_SUBSYS[@]}"; do
1509 if test -e "$CGROUP_MNT/$ss/tasks"; then
1510 let existing=${existing}+1
1513 test "$existing" -gt 0 || return 1
1515 test -e "$CGROUP_MNT/tasks" || return 1
1518 if $_VSERVER_INFO - FEATURE memcg; then
1521 test -d "$1/cgroup" -o \
1522 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
1523 ! -e "$1/nocgroup" \)
1526 function _handleCgroup
1538 useCgroup "$vdir" || return 0
1540 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1542 if test -n "$dir" -a -r "$dir"/name; then
1543 read name < "$dir"/name
1545 name="$VSERVER_NAME"
1548 if test -n "$CGROUP_MNT_PER_SS"; then
1550 for ss in "${CGROUP_SUBSYS[@]}"; do
1551 mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
1554 mnts=( "$CGROUP_MNT" )
1556 for mnt in "${mnts[@]}"; do
1557 test -d "$mnt" || continue
1558 if test "$action" = "attach"; then
1559 if test -n "$CGROUP_BASE"; then
1561 i="$mnt/$CGROUP_BASE"
1562 while test "$mnt" != "$i"; do
1563 dirs=( "$i" "${dirs[@]}" )
1566 for i in "${dirs[@]}"; do
1567 if mkdir "$i" 2>/dev/null; then
1569 for j in "${CGROUP_INHERIT[@]}"; do
1570 test -f "$parent/$j" || continue
1571 cat "$parent/$j" > "$i/$j"
1576 if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
1577 parent="$mnt/$CGROUP_BASE$name"
1578 parent="${parent%/*}"
1579 for i in "${CGROUP_INHERIT[@]}"; do
1580 test -f "$parent/$i" || continue
1581 cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i"
1584 if test -n "$dir"; then
1586 for i in "$dir"/*; do
1588 test "$f" != mnt -a "$f" != subsys -a \
1589 "$f" != inherit -a "$f" != name -a "$f" != base -a \
1592 if test -n "$CGROUP_MNT_PER_SS"; then
1594 test "$ss" = "${mnt##*/}" || continue
1596 cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
1600 echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
1601 elif test "$action" = "destroy"; then
1602 rmdir "$mnt/$name" 2>/dev/null || :
1609 function attachToCgroup
1611 _handleCgroup attach "$@"
1614 function destroyCgroup
1616 _handleCgroup destroy "$@"