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 )
53 declare -a STOPCMD_PREPARE=()
55 declare -a VSERVER_EXTRA_CMDS=()
58 VSHELPER_SYNC_TIMEOUT=30
63 _HAVE_INTERFACE_OPTIONS=
75 CGROUP_MNT=/dev/cgroup
77 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
79 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
81 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
87 function _readFileToArray
94 test -e "$_rfta_f" || return 0
95 while read _rfta_v; do
98 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
103 function _generateChbindOptions
111 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
113 local f="$vdir"/interfaces/bcast
114 getFileValue bcast "$f"
115 f="$vdir"/interfaces/lback
116 getFileValue lback "$f"
118 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
119 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
122 for i in "${INTERFACES[@]}"; do
123 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
126 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
127 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
129 _HAVE_CHBIND_OPTIONS=1
132 function _generateNiceCommand
136 local current_nice=`$_NICE`
138 test -r "$vdir/nice" && read nice <"$vdir"/nice
140 let nice=$nice-$current_nice || :
141 NICE_CMD=( $_NICE -n $nice )
144 function _generateIONiceCommand
148 local ionice_priority=0
150 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
151 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
153 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
156 function _generatePersonalityOptions
159 local f="$vdir"/personality
162 test -s "$f" || return 0
171 (*) flags=$flags$delim$tmp
178 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
179 --personality-type "$type"
180 ${flags:+--personality-flags "$flags"} )
183 function _generateCCapabilityOptions
187 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
190 function _generateBCapabilityOptions
194 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
197 function _generateCapabilityOptions
202 _generateBCapabilityOptions "$vdir"
203 _generateCCapabilityOptions "$vdir"
205 test -e "$vdir"/capabilities || return 0
214 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
215 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
218 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
221 done <"$vdir"/capabilities
224 function getEnterShell
231 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
233 test -n "$ENTER_SHELL" || {
235 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
237 test -x "$vdir/vdir/$1" || continue
244 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
245 function sendKillSequence
251 while isCtxRunning "$ctx"; do
252 test -z "$wait" || sleep "$wait"
254 killContext "$ctx" "$1"
255 test -n "$2" || break
261 function _generateInitOptions
264 local cfgdir=$vdir/apps/init
269 INITCMD_START_SYNC=()
274 INITKILL_SEQ=( 15 5 9 )
275 CHCONTEXT_INIT_OPTS=()
278 test x"$INITSTYLE" = xrescue || \
279 getFileValue INITSTYLE "$cfgdir"/style
280 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
281 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
282 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
283 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
285 findFile _gio_env "$cfgdir"/environment \
286 "$__CONFDIR"/.defaults/apps/init/environment \
287 "$__PKGLIBDEFAULTDIR"/environment
288 getFileArray OPTS_ENV "$_gio_env" || :
290 case x"$INITSTYLE" in
292 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
293 INITCMD_STOP=( /sbin/killall5 )
297 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
298 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
300 for i in /etc/init.d/rc /etc/rc.d/rc; do
301 test -x "$vdir/vdir/$i" || continue
302 INITCMD_START=( "$i" "$RUNLEVEL_START" )
303 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
305 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
306 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
307 if test -n "$OPTION_DEBUG_SYSV"; then
308 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
309 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
314 INITCMD_START=( /sbin/init )
315 INITCMD_STOP=( /sbin/init )
317 _NEED_VSHELPER_SYNC=1
318 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
319 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
323 INITCMD_START=( /sbin/minit-start )
324 INITCMD_STOP=( /sbin/minit-stop )
326 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
327 _NEED_VSHELPER_SYNC=1
328 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
329 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
330 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
334 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
335 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
337 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
338 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
339 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
340 RC_WRAP=/lib/rc/sh/init-vserver.sh
342 panic "init-vserver.sh not found; aborting"
345 INITCMD_START=( env TERM=$TERM $RC_WRAP "$RUNLEVEL_START" )
346 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
347 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
351 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
352 INITCMD_START=( /etc/rc.multi )
353 INITCMD_STOP=( /etc/rc.shutdown )
354 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
358 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
361 if test x"$INITSTYLE" != xrescue; then
362 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
363 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
364 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
365 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
366 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
369 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
370 INITCMD_START_SYNC=()
375 if vshelper.isEnabled; then
376 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
382 function _generateFlagOptions
387 CHCONTEXT_FLAG_OPTS=()
389 findFile file "$vdir"/cflags "$vdir"/flags ""
399 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
400 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
406 isAvoidNamespace "$vdir" || {
408 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
409 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
410 OPT_VCONTEXT_CHROOT=--pivot-root
414 function _generateChcontextOptions
417 local ctx hostname domainname
422 read ctx <"$vdir"/context || :
424 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
425 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
428 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
430 _generateCapabilityOptions "$vdir"
431 _generateFlagOptions "$vdir"
433 CHCONTEXT_OPTS=( $SILENT_OPT \
434 "${CHCONTEXT_FLAG_OPTS[@]}" \
437 ${ctx:+--ctx "$ctx"} \
438 ${hostname:+--hostname "$hostname"} \
439 ${domainname:+--domainname "$domainname"} )
441 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
442 ${ctx:+--xid "$ctx"} )
443 ## put '--secure' at front so that it can be overridden
444 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
447 function _generateScheduleOptions
450 if test -d "$vdir"/sched; then
451 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
455 local f="$vdir"/schedule
456 test -e "$f" || return 0
458 local fill_rate interval tokens tokens_min tokens_max prio_bias
466 read prio_bias || prio_bias=
470 test -n "$prio_bias" || {
471 echo $"Bad content in '$f'; aborting..." >&2
475 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
476 --tokens "$tokens" --tokens_min "$tokens_min" \
477 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
480 function _getInterfaceValue
490 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
493 : ${_giv_tmp:=$_giv_dflt}
494 eval $_giv_val=\$_giv_tmp
497 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
498 function _transformMask2Prefix
502 test -n "$_tm2p_tmp" || {
503 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
510 function _addInterfaceCmd
512 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
513 let ++INTERFACE_CMDS_IDX
516 ## Usage: _generateMac <var> <iface> <ctx>
517 function _generateMac
520 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
524 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
527 function _getVLANInfo
532 creation of VLAN_PLUS_VID devices is not supported; please create them
533 before starting the vserver and use the 'nodev' flag then"
534 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
538 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
539 create them before starting the vserver and use the 'nodev' flag then"
540 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
542 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
543 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
554 test -e "$iface/tun" -o -e "$iface/tap" || return 1
555 test ! -e "$iface/tun" || echo --tun
556 test ! -e "$iface/tap" || echo --tap
557 test ! -e "$iface/nocsum" || echo --~checksum
558 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
559 if test -e "$iface/uid"; then
561 getFileValue uid "$iface/uid"
564 if test -e "$iface/gid"; then
566 getFileValue gid "$iface/gid"
569 if test -e "$iface/linktype"; then
571 getFileValue linktype "$iface/linktype"
572 echo --linktype "$linktype"
577 ## Usage: _processSingleInterface <interface-directory>
578 function _processSingleInterface
594 _getInterfaceValue ip '' "$iface"
595 _getInterfaceValue extip '' "$iface" "$iface/.."
596 _getInterfaceValue dev '' "$iface" "$iface/.."
597 _getInterfaceValue prefix '' "$iface" "$iface/.."
598 _getInterfaceValue mask '' "$iface" "$iface/.."
599 _getInterfaceValue bcast '' "$iface" "$iface/.."
600 _getInterfaceValue name '' "$iface"
601 _getInterfaceValue scope '' "$iface" "$iface/.."
602 _getInterfaceValue mac '' "$iface"
603 _getInterfaceValue peer '' "$iface"
605 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
606 test -n "$dev" -o -e "$iface"/nodev || {
607 echo $"No device specified for '$iface'" >&2
611 test ! -e "$iface"/down || up=
614 _transformMask2Prefix prefix "$prefix" "$mask"
615 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
617 test ! -e "$iface"/nodev || break
619 test ! -e "$iface"/only_ip || break
621 test -e "$iface/vlandev" \
622 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
623 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
624 -a ! -e "$iface/novlandev" \
625 -a ! -e "$iface/../novlandev" \) && {
627 if vlan_info=$(_getVLANInfo "$dev"); then
628 test -d /proc/net/vlan || {
629 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
632 _addInterfaceCmd VCONFIG $vlan_info
636 if ! test -e "$iface"/indirect; then
638 local use_bcast="broadcast ${bcast:-+}"
639 echo "$ip" | $_GREP -q : && use_bcast=
642 if tun_info=$(_getTunInfo "$iface"); then
643 _addInterfaceCmd TUNCTL "$dev" $tun_info
646 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
647 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
648 _addInterfaceCmd IP_LINK "$dev" $up
649 elif ! test -n "$N_CONTEXT"; then
650 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
653 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
654 _addInterfaceCmd MODPROBE dummy "$dev"
655 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
656 _addInterfaceCmd NAMEIF "$dev" "$mac"
657 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
658 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
665 ## Usage: _generateInterfaceOptions <vserver-directory>
666 function _generateInterfaceOptions
670 # XXX: This is here instead of in _generateChbindOptions
671 # to avoid a circular dependency
672 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
673 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
675 for iface in "$1/interfaces/"*; do
676 test -d "$iface" || continue
677 test ! -e "$iface"/disabled || continue
679 _processSingleInterface "$iface"
681 _HAVE_INTERFACE_OPTIONS=1
684 function enableInterfaces
689 lock "$__LOCKDIR"/vserver.interfaces
691 while test $i -lt $INTERFACE_CMDS_IDX; do
692 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
703 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
705 NAMEIF) $_NAMEIF "$@";;
706 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
707 $_VCONFIG add "$2" "$3" >/dev/null;;
708 IP_ADDR) $_IP addr add "$@";;
709 IP_ADDR_FLUSH) $_IP addr flush "$@";;
710 IP_LINK) $_IP link set "$@";;
711 IP_ROUTE) $_IP route add "$@";;
715 $_TUNCTL --persist "$@" "$dev"
717 *) echo "Unknown interface-command type '$type'" >&2; false;;
726 function disableInterfaces
728 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
730 local i=$INTERFACE_CMDS_IDX
733 lock "$__LOCKDIR"/vserver.interfaces
735 while test $i -gt 0; do
738 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
745 MODPROBE) $_RMMOD "${2:-$1}";;
747 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
748 IP_ADDR) $_IP addr del "$@";;
750 IP_LINK) ;; ## Ignore the link-down command for now
751 IP_ROUTE) $_IP route del "$@";;
752 TUNCTL) $_TUNCTL --~persist "$1";;
753 *) echo "Unknown interface-command type '$type'" >&2; false;;
760 function _generateTagOptions
765 getFileValue tag "$vdir/tag" "$vdir/context"
766 test -n "$tag" || return 0
768 OPTS_VTAG_CREATE=( --tag "$tag" )
769 OPTS_VTAG_ENTER=( --tag "$tag" )
772 function _generateMemctrlOptions
777 getFileValue badness "$vdir/badness"
778 test -n "$badness" || return 0
780 OPTS_VMEMCTRL=( --badness "$badness" )
783 function _generateSpaceOptions
786 local d="$vdir"/spaces
788 ( test ! -e "$d"/pid ) || \
789 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
791 test ! -e "$d"/net || {
792 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
793 # network context and namespace don't make much sense
794 _HAVE_CHBIND_OPTIONS=1
799 getFileValue mask "$d"/mask || \
800 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
803 ## Usage: prepareInit <vserver-directory>
806 pushd "$1/vdir" >/dev/null
809 { find var/run ! -type d -print0; \
810 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
813 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
814 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
819 "${INITCMD_PREPARE[@]}"
823 ## Usage: prepareInit <vserver-directory>
826 pushd "$1/vdir" >/dev/null
829 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
832 "${STOPCMD_PREPARE[@]}"
837 function generateOptions
839 _generateInterfaceOptions "$1"
840 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
841 _generateNiceCommand "$1"
842 _generateIONiceCommand "$1"
843 _generateInitOptions "$1"
844 _generateChcontextOptions "$1"
845 _generateScheduleOptions "$1"
846 _generatePersonalityOptions "$1"
847 _generateTagOptions "$1"
848 _generateMemctrlOptions "$1"
849 _generateSpaceOptions "$1"
850 _generateCgroupOptions
852 if test -n "$_IS_FAKEINIT"; then
853 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
854 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
862 local f="$vdir"/cpuset
866 test -d "$f" || return 0
867 test -e "$f"/name || return 0
869 read cpuset < "$f"/name
870 test -e "$f"/nocreate || {
871 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
872 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
873 if test -e "$f"/"$i"; then
874 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
882 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
883 if [ "$configured" -ne 0 ]; then
885 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
886 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
891 function removeCPUSET
895 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 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
906 function _mountVserverInternal
911 test -e "$fstab" || return 0
914 pushd "$vdir" >/dev/null
915 # check whether / is mounted readonly or whether there is special
916 # magic regarding the mtab file; when etc/mtab can not be touched,
917 # add the '-n' flag to mount
918 test -w etc -o -w etc/mtab || xflag=-n
919 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
927 local fstab="$cfgdir"/fstab
930 test -e "$fstab" || return 0
931 pushd "$vdir" >/dev/null
932 # check whether / is mounted readonly or whether there is special
933 # magic regarding the mtab file; when etc/mtab can not be touched,
934 # add the '-n' flag to mount
935 test -w etc -o -w etc/mtab || xflag=-n
936 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
940 function mountVserver
949 test -e "$cfgdir"/fstab -o \
950 -e "$cfgdir"/fstab.local -o \
951 -e "$cfgdir"/fstab.remote || return 0
953 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
955 pushd "$vdir" >/dev/null
956 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
959 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
961 _mountVserverInternal "$cfgdir"/fstab
962 _mountVserverInternal "$cfgdir"/fstab.local
963 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
965 isNamespaceCleanup "$cfgdir" && \
966 _namespaceCleanup "$cfgdir"
968 real_vdir=$(getPhysicalDir "$vdir")
969 isAvoidNamespace "$cfgdir" || \
970 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
971 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
972 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
975 function _umountVserverInternal
978 test -e "$fstab" || return 0
983 while read src dst tmp; do
984 test -n "$tmp" || continue
990 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
996 function umountVserver
1002 isAvoidNamespace "$cfgdir" || return 0
1003 test -e "$cfgdir"/fstab -o \
1004 -e "$cfgdir"/fstab.local -o \
1005 -e "$cfgdir"/fstab.remote || return 0
1006 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1008 pushd "$vdir/" >/dev/null || return 1
1009 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1010 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1011 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1012 popd >/dev/null || return 1
1020 local fstab="$cfgdir"/fstab
1024 test -e "$fstab" || return 0
1026 export FSTAB_FILE="$fstab"
1029 test "$fsck_exitcode" -eq 0 -o \
1030 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1033 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1037 test -n "$_NEED_VSHELPER_SYNC" && \
1038 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1040 vshelper.initSync "$1" "$3" "$_is_meth"
1043 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1046 if $_VSERVER_INFO - FEATURE vwait; then
1048 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1051 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1052 --status-fd 3 "$2" \
1053 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1056 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1057 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1058 killContext "$S_CONTEXT" 9
1062 ) 4>$_is_tmpdir/procs &
1064 echo "$!" >$_is_tmpdir/pid
1065 eval "$3"=$_is_tmpdir
1070 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1071 function _waitForVWait
1076 declare -r procs=$(cat $4)
1078 getFileArray status "$2"
1083 'vwait' exited with error '$2' which indicates that vserver could not
1084 be stopped properly"
1087 (KILLED) warning $"\
1088 A timeout occured while waiting for the vserver to finish and it was
1089 killed by sending a SIGKILL signal. Please investigate the reasons
1090 and/or increase the timeout in apps/vshelper/sync-timeout."
1093 (TIMEOUT) warning $"\
1094 A timeout occured while waiting for the vserver to finish and it will
1095 be killed by sending a SIGKILL signal. The following process list
1096 might be useful for finding out the reason of this behavior:
1098 ----------------------------------------------------------------------
1100 }----------------------------------------------------------------------"
1103 (\?\?\?|*) warning $"\
1104 internal error: 'vwait' exited with an unexpected status '$1'; I will
1105 try to continue but be prepared for unexpected events."
1112 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1113 function waitForSync
1117 local vwait_statdir=$3
1120 if test -d "$vwait_statdir"; then
1121 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1122 elif test -n "$_NEED_VSHELPER_SYNC"; then
1123 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1125 A timeout or other error occured while waiting for the synchronization
1126 signal from vserver '$VSERVER_NAME'.
1127 The vserver will be killed nevertheless..."
1128 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1129 "${INITCMD_STOP_SYNC[@]}" || \
1131 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1132 will be killed nevertheless..."
1135 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1139 function _sourceWrap
1141 local vdir name flavor start i already_handled base
1145 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1146 function execScriptlets
1150 declare -r flavor=$3
1153 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1154 local DONT_SKIP_DEFAULTS=
1155 local already_handled=
1157 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1158 isRegularFile "$i" || continue
1159 test -r "$i" || continue
1163 test -x "$i" || start=_sourceWrap
1164 $start "$i" "$flavor" "$name"
1167 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1172 function sanityCheck
1174 declare -r cfgdir=$1
1176 ! test -e "$cfgdir"/fstab.local ||
1178 WARNING: 'fstab' will *not* be executed in the network context of the
1179 vserver anymore. Therefore, 'fstab.local' has the same functionality
1180 and is obsoleted. When you need the old behaviour, put the mounts
1181 into 'fstab.remote'"
1183 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1185 WARNING: The hostname is now configured in 'uts/nodename' but not in
1188 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1190 WARNING: The domainname is now configured in 'uts/domainname' but not
1191 in 'domainname'." >&2
1195 for i in "$cfgdir"/interfaces/*/only_ip; do
1196 if test -e "$i"; then
1198 iface=${i##$cfgdir/interfaces/}
1199 iface=${iface%%/only_ip}
1201 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1206 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1208 WARNING: There is no cachedirectory configured for this vserver;
1209 please create '$cfgdir/cache' e.g. by executing
1211 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1214 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1216 vshelper.doSanityCheck
1218 $_VSERVER_INFO - VERIFYCAP ||
1219 panic $"capabilities are not enabled in kernel-setup"
1221 $_VSERVER_INFO - VERIFYPROC ||
1223 /proc/uptime can not be accessed. Usually, this is caused by
1224 procfs-security. Please read the FAQ for more details
1225 http://linux-vserver.org/Proc-Security"
1227 test -e "$cfgdir"/context || {
1228 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1229 test "$TYPE" != "static" || panic $"\
1230 The kernel does not have dynamic contexts enabled. Please configure
1231 a static one by executing
1233 echo [number between 2 and 49151] > $cfgdir/context"
1238 function _setSingleDiskLimit
1250 getFileValue ctx "$vdir/context"
1251 getFileValue directory "$dlimit/directory" || return 0
1252 getFileValue space_total "$dlimit/space_total" || return 0
1253 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1254 getFileValue reserved "$dlimit/reserved" || return 0
1256 local cachename=$ctx$directory
1257 cachename=dlimits/${cachename//\//_}
1259 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1260 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1261 $_RM -f "$vdir/cache/$cachename"
1263 if test -z "$inodes_used" -o -z "$space_used"; then
1265 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1266 inodes_used=${tmpvdu##* }
1267 space_used=${tmpvdu%% *}
1270 $_VDLIMIT --xid $ctx \
1271 --set space_used=$space_used \
1272 --set space_total=$space_total \
1273 --set inodes_used=$inodes_used \
1274 --set inodes_total=$inodes_total \
1275 --set reserved=$reserved \
1280 function setDiskLimits
1285 # Disk Limits without a static context are useless
1286 test -e "$vdir"/context || return 0
1288 for dlimit in "$vdir/dlimits/"*; do
1289 test -d "$dlimit" || continue
1290 test ! -e "$dlimit/disabled" || continue
1292 _setSingleDiskLimit "$vdir" "$dlimit"
1297 function _saveSingleDiskLimit
1304 getFileValue ctx "$vdir/context"
1305 getFileValue directory "$dlimit/directory" || return 0
1307 local cachename=$ctx$directory
1308 cachename=${cachename//\//_}
1310 # Things are getting ugly here... LFS says that /var/cache (where
1311 # cachename is usually pointing to) can vanish and applications
1312 # have to deal with it. So, we have to interprete the $vdir/cache
1313 # symlink and have to create the needed directories manually.
1314 if test -d "$vdir/cache"; then
1315 : # ok, exists already
1316 elif test -L "$vdir/cache"; then
1317 # it's a dangling symlink
1319 link=$($_READLINK "$vdir/cache")
1320 ( cd $vdir && $_MKDIR -p "$link" )
1325 test -d "$vdir/cache"
1326 $_MKDIR -p "$vdir"/cache/dlimits
1328 $_VDLIMIT --xid $ctx "$directory" | \
1329 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1331 $_VDLIMIT --xid $ctx --remove "$directory"
1335 function saveDiskLimits
1340 test -e "$vdir"/context || return 0
1342 for dlimit in "$vdir/dlimits/"*; do
1343 test -d "$dlimit" || continue
1344 test ! -e "$dlimit/disabled" || continue
1346 _saveSingleDiskLimit "$vdir" "$dlimit"
1350 function _namespaceCleanup
1353 local root=$($_VSERVER_INFO "$1" VDIR 1)
1359 getFileArray skip "$vdir"/namespace-cleanup-skip \
1360 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1362 # these are things that have to be accessible post-cleanup
1363 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1364 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1365 local real=`getPhysicalDir "$i"`
1366 test "$i" != "$real" || real=
1367 for j in "$i" "$real"; do
1368 while test -n "$j"; do
1369 list=( "${list[@]}" "$j" )
1375 local -a list_umount
1376 while read -r dev path opts; do
1377 test -n "$path" || continue
1378 for i in "$root" /dev /proc; do
1379 test "${path#$i}" != "$path" && continue 2
1381 for i in "${list[@]}" /; do
1382 test "$path" = "$i" && continue 2
1384 # unmount them in reverse order so mounts further down the tree get unmounted first
1385 list_umount=( "$path" "${list_umount[@]}" )
1387 # separate loop to avoid races while reading /proc/mounts
1388 for i in "${list_umount[@]}"; do
1389 $_UMOUNT -l -n -i "$i"
1393 function handleDeviceMap
1398 local flags device target
1400 test -d "$dir" || return 0
1401 test -n "$xid" || return 0
1403 for i in "$dir"/*; do
1404 test -d "$i" || continue
1406 local -a vdevmap_opts=()
1407 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1408 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1409 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1411 getFileValue flags "$i/flags" || :
1412 getFileValue device "$i/device" || :
1413 getFileValue target "$i/target" || :
1414 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1415 ${device:+--device "$device"} ${target:+--target "$target"} )
1417 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1423 $_GREP -q "cgroup" /proc/filesystems
1426 function _generateCgroupOptions
1430 hasCgroup || return 0
1432 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1433 if test -n "$file"; then
1434 read CGROUP_MNT < "$file"
1436 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1437 if test -n "$file"; then
1438 read CGROUP_SUBSYS < "$file"
1440 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1441 if test -n "$file"; then
1442 _readFileToArray CGROUP_INHERIT "$file" ""
1450 hasCgroup || return 1
1451 test -d "$CGROUP_MNT" || return 1
1452 test -d "$1/cgroup" -o \
1453 \( -d "$__CONFDIR/.defaults/cgroup" -a \
1454 ! -e "$1/nocgroup" \)
1457 function _handleCgroup
1466 useCgroup "$vdir" || return 0
1468 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1469 test -d "$dir" || return 0
1471 if test -r "$dir"/name; then
1472 read name < "$dir"/name
1474 name="$VSERVER_NAME"
1477 if test "$action" = "attach"; then
1478 if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
1479 parent="$CGROUP_MNT/$name"
1480 parent="${parent%/*}"
1481 for i in "${CGROUP_INHERIT[@]}"; do
1482 test -f "$parent/$i" || continue
1483 cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
1487 for i in "$dir"/*; do
1488 cat "$i" > "$CGROUP_MNT/$name/${i##*/}"
1491 echo "$$" > "$CGROUP_MNT/$name/tasks"
1492 elif test "$action" = "destroy"; then
1493 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1499 function attachToCgroup
1501 _handleCgroup attach "$@"
1504 function destroyCgroup
1506 _handleCgroup destroy "$@"