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 _generateCapabilityOptions
214 _generateBCapabilityOptions "$vdir"
215 _generateCCapabilityOptions "$vdir"
217 test -e "$vdir"/capabilities || return 0
226 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
227 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
230 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
233 done <"$vdir"/capabilities
236 function getEnterShell
243 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
245 test -n "$ENTER_SHELL" || {
247 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
249 test -x "$vdir/vdir/$1" || continue
256 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
257 function sendKillSequence
263 while isCtxRunning "$ctx"; do
264 test -z "$wait" || sleep "$wait"
266 killContext "$ctx" "$1"
267 test -n "$2" || break
273 function _generateInitOptions
276 local cfgdir=$vdir/apps/init
281 INITCMD_START_SYNC=()
286 INITKILL_SEQ=( 15 5 9 )
287 CHCONTEXT_INIT_OPTS=()
290 test x"$INITSTYLE" = xrescue || \
291 getFileValue INITSTYLE "$cfgdir"/style
292 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
293 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
294 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
295 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
297 findFile _gio_env "$cfgdir"/environment \
298 "$__CONFDIR"/.defaults/apps/init/environment \
299 "$__PKGLIBDEFAULTDIR"/environment
300 getFileArray OPTS_ENV "$_gio_env" || :
302 case x"$INITSTYLE" in
304 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
305 INITCMD_STOP=( /sbin/killall5 )
309 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
310 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
312 for i in /etc/init.d/rc /etc/rc.d/rc; do
313 test -x "$vdir/vdir/$i" || continue
314 INITCMD_START=( "$i" "$RUNLEVEL_START" )
315 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
317 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
318 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
319 if test -n "$OPTION_DEBUG_SYSV"; then
320 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
321 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
326 INITCMD_START=( /sbin/init )
327 INITCMD_STOP=( /sbin/init )
329 _NEED_VSHELPER_SYNC=1
330 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
331 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
335 INITCMD_START=( /sbin/minit-start )
336 INITCMD_STOP=( /sbin/minit-stop )
338 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
339 _NEED_VSHELPER_SYNC=1
340 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
341 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
342 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
346 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
347 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
349 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
350 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
351 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
352 RC_WRAP=/lib/rc/sh/init-vserver.sh
354 panic "init-vserver.sh not found; aborting"
357 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
358 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
359 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
360 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
364 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
365 INITCMD_START=( /etc/rc.multi )
366 INITCMD_STOP=( /etc/rc.shutdown )
367 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
371 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
374 if test x"$INITSTYLE" != xrescue; then
375 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
376 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
377 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
378 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
379 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
382 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
383 INITCMD_START_SYNC=()
388 if vshelper.isEnabled; then
389 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
395 function _generateFlagOptions
400 CHCONTEXT_FLAG_OPTS=()
402 findFile file "$vdir"/cflags "$vdir"/flags ""
412 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
413 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
419 isAvoidNamespace "$vdir" || {
421 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
422 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
423 OPT_VCONTEXT_CHROOT=--pivot-root
427 function _generateChcontextOptions
430 local ctx hostname domainname
435 read ctx <"$vdir"/context || :
437 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
438 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
441 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
443 _generateCapabilityOptions "$vdir"
444 _generateFlagOptions "$vdir"
446 CHCONTEXT_OPTS=( $SILENT_OPT \
447 "${CHCONTEXT_FLAG_OPTS[@]}" \
450 ${ctx:+--ctx "$ctx"} \
451 ${hostname:+--hostname "$hostname"} \
452 ${domainname:+--domainname "$domainname"} )
454 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
455 ${ctx:+--xid "$ctx"} )
456 ## put '--secure' at front so that it can be overridden
457 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
460 function _generateScheduleOptions
463 if test -d "$vdir"/sched; then
464 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
468 local f="$vdir"/schedule
469 test -e "$f" || return 0
471 local fill_rate interval tokens tokens_min tokens_max prio_bias
479 read prio_bias || prio_bias=
483 test -n "$prio_bias" || {
484 echo $"Bad content in '$f'; aborting..." >&2
488 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
489 --tokens "$tokens" --tokens_min "$tokens_min" \
490 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
493 function _getInterfaceValue
503 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
506 : ${_giv_tmp:=$_giv_dflt}
507 eval $_giv_val=\$_giv_tmp
510 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
511 function _transformMask2Prefix
515 test -n "$_tm2p_tmp" || {
516 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
523 function _addInterfaceCmd
525 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
526 let ++INTERFACE_CMDS_IDX
529 ## Usage: _generateMac <var> <iface> <ctx>
530 function _generateMac
533 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
537 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
540 function _getVLANInfo
545 creation of VLAN_PLUS_VID devices is not supported; please create them
546 before starting the vserver and use the 'nodev' flag then"
547 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
551 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
552 create them before starting the vserver and use the 'nodev' flag then"
553 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
555 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
556 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
567 test -e "$iface/tun" -o -e "$iface/tap" || return 1
568 test ! -e "$iface/tun" || echo --tun
569 test ! -e "$iface/tap" || echo --tap
570 test ! -e "$iface/nocsum" || echo --~checksum
571 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
572 if test -e "$iface/uid"; then
574 getFileValue uid "$iface/uid"
577 if test -e "$iface/gid"; then
579 getFileValue gid "$iface/gid"
582 if test -e "$iface/linktype"; then
584 getFileValue linktype "$iface/linktype"
585 echo --linktype "$linktype"
590 ## Usage: _processSingleInterface <interface-directory>
591 function _processSingleInterface
607 _getInterfaceValue ip '' "$iface"
608 _getInterfaceValue extip '' "$iface" "$iface/.."
609 _getInterfaceValue dev '' "$iface" "$iface/.."
610 _getInterfaceValue prefix '' "$iface" "$iface/.."
611 _getInterfaceValue mask '' "$iface" "$iface/.."
612 _getInterfaceValue bcast '' "$iface" "$iface/.."
613 _getInterfaceValue name '' "$iface"
614 _getInterfaceValue scope '' "$iface" "$iface/.."
615 _getInterfaceValue mac '' "$iface"
616 _getInterfaceValue peer '' "$iface"
618 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
619 test -n "$dev" -o -e "$iface"/nodev || {
620 echo $"No device specified for '$iface'" >&2
624 test ! -e "$iface"/down || up=
627 _transformMask2Prefix prefix "$prefix" "$mask"
628 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
630 test ! -e "$iface"/nodev || break
632 test ! -e "$iface"/only_ip || break
634 test -e "$iface/vlandev" \
635 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
636 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
637 -a ! -e "$iface/novlandev" \
638 -a ! -e "$iface/../novlandev" \) && {
640 if vlan_info=$(_getVLANInfo "$dev"); then
641 test -d /proc/net/vlan || {
642 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
645 _addInterfaceCmd VCONFIG $vlan_info
649 if ! test -e "$iface"/indirect; then
651 local use_bcast="broadcast ${bcast:-+}"
652 echo "$ip" | $_GREP -q : && use_bcast=
655 if tun_info=$(_getTunInfo "$iface"); then
656 _addInterfaceCmd TUNCTL "$dev" $tun_info
659 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
660 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
661 _addInterfaceCmd IP_LINK "$dev" $up
662 elif ! test -n "$N_CONTEXT"; then
663 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
666 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
667 _addInterfaceCmd MODPROBE dummy "$dev"
668 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
669 _addInterfaceCmd NAMEIF "$dev" "$mac"
670 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
671 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
678 ## Usage: _generateInterfaceOptions <vserver-directory>
679 function _generateInterfaceOptions
683 # XXX: This is here instead of in _generateChbindOptions
684 # to avoid a circular dependency
685 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
686 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
688 for iface in "$1/interfaces/"*; do
689 test -d "$iface" || continue
690 test ! -e "$iface"/disabled || continue
692 _processSingleInterface "$iface"
694 _HAVE_INTERFACE_OPTIONS=1
697 function enableInterfaces
702 lock "$__LOCKDIR"/vserver.interfaces
704 while test $i -lt $INTERFACE_CMDS_IDX; do
705 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
716 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
718 NAMEIF) $_NAMEIF "$@";;
719 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
720 $_VCONFIG add "$2" "$3" >/dev/null;;
721 IP_ADDR) $_IP addr add "$@";;
722 IP_ADDR_FLUSH) $_IP addr flush "$@";;
723 IP_LINK) $_IP link set "$@";;
724 IP_ROUTE) $_IP route add "$@";;
728 $_TUNCTL --persist "$@" "$dev"
730 *) echo "Unknown interface-command type '$type'" >&2; false;;
739 function disableInterfaces
741 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
743 local i=$INTERFACE_CMDS_IDX
746 lock "$__LOCKDIR"/vserver.interfaces
748 while test $i -gt 0; do
751 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
758 MODPROBE) $_RMMOD "${2:-$1}";;
760 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
761 IP_ADDR) $_IP addr del "$@";;
763 IP_LINK) ;; ## Ignore the link-down command for now
764 IP_ROUTE) $_IP route del "$@";;
768 $_TUNCTL --~persist "$@" "$dev"
770 *) echo "Unknown interface-command type '$type'" >&2; false;;
777 function _generateTagOptions
782 getFileValue tag "$vdir/tag" "$vdir/context"
783 test -n "$tag" || return 0
785 OPTS_VTAG_CREATE=( --tag "$tag" )
786 OPTS_VTAG_ENTER=( --tag "$tag" )
789 function _generateMemctrlOptions
794 getFileValue badness "$vdir/badness"
795 test -n "$badness" || return 0
797 OPTS_VMEMCTRL=( --badness "$badness" )
800 function _generateSpaceOptions
803 local d="$vdir"/spaces
807 for space in pid net; do
808 if test -e "$d"/$space; then
809 getFileValue shared "$d"/$space || shared=""
810 if test -z "$shared"; then
811 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
812 elif test "$shared" = "0"; then
815 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
816 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
822 getFileValue mask "$d"/mask || \
823 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
826 ## Usage: prepareInit <vserver-directory>
829 pushd "$1/vdir" >/dev/null
832 { $_FIND var/run ! -type d -print0; \
833 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
836 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
837 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
842 "${INITCMD_PREPARE[@]}"
846 ## Usage: prepareInit <vserver-directory>
849 pushd "$1/vdir" >/dev/null
852 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
855 "${STOPCMD_PREPARE[@]}"
860 function generateOptions
862 _generateInterfaceOptions "$1"
863 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
864 _generateNiceCommand "$1"
865 _generateIONiceCommand "$1"
866 _generateInitOptions "$1"
867 _generateChcontextOptions "$1"
868 _generateScheduleOptions "$1"
869 _generatePersonalityOptions "$1"
870 _generateTagOptions "$1"
871 _generateMemctrlOptions "$1"
872 _generateSpaceOptions "$1"
873 _generateCgroupOptions
875 if test -n "$_IS_FAKEINIT"; then
876 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
877 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
885 local f="$vdir"/cpuset
889 test -d "$f" || return 0
890 test -e "$f"/name || return 0
892 read cpuset < "$f"/name
893 test -e "$f"/nocreate || {
894 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
895 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
896 if test -e "$f"/"$i"; then
897 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
905 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
906 if [ "$configured" -ne 0 ]; then
908 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
909 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
914 function removeCPUSET
918 local f="$vdir"/cpuset
920 test -d "$f" || return 0
921 test -e "$f"/name || return 0
923 read cpuset < "$f"/name
924 test -e "$f"/nocreate || {
925 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
929 function _mountVserverInternal
934 test -e "$fstab" || return 0
937 pushd "$vdir" >/dev/null
938 # check whether / is mounted readonly or whether there is special
939 # magic regarding the mtab file; when etc/mtab can not be touched,
940 # add the '-n' flag to mount
941 test -w etc -o -w etc/mtab || xflag=-n
942 if test -h etc/mtab; then
943 local l=$($_READLINK etc/mtab)
944 test "${l##/proc/}" = "$l" || xflag=-n
946 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
954 local fstab="$cfgdir"/fstab
957 test -e "$fstab" || return 0
958 pushd "$vdir" >/dev/null
959 # check whether / is mounted readonly or whether there is special
960 # magic regarding the mtab file; when etc/mtab can not be touched,
961 # add the '-n' flag to mount
962 test -w etc -o -w etc/mtab || xflag=-n
963 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
967 function mountVserver
976 test -e "$cfgdir"/fstab -o \
977 -e "$cfgdir"/fstab.local -o \
978 -e "$cfgdir"/fstab.remote || return 0
980 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
982 pushd "$vdir" >/dev/null
983 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
986 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
988 _mountVserverInternal "$cfgdir"/fstab
989 _mountVserverInternal "$cfgdir"/fstab.local
990 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
992 isNamespaceCleanup "$cfgdir" && \
993 _namespaceCleanup "$cfgdir"
995 real_vdir=$(getPhysicalDir "$vdir")
996 isAvoidNamespace "$cfgdir" || \
997 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
998 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
999 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
1002 function _umountVserverInternal
1005 test -e "$fstab" || return 0
1010 while read src dst tmp; do
1011 test -n "$tmp" || continue
1017 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1023 function umountVserver
1029 isAvoidNamespace "$cfgdir" || return 0
1030 test -e "$cfgdir"/fstab -o \
1031 -e "$cfgdir"/fstab.local -o \
1032 -e "$cfgdir"/fstab.remote || return 0
1033 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1035 pushd "$vdir/" >/dev/null || return 1
1036 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1037 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1038 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1039 popd >/dev/null || return 1
1047 local fstab="$cfgdir"/fstab
1051 test -e "$fstab" || return 0
1053 export FSTAB_FILE="$fstab"
1056 test "$fsck_exitcode" -eq 0 -o \
1057 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1060 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1064 test -n "$_NEED_VSHELPER_SYNC" && \
1065 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1067 vshelper.initSync "$1" "$3" "$_is_meth"
1070 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1073 if $_VSERVER_INFO - FEATURE vwait; then
1075 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1078 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1079 --status-fd 3 "$2" \
1080 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1083 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1084 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1085 killContext "$S_CONTEXT" 9
1089 ) 4>$_is_tmpdir/procs &
1091 echo "$!" >$_is_tmpdir/pid
1092 eval "$3"=$_is_tmpdir
1097 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1098 function _waitForVWait
1103 declare -r procs=$(cat $4)
1105 getFileArray status "$2"
1110 'vwait' exited with error '$2' which indicates that vserver could not
1111 be stopped properly"
1114 (KILLED) warning $"\
1115 A timeout occured while waiting for the vserver to finish and it was
1116 killed by sending a SIGKILL signal. Please investigate the reasons
1117 and/or increase the timeout in apps/vshelper/sync-timeout."
1120 (TIMEOUT) warning $"\
1121 A timeout occured while waiting for the vserver to finish and it will
1122 be killed by sending a SIGKILL signal. The following process list
1123 might be useful for finding out the reason of this behavior:
1125 ----------------------------------------------------------------------
1127 }----------------------------------------------------------------------"
1130 (\?\?\?|*) warning $"\
1131 internal error: 'vwait' exited with an unexpected status '$1'; I will
1132 try to continue but be prepared for unexpected events."
1139 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1140 function waitForSync
1144 local vwait_statdir=$3
1147 if test -d "$vwait_statdir"; then
1148 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1149 elif test -n "$_NEED_VSHELPER_SYNC"; then
1150 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1152 A timeout or other error occured while waiting for the synchronization
1153 signal from vserver '$VSERVER_NAME'.
1154 The vserver will be killed nevertheless..."
1155 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1156 "${INITCMD_STOP_SYNC[@]}" || \
1158 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1159 will be killed nevertheless..."
1162 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1166 function _sourceWrap
1168 local vdir name flavor start i already_handled base
1172 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1173 function execScriptlets
1177 declare -r flavor=$3
1180 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1181 local DONT_SKIP_DEFAULTS=
1182 local already_handled=
1184 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1185 isRegularFile "$i" || continue
1186 test -r "$i" || continue
1190 test -x "$i" || start=_sourceWrap
1191 $start "$i" "$flavor" "$name"
1194 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1199 function sanityCheck
1201 declare -r cfgdir=$1
1203 ! test -e "$cfgdir"/fstab.local ||
1205 WARNING: 'fstab' will *not* be executed in the network context of the
1206 vserver anymore. Therefore, 'fstab.local' has the same functionality
1207 and is obsoleted. When you need the old behaviour, put the mounts
1208 into 'fstab.remote'"
1210 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1212 WARNING: The hostname is now configured in 'uts/nodename' but not in
1215 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1217 WARNING: The domainname is now configured in 'uts/domainname' but not
1218 in 'domainname'." >&2
1222 for i in "$cfgdir"/interfaces/*/only_ip; do
1223 if test -e "$i"; then
1225 iface=${i##$cfgdir/interfaces/}
1226 iface=${iface%%/only_ip}
1228 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1233 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1235 WARNING: There is no cachedirectory configured for this vserver;
1236 please create '$cfgdir/cache' e.g. by executing
1238 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1241 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1243 vshelper.doSanityCheck
1245 $_VSERVER_INFO - VERIFYCAP ||
1246 panic $"capabilities are not enabled in kernel-setup"
1248 $_VSERVER_INFO - VERIFYPROC ||
1250 /proc/uptime can not be accessed. Usually, this is caused by
1251 procfs-security. Please read the FAQ for more details
1252 http://linux-vserver.org/Proc-Security"
1254 test -e "$cfgdir"/context || {
1255 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1256 test "$TYPE" != "static" || panic $"\
1257 The kernel does not have dynamic contexts enabled. Please configure
1258 a static one by executing
1260 echo [number between 2 and 49151] > $cfgdir/context"
1265 function _setSingleDiskLimit
1277 getFileValue ctx "$vdir/context"
1278 getFileValue directory "$dlimit/directory" || return 0
1279 getFileValue space_total "$dlimit/space_total" || return 0
1280 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1281 getFileValue reserved "$dlimit/reserved" || return 0
1283 local cachename=$ctx$directory
1284 cachename=dlimits/${cachename//\//_}
1286 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1287 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1288 $_RM -f "$vdir/cache/$cachename"
1290 if test -z "$inodes_used" -o -z "$space_used"; then
1292 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1293 inodes_used=${tmpvdu##* }
1294 space_used=${tmpvdu%% *}
1297 $_VDLIMIT --xid $ctx \
1298 --set space_used=$space_used \
1299 --set space_total=$space_total \
1300 --set inodes_used=$inodes_used \
1301 --set inodes_total=$inodes_total \
1302 --set reserved=$reserved \
1307 function setDiskLimits
1312 # Disk Limits without a static context are useless
1313 test -e "$vdir"/context || return 0
1315 for dlimit in "$vdir/dlimits/"*; do
1316 test -d "$dlimit" || continue
1317 test ! -e "$dlimit/disabled" || continue
1319 _setSingleDiskLimit "$vdir" "$dlimit"
1324 function _saveSingleDiskLimit
1331 getFileValue ctx "$vdir/context"
1332 getFileValue directory "$dlimit/directory" || return 0
1334 local cachename=$ctx$directory
1335 cachename=${cachename//\//_}
1337 # Things are getting ugly here... LFS says that /var/cache (where
1338 # cachename is usually pointing to) can vanish and applications
1339 # have to deal with it. So, we have to interprete the $vdir/cache
1340 # symlink and have to create the needed directories manually.
1341 if test -d "$vdir/cache"; then
1342 : # ok, exists already
1343 elif test -L "$vdir/cache"; then
1344 # it's a dangling symlink
1346 link=$($_READLINK "$vdir/cache")
1347 ( cd $vdir && $_MKDIR -p "$link" )
1352 test -d "$vdir/cache"
1353 $_MKDIR -p "$vdir"/cache/dlimits
1355 $_VDLIMIT --xid $ctx "$directory" | \
1356 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1358 $_VDLIMIT --xid $ctx --remove "$directory"
1362 function saveDiskLimits
1367 test -e "$vdir"/context || return 0
1369 for dlimit in "$vdir/dlimits/"*; do
1370 test -d "$dlimit" || continue
1371 test ! -e "$dlimit/disabled" || continue
1373 _saveSingleDiskLimit "$vdir" "$dlimit"
1377 function _namespaceCleanup
1380 local root=$($_VSERVER_INFO "$1" VDIR 1)
1386 getFileArray skip "$vdir"/namespace-cleanup-skip \
1387 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1389 # these are things that have to be accessible post-cleanup
1390 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1391 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1392 local real=`getPhysicalDir "$i"`
1393 test "$i" != "$real" || real=
1394 for j in "$i" "$real"; do
1395 while test -n "$j"; do
1396 list=( "${list[@]}" "$j" )
1402 local -a list_umount
1403 while read -r dev path opts; do
1404 test -n "$path" || continue
1405 for i in "$root" /dev /proc; do
1407 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1409 for i in "${list[@]}" /; do
1410 test "$path" = "$i" && continue 2
1412 # unmount them in reverse order so mounts further down the tree get unmounted first
1413 list_umount=( "$path" "${list_umount[@]}" )
1415 # separate loop to avoid races while reading /proc/mounts
1416 for i in "${list_umount[@]}"; do
1417 $_UMOUNT -l -n -i "$i"
1421 function handleDeviceMap
1426 local flags device target
1428 test -d "$dir" || return 0
1429 test -n "$xid" || return 0
1431 for i in "$dir"/*; do
1432 test -d "$i" || continue
1434 local -a vdevmap_opts=()
1435 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1436 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1437 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1439 getFileValue flags "$i/flags" || :
1440 getFileValue device "$i/device" || :
1441 getFileValue target "$i/target" || :
1442 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1443 ${device:+--device "$device"} ${target:+--target "$target"} )
1445 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1451 $_GREP -q "cgroup" /proc/filesystems
1454 function _generateCgroupOptions
1458 hasCgroup || return 0
1460 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1461 if test -n "$file"; then
1462 read CGROUP_MNT < "$file"
1464 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1465 if test -n "$file"; then
1466 _readFileToArray CGROUP_SUBSYS "$file"
1468 CGROUP_SUBSYS=( $($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups) )
1470 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1471 if test -n "$file"; then
1472 _readFileToArray CGROUP_INHERIT "$file" ""
1474 findFile file "$__CONFDIR/.defaults/cgroup/base" ""
1475 if test -n "$file"; then
1476 read CGROUP_BASE < "$file"
1477 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
1478 CGROUP_BASE="${CGROUP_BASE}/"
1480 findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
1481 if test -n "$file"; then
1490 hasCgroup || return 1
1491 if test -n "$CGROUP_MNT_PER_SS"; then
1494 for ss in "${CGROUP_SUBSYS[@]}"; do
1495 if test -e "$CGROUP_MNT/$ss/tasks"; then
1496 let existing=${existing}+1
1499 test "$existing" -gt 0 || return 1
1501 test -e "$CGROUP_MNT/tasks" || return 1
1504 if $_VSERVER_INFO - FEATURE memcg; then
1507 test -d "$1/cgroup" -o \
1508 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
1509 ! -e "$1/nocgroup" \)
1512 function _handleCgroup
1524 useCgroup "$vdir" || return 0
1526 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1528 if test -n "$dir" -a -r "$dir"/name; then
1529 read name < "$dir"/name
1531 name="$VSERVER_NAME"
1534 if test -n "$CGROUP_MNT_PER_SS"; then
1536 for ss in "${CGROUP_SUBSYS[@]}"; do
1537 mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
1540 mnts=( "$CGROUP_MNT" )
1542 for mnt in "${mnts[@]}"; do
1543 test -d "$mnt" || continue
1544 if test "$action" = "attach"; then
1545 if test -n "$CGROUP_BASE"; then
1547 i="$mnt/$CGROUP_BASE"
1548 while test "$mnt" != "$i"; do
1549 dirs=( "$i" "${dirs[@]}" )
1552 for i in "${dirs[@]}"; do
1553 if mkdir "$i" 2>/dev/null; then
1555 for j in "${CGROUP_INHERIT[@]}"; do
1556 test -f "$parent/$j" || continue
1557 cat "$parent/$j" > "$i/$j"
1562 if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
1563 parent="$mnt/$CGROUP_BASE$name"
1564 parent="${parent%/*}"
1565 for i in "${CGROUP_INHERIT[@]}"; do
1566 test -f "$parent/$i" || continue
1567 cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i"
1570 if test -n "$dir"; then
1572 for i in "$dir"/*; do
1574 test "$f" != mnt -a "$f" != subsys -a \
1575 "$f" != inherit -a "$f" != name -a "$f" != base -a \
1578 if test -n "$CGROUP_MNT_PER_SS"; then
1580 test "$ss" = "${mnt##*/}" || continue
1582 cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
1586 echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
1587 elif test "$action" = "destroy"; then
1588 rmdir "$mnt/$name" 2>/dev/null || :
1595 function attachToCgroup
1597 _handleCgroup attach "$@"
1600 function destroyCgroup
1602 _handleCgroup destroy "$@"