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 -n "$_IONICE" || return 0
152 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
153 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
155 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
158 function _generatePersonalityOptions
161 local f="$vdir"/personality
164 test -s "$f" || return 0
173 (*) flags=$flags$delim$tmp
180 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
181 --personality-type "$type"
182 ${flags:+--personality-flags "$flags"} )
185 function _generateCCapabilityOptions
189 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
192 function _generateBCapabilityOptions
196 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
199 function _generateCapabilityOptions
204 _generateBCapabilityOptions "$vdir"
205 _generateCCapabilityOptions "$vdir"
207 test -e "$vdir"/capabilities || return 0
216 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
217 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
220 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
223 done <"$vdir"/capabilities
226 function getEnterShell
233 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
235 test -n "$ENTER_SHELL" || {
237 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
239 test -x "$vdir/vdir/$1" || continue
246 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
247 function sendKillSequence
253 while isCtxRunning "$ctx"; do
254 test -z "$wait" || sleep "$wait"
256 killContext "$ctx" "$1"
257 test -n "$2" || break
263 function _generateInitOptions
266 local cfgdir=$vdir/apps/init
271 INITCMD_START_SYNC=()
276 INITKILL_SEQ=( 15 5 9 )
277 CHCONTEXT_INIT_OPTS=()
280 test x"$INITSTYLE" = xrescue || \
281 getFileValue INITSTYLE "$cfgdir"/style
282 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
283 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
284 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
285 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
287 findFile _gio_env "$cfgdir"/environment \
288 "$__CONFDIR"/.defaults/apps/init/environment \
289 "$__PKGLIBDEFAULTDIR"/environment
290 getFileArray OPTS_ENV "$_gio_env" || :
292 case x"$INITSTYLE" in
294 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
295 INITCMD_STOP=( /sbin/killall5 )
299 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
300 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
302 for i in /etc/init.d/rc /etc/rc.d/rc; do
303 test -x "$vdir/vdir/$i" || continue
304 INITCMD_START=( "$i" "$RUNLEVEL_START" )
305 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
307 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
308 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
309 if test -n "$OPTION_DEBUG_SYSV"; then
310 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
311 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
316 INITCMD_START=( /sbin/init )
317 INITCMD_STOP=( /sbin/init )
319 _NEED_VSHELPER_SYNC=1
320 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
321 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
325 INITCMD_START=( /sbin/minit-start )
326 INITCMD_STOP=( /sbin/minit-stop )
328 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
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" )
332 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
336 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
337 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
339 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
340 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
341 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
342 RC_WRAP=/lib/rc/sh/init-vserver.sh
344 panic "init-vserver.sh not found; aborting"
347 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
348 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
349 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
350 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
354 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
355 INITCMD_START=( /etc/rc.multi )
356 INITCMD_STOP=( /etc/rc.shutdown )
357 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
361 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
364 if test x"$INITSTYLE" != xrescue; then
365 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
366 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
367 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
368 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
369 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
372 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
373 INITCMD_START_SYNC=()
378 if vshelper.isEnabled; then
379 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
385 function _generateFlagOptions
390 CHCONTEXT_FLAG_OPTS=()
392 findFile file "$vdir"/cflags "$vdir"/flags ""
402 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
403 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
409 isAvoidNamespace "$vdir" || {
411 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
412 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
413 OPT_VCONTEXT_CHROOT=--pivot-root
417 function _generateChcontextOptions
420 local ctx hostname domainname
425 read ctx <"$vdir"/context || :
427 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
428 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
431 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
433 _generateCapabilityOptions "$vdir"
434 _generateFlagOptions "$vdir"
436 CHCONTEXT_OPTS=( $SILENT_OPT \
437 "${CHCONTEXT_FLAG_OPTS[@]}" \
440 ${ctx:+--ctx "$ctx"} \
441 ${hostname:+--hostname "$hostname"} \
442 ${domainname:+--domainname "$domainname"} )
444 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
445 ${ctx:+--xid "$ctx"} )
446 ## put '--secure' at front so that it can be overridden
447 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
450 function _generateScheduleOptions
453 if test -d "$vdir"/sched; then
454 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
458 local f="$vdir"/schedule
459 test -e "$f" || return 0
461 local fill_rate interval tokens tokens_min tokens_max prio_bias
469 read prio_bias || prio_bias=
473 test -n "$prio_bias" || {
474 echo $"Bad content in '$f'; aborting..." >&2
478 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
479 --tokens "$tokens" --tokens_min "$tokens_min" \
480 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
483 function _getInterfaceValue
493 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
496 : ${_giv_tmp:=$_giv_dflt}
497 eval $_giv_val=\$_giv_tmp
500 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
501 function _transformMask2Prefix
505 test -n "$_tm2p_tmp" || {
506 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
513 function _addInterfaceCmd
515 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
516 let ++INTERFACE_CMDS_IDX
519 ## Usage: _generateMac <var> <iface> <ctx>
520 function _generateMac
523 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
527 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
530 function _getVLANInfo
535 creation of VLAN_PLUS_VID devices is not supported; please create them
536 before starting the vserver and use the 'nodev' flag then"
537 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
541 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
542 create them before starting the vserver and use the 'nodev' flag then"
543 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
545 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
546 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
557 test -e "$iface/tun" -o -e "$iface/tap" || return 1
558 test ! -e "$iface/tun" || echo --tun
559 test ! -e "$iface/tap" || echo --tap
560 test ! -e "$iface/nocsum" || echo --~checksum
561 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
562 if test -e "$iface/uid"; then
564 getFileValue uid "$iface/uid"
567 if test -e "$iface/gid"; then
569 getFileValue gid "$iface/gid"
572 if test -e "$iface/linktype"; then
574 getFileValue linktype "$iface/linktype"
575 echo --linktype "$linktype"
580 ## Usage: _processSingleInterface <interface-directory>
581 function _processSingleInterface
597 _getInterfaceValue ip '' "$iface"
598 _getInterfaceValue extip '' "$iface" "$iface/.."
599 _getInterfaceValue dev '' "$iface" "$iface/.."
600 _getInterfaceValue prefix '' "$iface" "$iface/.."
601 _getInterfaceValue mask '' "$iface" "$iface/.."
602 _getInterfaceValue bcast '' "$iface" "$iface/.."
603 _getInterfaceValue name '' "$iface"
604 _getInterfaceValue scope '' "$iface" "$iface/.."
605 _getInterfaceValue mac '' "$iface"
606 _getInterfaceValue peer '' "$iface"
608 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
609 test -n "$dev" -o -e "$iface"/nodev || {
610 echo $"No device specified for '$iface'" >&2
614 test ! -e "$iface"/down || up=
617 _transformMask2Prefix prefix "$prefix" "$mask"
618 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
620 test ! -e "$iface"/nodev || break
622 test ! -e "$iface"/only_ip || break
624 test -e "$iface/vlandev" \
625 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
626 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
627 -a ! -e "$iface/novlandev" \
628 -a ! -e "$iface/../novlandev" \) && {
630 if vlan_info=$(_getVLANInfo "$dev"); then
631 test -d /proc/net/vlan || {
632 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
635 _addInterfaceCmd VCONFIG $vlan_info
639 if ! test -e "$iface"/indirect; then
641 local use_bcast="broadcast ${bcast:-+}"
642 echo "$ip" | $_GREP -q : && use_bcast=
645 if tun_info=$(_getTunInfo "$iface"); then
646 _addInterfaceCmd TUNCTL "$dev" $tun_info
649 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
650 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
651 _addInterfaceCmd IP_LINK "$dev" $up
652 elif ! test -n "$N_CONTEXT"; then
653 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
656 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
657 _addInterfaceCmd MODPROBE dummy "$dev"
658 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
659 _addInterfaceCmd NAMEIF "$dev" "$mac"
660 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
661 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
668 ## Usage: _generateInterfaceOptions <vserver-directory>
669 function _generateInterfaceOptions
673 # XXX: This is here instead of in _generateChbindOptions
674 # to avoid a circular dependency
675 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
676 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
678 for iface in "$1/interfaces/"*; do
679 test -d "$iface" || continue
680 test ! -e "$iface"/disabled || continue
682 _processSingleInterface "$iface"
684 _HAVE_INTERFACE_OPTIONS=1
687 function enableInterfaces
692 lock "$__LOCKDIR"/vserver.interfaces
694 while test $i -lt $INTERFACE_CMDS_IDX; do
695 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
706 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
708 NAMEIF) $_NAMEIF "$@";;
709 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
710 $_VCONFIG add "$2" "$3" >/dev/null;;
711 IP_ADDR) $_IP addr add "$@";;
712 IP_ADDR_FLUSH) $_IP addr flush "$@";;
713 IP_LINK) $_IP link set "$@";;
714 IP_ROUTE) $_IP route add "$@";;
718 $_TUNCTL --persist "$@" "$dev"
720 *) echo "Unknown interface-command type '$type'" >&2; false;;
729 function disableInterfaces
731 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
733 local i=$INTERFACE_CMDS_IDX
736 lock "$__LOCKDIR"/vserver.interfaces
738 while test $i -gt 0; do
741 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
748 MODPROBE) $_RMMOD "${2:-$1}";;
750 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
751 IP_ADDR) $_IP addr del "$@";;
753 IP_LINK) ;; ## Ignore the link-down command for now
754 IP_ROUTE) $_IP route del "$@";;
755 TUNCTL) $_TUNCTL --~persist "$1";;
756 *) echo "Unknown interface-command type '$type'" >&2; false;;
763 function _generateTagOptions
768 getFileValue tag "$vdir/tag" "$vdir/context"
769 test -n "$tag" || return 0
771 OPTS_VTAG_CREATE=( --tag "$tag" )
772 OPTS_VTAG_ENTER=( --tag "$tag" )
775 function _generateMemctrlOptions
780 getFileValue badness "$vdir/badness"
781 test -n "$badness" || return 0
783 OPTS_VMEMCTRL=( --badness "$badness" )
786 function _generateSpaceOptions
789 local d="$vdir"/spaces
791 ( test ! -e "$d"/pid ) || \
792 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
794 test ! -e "$d"/net || {
795 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
796 # network context and namespace don't make much sense
797 _HAVE_CHBIND_OPTIONS=1
802 getFileValue mask "$d"/mask || \
803 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
806 ## Usage: prepareInit <vserver-directory>
809 pushd "$1/vdir" >/dev/null
812 { $_FIND var/run ! -type d -print0; \
813 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
816 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
817 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
822 "${INITCMD_PREPARE[@]}"
826 ## Usage: prepareInit <vserver-directory>
829 pushd "$1/vdir" >/dev/null
832 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
835 "${STOPCMD_PREPARE[@]}"
840 function generateOptions
842 _generateInterfaceOptions "$1"
843 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
844 _generateNiceCommand "$1"
845 _generateIONiceCommand "$1"
846 _generateInitOptions "$1"
847 _generateChcontextOptions "$1"
848 _generateScheduleOptions "$1"
849 _generatePersonalityOptions "$1"
850 _generateTagOptions "$1"
851 _generateMemctrlOptions "$1"
852 _generateSpaceOptions "$1"
853 _generateCgroupOptions
855 if test -n "$_IS_FAKEINIT"; then
856 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
857 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
865 local f="$vdir"/cpuset
869 test -d "$f" || return 0
870 test -e "$f"/name || return 0
872 read cpuset < "$f"/name
873 test -e "$f"/nocreate || {
874 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
875 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
876 if test -e "$f"/"$i"; then
877 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
885 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
886 if [ "$configured" -ne 0 ]; then
888 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
889 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
894 function removeCPUSET
898 local f="$vdir"/cpuset
900 test -d "$f" || return 0
901 test -e "$f"/name || return 0
903 read cpuset < "$f"/name
904 test -e "$f"/nocreate || {
905 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
909 function _mountVserverInternal
914 test -e "$fstab" || return 0
917 pushd "$vdir" >/dev/null
918 # check whether / is mounted readonly or whether there is special
919 # magic regarding the mtab file; when etc/mtab can not be touched,
920 # add the '-n' flag to mount
921 test -w etc -o -w etc/mtab || xflag=-n
922 if test -h etc/mtab; then
923 local l=$($_READLINK etc/mtab)
924 test "${l##/proc/}" = "$l" || xflag=-n
926 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
934 local fstab="$cfgdir"/fstab
937 test -e "$fstab" || return 0
938 pushd "$vdir" >/dev/null
939 # check whether / is mounted readonly or whether there is special
940 # magic regarding the mtab file; when etc/mtab can not be touched,
941 # add the '-n' flag to mount
942 test -w etc -o -w etc/mtab || xflag=-n
943 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
947 function mountVserver
956 test -e "$cfgdir"/fstab -o \
957 -e "$cfgdir"/fstab.local -o \
958 -e "$cfgdir"/fstab.remote || return 0
960 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
962 pushd "$vdir" >/dev/null
963 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
966 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
968 _mountVserverInternal "$cfgdir"/fstab
969 _mountVserverInternal "$cfgdir"/fstab.local
970 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
972 isNamespaceCleanup "$cfgdir" && \
973 _namespaceCleanup "$cfgdir"
975 real_vdir=$(getPhysicalDir "$vdir")
976 isAvoidNamespace "$cfgdir" || \
977 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
978 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
979 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
982 function _umountVserverInternal
985 test -e "$fstab" || return 0
990 while read src dst tmp; do
991 test -n "$tmp" || continue
997 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1003 function umountVserver
1009 isAvoidNamespace "$cfgdir" || return 0
1010 test -e "$cfgdir"/fstab -o \
1011 -e "$cfgdir"/fstab.local -o \
1012 -e "$cfgdir"/fstab.remote || return 0
1013 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1015 pushd "$vdir/" >/dev/null || return 1
1016 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1017 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1018 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1019 popd >/dev/null || return 1
1027 local fstab="$cfgdir"/fstab
1031 test -e "$fstab" || return 0
1033 export FSTAB_FILE="$fstab"
1036 test "$fsck_exitcode" -eq 0 -o \
1037 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1040 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1044 test -n "$_NEED_VSHELPER_SYNC" && \
1045 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1047 vshelper.initSync "$1" "$3" "$_is_meth"
1050 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1053 if $_VSERVER_INFO - FEATURE vwait; then
1055 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1058 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1059 --status-fd 3 "$2" \
1060 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1063 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1064 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1065 killContext "$S_CONTEXT" 9
1069 ) 4>$_is_tmpdir/procs &
1071 echo "$!" >$_is_tmpdir/pid
1072 eval "$3"=$_is_tmpdir
1077 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1078 function _waitForVWait
1083 declare -r procs=$(cat $4)
1085 getFileArray status "$2"
1090 'vwait' exited with error '$2' which indicates that vserver could not
1091 be stopped properly"
1094 (KILLED) warning $"\
1095 A timeout occured while waiting for the vserver to finish and it was
1096 killed by sending a SIGKILL signal. Please investigate the reasons
1097 and/or increase the timeout in apps/vshelper/sync-timeout."
1100 (TIMEOUT) warning $"\
1101 A timeout occured while waiting for the vserver to finish and it will
1102 be killed by sending a SIGKILL signal. The following process list
1103 might be useful for finding out the reason of this behavior:
1105 ----------------------------------------------------------------------
1107 }----------------------------------------------------------------------"
1110 (\?\?\?|*) warning $"\
1111 internal error: 'vwait' exited with an unexpected status '$1'; I will
1112 try to continue but be prepared for unexpected events."
1119 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1120 function waitForSync
1124 local vwait_statdir=$3
1127 if test -d "$vwait_statdir"; then
1128 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1129 elif test -n "$_NEED_VSHELPER_SYNC"; then
1130 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1132 A timeout or other error occured while waiting for the synchronization
1133 signal from vserver '$VSERVER_NAME'.
1134 The vserver will be killed nevertheless..."
1135 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1136 "${INITCMD_STOP_SYNC[@]}" || \
1138 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1139 will be killed nevertheless..."
1142 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1146 function _sourceWrap
1148 local vdir name flavor start i already_handled base
1152 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1153 function execScriptlets
1157 declare -r flavor=$3
1160 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1161 local DONT_SKIP_DEFAULTS=
1162 local already_handled=
1164 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1165 isRegularFile "$i" || continue
1166 test -r "$i" || continue
1170 test -x "$i" || start=_sourceWrap
1171 $start "$i" "$flavor" "$name"
1174 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1179 function sanityCheck
1181 declare -r cfgdir=$1
1183 ! test -e "$cfgdir"/fstab.local ||
1185 WARNING: 'fstab' will *not* be executed in the network context of the
1186 vserver anymore. Therefore, 'fstab.local' has the same functionality
1187 and is obsoleted. When you need the old behaviour, put the mounts
1188 into 'fstab.remote'"
1190 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1192 WARNING: The hostname is now configured in 'uts/nodename' but not in
1195 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1197 WARNING: The domainname is now configured in 'uts/domainname' but not
1198 in 'domainname'." >&2
1202 for i in "$cfgdir"/interfaces/*/only_ip; do
1203 if test -e "$i"; then
1205 iface=${i##$cfgdir/interfaces/}
1206 iface=${iface%%/only_ip}
1208 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1213 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1215 WARNING: There is no cachedirectory configured for this vserver;
1216 please create '$cfgdir/cache' e.g. by executing
1218 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1221 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1223 vshelper.doSanityCheck
1225 $_VSERVER_INFO - VERIFYCAP ||
1226 panic $"capabilities are not enabled in kernel-setup"
1228 $_VSERVER_INFO - VERIFYPROC ||
1230 /proc/uptime can not be accessed. Usually, this is caused by
1231 procfs-security. Please read the FAQ for more details
1232 http://linux-vserver.org/Proc-Security"
1234 test -e "$cfgdir"/context || {
1235 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1236 test "$TYPE" != "static" || panic $"\
1237 The kernel does not have dynamic contexts enabled. Please configure
1238 a static one by executing
1240 echo [number between 2 and 49151] > $cfgdir/context"
1245 function _setSingleDiskLimit
1257 getFileValue ctx "$vdir/context"
1258 getFileValue directory "$dlimit/directory" || return 0
1259 getFileValue space_total "$dlimit/space_total" || return 0
1260 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1261 getFileValue reserved "$dlimit/reserved" || return 0
1263 local cachename=$ctx$directory
1264 cachename=dlimits/${cachename//\//_}
1266 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1267 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1268 $_RM -f "$vdir/cache/$cachename"
1270 if test -z "$inodes_used" -o -z "$space_used"; then
1272 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1273 inodes_used=${tmpvdu##* }
1274 space_used=${tmpvdu%% *}
1277 $_VDLIMIT --xid $ctx \
1278 --set space_used=$space_used \
1279 --set space_total=$space_total \
1280 --set inodes_used=$inodes_used \
1281 --set inodes_total=$inodes_total \
1282 --set reserved=$reserved \
1287 function setDiskLimits
1292 # Disk Limits without a static context are useless
1293 test -e "$vdir"/context || return 0
1295 for dlimit in "$vdir/dlimits/"*; do
1296 test -d "$dlimit" || continue
1297 test ! -e "$dlimit/disabled" || continue
1299 _setSingleDiskLimit "$vdir" "$dlimit"
1304 function _saveSingleDiskLimit
1311 getFileValue ctx "$vdir/context"
1312 getFileValue directory "$dlimit/directory" || return 0
1314 local cachename=$ctx$directory
1315 cachename=${cachename//\//_}
1317 # Things are getting ugly here... LFS says that /var/cache (where
1318 # cachename is usually pointing to) can vanish and applications
1319 # have to deal with it. So, we have to interprete the $vdir/cache
1320 # symlink and have to create the needed directories manually.
1321 if test -d "$vdir/cache"; then
1322 : # ok, exists already
1323 elif test -L "$vdir/cache"; then
1324 # it's a dangling symlink
1326 link=$($_READLINK "$vdir/cache")
1327 ( cd $vdir && $_MKDIR -p "$link" )
1332 test -d "$vdir/cache"
1333 $_MKDIR -p "$vdir"/cache/dlimits
1335 $_VDLIMIT --xid $ctx "$directory" | \
1336 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1338 $_VDLIMIT --xid $ctx --remove "$directory"
1342 function saveDiskLimits
1347 test -e "$vdir"/context || return 0
1349 for dlimit in "$vdir/dlimits/"*; do
1350 test -d "$dlimit" || continue
1351 test ! -e "$dlimit/disabled" || continue
1353 _saveSingleDiskLimit "$vdir" "$dlimit"
1357 function _namespaceCleanup
1360 local root=$($_VSERVER_INFO "$1" VDIR 1)
1366 getFileArray skip "$vdir"/namespace-cleanup-skip \
1367 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1369 # these are things that have to be accessible post-cleanup
1370 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1371 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1372 local real=`getPhysicalDir "$i"`
1373 test "$i" != "$real" || real=
1374 for j in "$i" "$real"; do
1375 while test -n "$j"; do
1376 list=( "${list[@]}" "$j" )
1382 local -a list_umount
1383 while read -r dev path opts; do
1384 test -n "$path" || continue
1385 for i in "$root" /dev /proc; do
1387 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1389 for i in "${list[@]}" /; do
1390 test "$path" = "$i" && continue 2
1392 # unmount them in reverse order so mounts further down the tree get unmounted first
1393 list_umount=( "$path" "${list_umount[@]}" )
1395 # separate loop to avoid races while reading /proc/mounts
1396 for i in "${list_umount[@]}"; do
1397 $_UMOUNT -l -n -i "$i"
1401 function handleDeviceMap
1406 local flags device target
1408 test -d "$dir" || return 0
1409 test -n "$xid" || return 0
1411 for i in "$dir"/*; do
1412 test -d "$i" || continue
1414 local -a vdevmap_opts=()
1415 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1416 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1417 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1419 getFileValue flags "$i/flags" || :
1420 getFileValue device "$i/device" || :
1421 getFileValue target "$i/target" || :
1422 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1423 ${device:+--device "$device"} ${target:+--target "$target"} )
1425 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1431 $_GREP -q "cgroup" /proc/filesystems
1434 function _generateCgroupOptions
1438 hasCgroup || return 0
1440 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1441 if test -n "$file"; then
1442 read CGROUP_MNT < "$file"
1444 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1445 if test -n "$file"; then
1446 read CGROUP_SUBSYS < "$file"
1447 elif $_GREP -q '^ns[[:space:]]' /proc/cgroups; then
1448 # Hack for the ns subsystem, with which we are incompatible
1449 CGROUP_SUBSYS=$($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups | \
1450 (s=""; while read x; do test -n "$s" && s="$s,"; s="$s$x"; done; echo "$s"))
1452 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1453 if test -n "$file"; then
1454 _readFileToArray CGROUP_INHERIT "$file" ""
1462 hasCgroup || return 1
1463 test -d "$CGROUP_MNT" || return 1
1464 test -d "$1/cgroup" -o \
1465 \( -d "$__CONFDIR/.defaults/cgroup" -a \
1466 ! -e "$1/nocgroup" \)
1469 function _handleCgroup
1478 useCgroup "$vdir" || return 0
1480 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1481 test -d "$dir" || return 0
1483 if test -r "$dir"/name; then
1484 read name < "$dir"/name
1486 name="$VSERVER_NAME"
1489 if test "$action" = "attach"; then
1490 if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
1491 parent="$CGROUP_MNT/$name"
1492 parent="${parent%/*}"
1493 for i in "${CGROUP_INHERIT[@]}"; do
1494 test -f "$parent/$i" || continue
1495 cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
1499 for i in "$dir"/*; do
1501 test "$f" != mnt -a "$f" != subsys -a \
1502 "$f" != inherit -a "$f" != name || continue
1503 cat "$i" > "$CGROUP_MNT/$name/$f"
1506 echo "$$" > "$CGROUP_MNT/$name/tasks"
1507 elif test "$action" = "destroy"; then
1508 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1514 function attachToCgroup
1516 _handleCgroup attach "$@"
1519 function destroyCgroup
1521 _handleCgroup destroy "$@"