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 INITCMD_START=( env TERM=$TERM $RC_WRAP "$RUNLEVEL_START" )
348 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
349 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
353 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
354 INITCMD_START=( /etc/rc.multi )
355 INITCMD_STOP=( /etc/rc.shutdown )
356 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
360 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
363 if test x"$INITSTYLE" != xrescue; then
364 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
365 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
366 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
367 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
368 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
371 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
372 INITCMD_START_SYNC=()
377 if vshelper.isEnabled; then
378 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
384 function _generateFlagOptions
389 CHCONTEXT_FLAG_OPTS=()
391 findFile file "$vdir"/cflags "$vdir"/flags ""
401 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
402 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
408 isAvoidNamespace "$vdir" || {
410 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
411 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
412 OPT_VCONTEXT_CHROOT=--pivot-root
416 function _generateChcontextOptions
419 local ctx hostname domainname
424 read ctx <"$vdir"/context || :
426 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
427 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
430 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
432 _generateCapabilityOptions "$vdir"
433 _generateFlagOptions "$vdir"
435 CHCONTEXT_OPTS=( $SILENT_OPT \
436 "${CHCONTEXT_FLAG_OPTS[@]}" \
439 ${ctx:+--ctx "$ctx"} \
440 ${hostname:+--hostname "$hostname"} \
441 ${domainname:+--domainname "$domainname"} )
443 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
444 ${ctx:+--xid "$ctx"} )
445 ## put '--secure' at front so that it can be overridden
446 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
449 function _generateScheduleOptions
452 if test -d "$vdir"/sched; then
453 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
457 local f="$vdir"/schedule
458 test -e "$f" || return 0
460 local fill_rate interval tokens tokens_min tokens_max prio_bias
468 read prio_bias || prio_bias=
472 test -n "$prio_bias" || {
473 echo $"Bad content in '$f'; aborting..." >&2
477 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
478 --tokens "$tokens" --tokens_min "$tokens_min" \
479 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
482 function _getInterfaceValue
492 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
495 : ${_giv_tmp:=$_giv_dflt}
496 eval $_giv_val=\$_giv_tmp
499 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
500 function _transformMask2Prefix
504 test -n "$_tm2p_tmp" || {
505 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
512 function _addInterfaceCmd
514 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
515 let ++INTERFACE_CMDS_IDX
518 ## Usage: _generateMac <var> <iface> <ctx>
519 function _generateMac
522 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
526 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
529 function _getVLANInfo
534 creation of VLAN_PLUS_VID devices is not supported; please create them
535 before starting the vserver and use the 'nodev' flag then"
536 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
540 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
541 create them before starting the vserver and use the 'nodev' flag then"
542 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
544 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
545 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
556 test -e "$iface/tun" -o -e "$iface/tap" || return 1
557 test ! -e "$iface/tun" || echo --tun
558 test ! -e "$iface/tap" || echo --tap
559 test ! -e "$iface/nocsum" || echo --~checksum
560 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
561 if test -e "$iface/uid"; then
563 getFileValue uid "$iface/uid"
566 if test -e "$iface/gid"; then
568 getFileValue gid "$iface/gid"
571 if test -e "$iface/linktype"; then
573 getFileValue linktype "$iface/linktype"
574 echo --linktype "$linktype"
579 ## Usage: _processSingleInterface <interface-directory>
580 function _processSingleInterface
596 _getInterfaceValue ip '' "$iface"
597 _getInterfaceValue extip '' "$iface" "$iface/.."
598 _getInterfaceValue dev '' "$iface" "$iface/.."
599 _getInterfaceValue prefix '' "$iface" "$iface/.."
600 _getInterfaceValue mask '' "$iface" "$iface/.."
601 _getInterfaceValue bcast '' "$iface" "$iface/.."
602 _getInterfaceValue name '' "$iface"
603 _getInterfaceValue scope '' "$iface" "$iface/.."
604 _getInterfaceValue mac '' "$iface"
605 _getInterfaceValue peer '' "$iface"
607 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
608 test -n "$dev" -o -e "$iface"/nodev || {
609 echo $"No device specified for '$iface'" >&2
613 test ! -e "$iface"/down || up=
616 _transformMask2Prefix prefix "$prefix" "$mask"
617 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
619 test ! -e "$iface"/nodev || break
621 test ! -e "$iface"/only_ip || break
623 test -e "$iface/vlandev" \
624 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
625 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
626 -a ! -e "$iface/novlandev" \
627 -a ! -e "$iface/../novlandev" \) && {
629 if vlan_info=$(_getVLANInfo "$dev"); then
630 test -d /proc/net/vlan || {
631 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
634 _addInterfaceCmd VCONFIG $vlan_info
638 if ! test -e "$iface"/indirect; then
640 local use_bcast="broadcast ${bcast:-+}"
641 echo "$ip" | $_GREP -q : && use_bcast=
644 if tun_info=$(_getTunInfo "$iface"); then
645 _addInterfaceCmd TUNCTL "$dev" $tun_info
648 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
649 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
650 _addInterfaceCmd IP_LINK "$dev" $up
651 elif ! test -n "$N_CONTEXT"; then
652 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
655 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
656 _addInterfaceCmd MODPROBE dummy "$dev"
657 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
658 _addInterfaceCmd NAMEIF "$dev" "$mac"
659 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
660 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
667 ## Usage: _generateInterfaceOptions <vserver-directory>
668 function _generateInterfaceOptions
672 # XXX: This is here instead of in _generateChbindOptions
673 # to avoid a circular dependency
674 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
675 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
677 for iface in "$1/interfaces/"*; do
678 test -d "$iface" || continue
679 test ! -e "$iface"/disabled || continue
681 _processSingleInterface "$iface"
683 _HAVE_INTERFACE_OPTIONS=1
686 function enableInterfaces
691 lock "$__LOCKDIR"/vserver.interfaces
693 while test $i -lt $INTERFACE_CMDS_IDX; do
694 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
705 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
707 NAMEIF) $_NAMEIF "$@";;
708 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
709 $_VCONFIG add "$2" "$3" >/dev/null;;
710 IP_ADDR) $_IP addr add "$@";;
711 IP_ADDR_FLUSH) $_IP addr flush "$@";;
712 IP_LINK) $_IP link set "$@";;
713 IP_ROUTE) $_IP route add "$@";;
717 $_TUNCTL --persist "$@" "$dev"
719 *) echo "Unknown interface-command type '$type'" >&2; false;;
728 function disableInterfaces
730 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
732 local i=$INTERFACE_CMDS_IDX
735 lock "$__LOCKDIR"/vserver.interfaces
737 while test $i -gt 0; do
740 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
747 MODPROBE) $_RMMOD "${2:-$1}";;
749 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
750 IP_ADDR) $_IP addr del "$@";;
752 IP_LINK) ;; ## Ignore the link-down command for now
753 IP_ROUTE) $_IP route del "$@";;
754 TUNCTL) $_TUNCTL --~persist "$1";;
755 *) echo "Unknown interface-command type '$type'" >&2; false;;
762 function _generateTagOptions
767 getFileValue tag "$vdir/tag" "$vdir/context"
768 test -n "$tag" || return 0
770 OPTS_VTAG_CREATE=( --tag "$tag" )
771 OPTS_VTAG_ENTER=( --tag "$tag" )
774 function _generateMemctrlOptions
779 getFileValue badness "$vdir/badness"
780 test -n "$badness" || return 0
782 OPTS_VMEMCTRL=( --badness "$badness" )
785 function _generateSpaceOptions
788 local d="$vdir"/spaces
790 ( test ! -e "$d"/pid ) || \
791 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
793 test ! -e "$d"/net || {
794 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
795 # network context and namespace don't make much sense
796 _HAVE_CHBIND_OPTIONS=1
801 getFileValue mask "$d"/mask || \
802 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
805 ## Usage: prepareInit <vserver-directory>
808 pushd "$1/vdir" >/dev/null
811 { find var/run ! -type d -print0; \
812 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
815 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
816 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
821 "${INITCMD_PREPARE[@]}"
825 ## Usage: prepareInit <vserver-directory>
828 pushd "$1/vdir" >/dev/null
831 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
834 "${STOPCMD_PREPARE[@]}"
839 function generateOptions
841 _generateInterfaceOptions "$1"
842 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
843 _generateNiceCommand "$1"
844 _generateIONiceCommand "$1"
845 _generateInitOptions "$1"
846 _generateChcontextOptions "$1"
847 _generateScheduleOptions "$1"
848 _generatePersonalityOptions "$1"
849 _generateTagOptions "$1"
850 _generateMemctrlOptions "$1"
851 _generateSpaceOptions "$1"
852 _generateCgroupOptions
854 if test -n "$_IS_FAKEINIT"; then
855 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
856 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
864 local f="$vdir"/cpuset
868 test -d "$f" || return 0
869 test -e "$f"/name || return 0
871 read cpuset < "$f"/name
872 test -e "$f"/nocreate || {
873 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
874 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
875 if test -e "$f"/"$i"; then
876 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
884 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
885 if [ "$configured" -ne 0 ]; then
887 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
888 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
893 function removeCPUSET
897 local f="$vdir"/cpuset
899 test -d "$f" || return 0
900 test -e "$f"/name || return 0
902 read cpuset < "$f"/name
903 test -e "$f"/nocreate || {
904 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
908 function _mountVserverInternal
913 test -e "$fstab" || return 0
916 pushd "$vdir" >/dev/null
917 # check whether / is mounted readonly or whether there is special
918 # magic regarding the mtab file; when etc/mtab can not be touched,
919 # add the '-n' flag to mount
920 test -w etc -o -w etc/mtab || xflag=-n
921 if test -h etc/mtab; then
922 local l=$($_READLINK etc/mtab)
923 test "${l##/proc/}" = "$l" || xflag=-n
925 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
933 local fstab="$cfgdir"/fstab
936 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 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
946 function mountVserver
955 test -e "$cfgdir"/fstab -o \
956 -e "$cfgdir"/fstab.local -o \
957 -e "$cfgdir"/fstab.remote || return 0
959 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
961 pushd "$vdir" >/dev/null
962 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
965 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
967 _mountVserverInternal "$cfgdir"/fstab
968 _mountVserverInternal "$cfgdir"/fstab.local
969 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
971 isNamespaceCleanup "$cfgdir" && \
972 _namespaceCleanup "$cfgdir"
974 real_vdir=$(getPhysicalDir "$vdir")
975 isAvoidNamespace "$cfgdir" || \
976 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
977 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
978 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
981 function _umountVserverInternal
984 test -e "$fstab" || return 0
989 while read src dst tmp; do
990 test -n "$tmp" || continue
996 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1002 function umountVserver
1008 isAvoidNamespace "$cfgdir" || return 0
1009 test -e "$cfgdir"/fstab -o \
1010 -e "$cfgdir"/fstab.local -o \
1011 -e "$cfgdir"/fstab.remote || return 0
1012 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1014 pushd "$vdir/" >/dev/null || return 1
1015 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1016 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1017 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1018 popd >/dev/null || return 1
1026 local fstab="$cfgdir"/fstab
1030 test -e "$fstab" || return 0
1032 export FSTAB_FILE="$fstab"
1035 test "$fsck_exitcode" -eq 0 -o \
1036 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1039 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1043 test -n "$_NEED_VSHELPER_SYNC" && \
1044 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1046 vshelper.initSync "$1" "$3" "$_is_meth"
1049 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1052 if $_VSERVER_INFO - FEATURE vwait; then
1054 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1057 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1058 --status-fd 3 "$2" \
1059 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1062 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1063 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1064 killContext "$S_CONTEXT" 9
1068 ) 4>$_is_tmpdir/procs &
1070 echo "$!" >$_is_tmpdir/pid
1071 eval "$3"=$_is_tmpdir
1076 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1077 function _waitForVWait
1082 declare -r procs=$(cat $4)
1084 getFileArray status "$2"
1089 'vwait' exited with error '$2' which indicates that vserver could not
1090 be stopped properly"
1093 (KILLED) warning $"\
1094 A timeout occured while waiting for the vserver to finish and it was
1095 killed by sending a SIGKILL signal. Please investigate the reasons
1096 and/or increase the timeout in apps/vshelper/sync-timeout."
1099 (TIMEOUT) warning $"\
1100 A timeout occured while waiting for the vserver to finish and it will
1101 be killed by sending a SIGKILL signal. The following process list
1102 might be useful for finding out the reason of this behavior:
1104 ----------------------------------------------------------------------
1106 }----------------------------------------------------------------------"
1109 (\?\?\?|*) warning $"\
1110 internal error: 'vwait' exited with an unexpected status '$1'; I will
1111 try to continue but be prepared for unexpected events."
1118 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1119 function waitForSync
1123 local vwait_statdir=$3
1126 if test -d "$vwait_statdir"; then
1127 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1128 elif test -n "$_NEED_VSHELPER_SYNC"; then
1129 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1131 A timeout or other error occured while waiting for the synchronization
1132 signal from vserver '$VSERVER_NAME'.
1133 The vserver will be killed nevertheless..."
1134 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1135 "${INITCMD_STOP_SYNC[@]}" || \
1137 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1138 will be killed nevertheless..."
1141 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1145 function _sourceWrap
1147 local vdir name flavor start i already_handled base
1151 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1152 function execScriptlets
1156 declare -r flavor=$3
1159 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1160 local DONT_SKIP_DEFAULTS=
1161 local already_handled=
1163 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1164 isRegularFile "$i" || continue
1165 test -r "$i" || continue
1169 test -x "$i" || start=_sourceWrap
1170 $start "$i" "$flavor" "$name"
1173 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1178 function sanityCheck
1180 declare -r cfgdir=$1
1182 ! test -e "$cfgdir"/fstab.local ||
1184 WARNING: 'fstab' will *not* be executed in the network context of the
1185 vserver anymore. Therefore, 'fstab.local' has the same functionality
1186 and is obsoleted. When you need the old behaviour, put the mounts
1187 into 'fstab.remote'"
1189 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1191 WARNING: The hostname is now configured in 'uts/nodename' but not in
1194 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1196 WARNING: The domainname is now configured in 'uts/domainname' but not
1197 in 'domainname'." >&2
1201 for i in "$cfgdir"/interfaces/*/only_ip; do
1202 if test -e "$i"; then
1204 iface=${i##$cfgdir/interfaces/}
1205 iface=${iface%%/only_ip}
1207 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1212 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1214 WARNING: There is no cachedirectory configured for this vserver;
1215 please create '$cfgdir/cache' e.g. by executing
1217 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1220 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1222 vshelper.doSanityCheck
1224 $_VSERVER_INFO - VERIFYCAP ||
1225 panic $"capabilities are not enabled in kernel-setup"
1227 $_VSERVER_INFO - VERIFYPROC ||
1229 /proc/uptime can not be accessed. Usually, this is caused by
1230 procfs-security. Please read the FAQ for more details
1231 http://linux-vserver.org/Proc-Security"
1233 test -e "$cfgdir"/context || {
1234 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1235 test "$TYPE" != "static" || panic $"\
1236 The kernel does not have dynamic contexts enabled. Please configure
1237 a static one by executing
1239 echo [number between 2 and 49151] > $cfgdir/context"
1244 function _setSingleDiskLimit
1256 getFileValue ctx "$vdir/context"
1257 getFileValue directory "$dlimit/directory" || return 0
1258 getFileValue space_total "$dlimit/space_total" || return 0
1259 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1260 getFileValue reserved "$dlimit/reserved" || return 0
1262 local cachename=$ctx$directory
1263 cachename=dlimits/${cachename//\//_}
1265 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1266 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1267 $_RM -f "$vdir/cache/$cachename"
1269 if test -z "$inodes_used" -o -z "$space_used"; then
1271 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1272 inodes_used=${tmpvdu##* }
1273 space_used=${tmpvdu%% *}
1276 $_VDLIMIT --xid $ctx \
1277 --set space_used=$space_used \
1278 --set space_total=$space_total \
1279 --set inodes_used=$inodes_used \
1280 --set inodes_total=$inodes_total \
1281 --set reserved=$reserved \
1286 function setDiskLimits
1291 # Disk Limits without a static context are useless
1292 test -e "$vdir"/context || return 0
1294 for dlimit in "$vdir/dlimits/"*; do
1295 test -d "$dlimit" || continue
1296 test ! -e "$dlimit/disabled" || continue
1298 _setSingleDiskLimit "$vdir" "$dlimit"
1303 function _saveSingleDiskLimit
1310 getFileValue ctx "$vdir/context"
1311 getFileValue directory "$dlimit/directory" || return 0
1313 local cachename=$ctx$directory
1314 cachename=${cachename//\//_}
1316 # Things are getting ugly here... LFS says that /var/cache (where
1317 # cachename is usually pointing to) can vanish and applications
1318 # have to deal with it. So, we have to interprete the $vdir/cache
1319 # symlink and have to create the needed directories manually.
1320 if test -d "$vdir/cache"; then
1321 : # ok, exists already
1322 elif test -L "$vdir/cache"; then
1323 # it's a dangling symlink
1325 link=$($_READLINK "$vdir/cache")
1326 ( cd $vdir && $_MKDIR -p "$link" )
1331 test -d "$vdir/cache"
1332 $_MKDIR -p "$vdir"/cache/dlimits
1334 $_VDLIMIT --xid $ctx "$directory" | \
1335 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1337 $_VDLIMIT --xid $ctx --remove "$directory"
1341 function saveDiskLimits
1346 test -e "$vdir"/context || return 0
1348 for dlimit in "$vdir/dlimits/"*; do
1349 test -d "$dlimit" || continue
1350 test ! -e "$dlimit/disabled" || continue
1352 _saveSingleDiskLimit "$vdir" "$dlimit"
1356 function _namespaceCleanup
1359 local root=$($_VSERVER_INFO "$1" VDIR 1)
1365 getFileArray skip "$vdir"/namespace-cleanup-skip \
1366 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1368 # these are things that have to be accessible post-cleanup
1369 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1370 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1371 local real=`getPhysicalDir "$i"`
1372 test "$i" != "$real" || real=
1373 for j in "$i" "$real"; do
1374 while test -n "$j"; do
1375 list=( "${list[@]}" "$j" )
1381 local -a list_umount
1382 while read -r dev path opts; do
1383 test -n "$path" || continue
1384 for i in "$root" /dev /proc; do
1385 test "${path#$i}" != "$path" && continue 2
1387 for i in "${list[@]}" /; do
1388 test "$path" = "$i" && continue 2
1390 # unmount them in reverse order so mounts further down the tree get unmounted first
1391 list_umount=( "$path" "${list_umount[@]}" )
1393 # separate loop to avoid races while reading /proc/mounts
1394 for i in "${list_umount[@]}"; do
1395 $_UMOUNT -l -n -i "$i"
1399 function handleDeviceMap
1404 local flags device target
1406 test -d "$dir" || return 0
1407 test -n "$xid" || return 0
1409 for i in "$dir"/*; do
1410 test -d "$i" || continue
1412 local -a vdevmap_opts=()
1413 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1414 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1415 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1417 getFileValue flags "$i/flags" || :
1418 getFileValue device "$i/device" || :
1419 getFileValue target "$i/target" || :
1420 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1421 ${device:+--device "$device"} ${target:+--target "$target"} )
1423 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1429 $_GREP -q "cgroup" /proc/filesystems
1432 function _generateCgroupOptions
1436 hasCgroup || return 0
1438 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1439 if test -n "$file"; then
1440 read CGROUP_MNT < "$file"
1442 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1443 if test -n "$file"; then
1444 read CGROUP_SUBSYS < "$file"
1446 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1447 if test -n "$file"; then
1448 _readFileToArray CGROUP_INHERIT "$file" ""
1456 hasCgroup || return 1
1457 test -d "$CGROUP_MNT" || return 1
1458 test -d "$1/cgroup" -o \
1459 \( -d "$__CONFDIR/.defaults/cgroup" -a \
1460 ! -e "$1/nocgroup" \)
1463 function _handleCgroup
1472 useCgroup "$vdir" || return 0
1474 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1475 test -d "$dir" || return 0
1477 if test -r "$dir"/name; then
1478 read name < "$dir"/name
1480 name="$VSERVER_NAME"
1483 if test "$action" = "attach"; then
1484 if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
1485 parent="$CGROUP_MNT/$name"
1486 parent="${parent%/*}"
1487 for i in "${CGROUP_INHERIT[@]}"; do
1488 test -f "$parent/$i" || continue
1489 cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
1493 for i in "$dir"/*; do
1494 cat "$i" > "$CGROUP_MNT/$name/${i##*/}"
1497 echo "$$" > "$CGROUP_MNT/$name/tasks"
1498 elif test "$action" = "destroy"; then
1499 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1505 function attachToCgroup
1507 _handleCgroup attach "$@"
1510 function destroyCgroup
1512 _handleCgroup destroy "$@"