3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # $VSERVER_DIR ... path to vserver-cfg dir
20 # $VSERVER_NAME ... name of vserver
22 declare -a NICE_CMD=()
23 declare -a IONICE_CMD=()
24 declare -a CHBIND_CMD=()
25 declare -a CAP_OPTS=()
26 declare -a CHCONTEXT_INIT_OPTS=()
27 declare -a CHCONTEXT_FLAG_OPTS=()
28 declare -a CHCONTEXT_OPTS=()
29 declare -a CAPCHROOT_OPTS=()
30 declare -a INTERFACES=()
32 declare -a INITCMD_RESCUE=( /bin/sleep 900 )
33 declare -a INITCMD_START=()
34 declare -a INITCMD_START_SYNC=()
35 declare -a INITCMD_STOP=()
36 declare -a INITCMD_STOP_SYNC=()
37 declare -a INITCMD_PREPARE=()
38 declare -a INITKILL_SEQ=()
39 declare -a ENTER_SHELL=()
41 declare -a OPTS_VCONTEXT_CREATE=()
42 declare -a OPTS_VCONTEXT_MIGRATE=()
43 declare -a OPTS_VCONTEXT_ENTER=()
44 OPT_VCONTEXT_CHROOT=--chroot
45 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
46 declare -a OPTS_VSCHED=()
47 declare -a OPTS_ENV=()
48 declare -a OPTS_VTAG_CREATE=()
49 declare -a OPTS_VTAG_ENTER=()
50 declare -a OPTS_VMEMCTRL=()
51 declare -a OPTS_VSPACE=( --default )
52 declare -a OPTS_VSPACE_SHARED=()
53 declare -a VSPACE_SHARED_CMD=()
55 declare -a STOPCMD_PREPARE=()
57 declare -a VSERVER_EXTRA_CMDS=()
60 VSHELPER_SYNC_TIMEOUT=30
65 _HAVE_INTERFACE_OPTIONS=
77 CGROUP_MNT=/dev/cgroup
79 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
81 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
83 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
89 function _readFileToArray
96 test -e "$_rfta_f" || return 0
97 while read _rfta_v; do
100 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
105 function _generateChbindOptions
113 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
115 if test -e "$vdir"/noncontext -o
116 \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
117 _HAVE_CHBIND_OPTIONS=1
121 local f="$vdir"/interfaces/bcast
122 getFileValue bcast "$f"
123 f="$vdir"/interfaces/lback
124 getFileValue lback "$f"
126 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
127 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
130 for i in "${INTERFACES[@]}"; do
131 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
134 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
135 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
137 _HAVE_CHBIND_OPTIONS=1
140 function _generateNiceCommand
144 local current_nice=`$_NICE`
146 test -r "$vdir/nice" && read nice <"$vdir"/nice
148 let nice=$nice-$current_nice || :
149 NICE_CMD=( $_NICE -n $nice )
152 function _generateIONiceCommand
156 local ionice_priority=0
158 test -n "$_IONICE" || return 0
160 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
161 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
163 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
166 function _generatePersonalityOptions
169 local f="$vdir"/personality
172 test -s "$f" || return 0
181 (*) flags=$flags$delim$tmp
188 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
189 --personality-type "$type"
190 ${flags:+--personality-flags "$flags"} )
193 function _generateCCapabilityOptions
197 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
200 function _generateBCapabilityOptions
204 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
207 function _generateCapabilityOptions
212 _generateBCapabilityOptions "$vdir"
213 _generateCCapabilityOptions "$vdir"
215 test -e "$vdir"/capabilities || return 0
224 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
225 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
228 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
231 done <"$vdir"/capabilities
234 function getEnterShell
241 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
243 test -n "$ENTER_SHELL" || {
245 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
247 test -x "$vdir/vdir/$1" || continue
254 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
255 function sendKillSequence
261 while isCtxRunning "$ctx"; do
262 test -z "$wait" || sleep "$wait"
264 killContext "$ctx" "$1"
265 test -n "$2" || break
271 function _generateInitOptions
274 local cfgdir=$vdir/apps/init
279 INITCMD_START_SYNC=()
284 INITKILL_SEQ=( 15 5 9 )
285 CHCONTEXT_INIT_OPTS=()
288 test x"$INITSTYLE" = xrescue || \
289 getFileValue INITSTYLE "$cfgdir"/style
290 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
291 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
292 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
293 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
295 findFile _gio_env "$cfgdir"/environment \
296 "$__CONFDIR"/.defaults/apps/init/environment \
297 "$__PKGLIBDEFAULTDIR"/environment
298 getFileArray OPTS_ENV "$_gio_env" || :
300 case x"$INITSTYLE" in
302 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
303 INITCMD_STOP=( /sbin/killall5 )
307 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
308 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
310 for i in /etc/init.d/rc /etc/rc.d/rc; do
311 test -x "$vdir/vdir/$i" || continue
312 INITCMD_START=( "$i" "$RUNLEVEL_START" )
313 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
315 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
316 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
317 if test -n "$OPTION_DEBUG_SYSV"; then
318 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
319 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
324 INITCMD_START=( /sbin/init )
325 INITCMD_STOP=( /sbin/init )
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" )
333 INITCMD_START=( /sbin/minit-start )
334 INITCMD_STOP=( /sbin/minit-stop )
336 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
337 _NEED_VSHELPER_SYNC=1
338 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
339 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
340 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
344 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
345 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
347 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
348 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
349 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
350 RC_WRAP=/lib/rc/sh/init-vserver.sh
352 panic "init-vserver.sh not found; aborting"
355 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
356 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
357 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
358 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
362 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
363 INITCMD_START=( /etc/rc.multi )
364 INITCMD_STOP=( /etc/rc.shutdown )
365 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
369 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
372 if test x"$INITSTYLE" != xrescue; then
373 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
374 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
375 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
376 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
377 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
380 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
381 INITCMD_START_SYNC=()
386 if vshelper.isEnabled; then
387 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
393 function _generateFlagOptions
398 CHCONTEXT_FLAG_OPTS=()
400 findFile file "$vdir"/cflags "$vdir"/flags ""
410 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
411 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
417 isAvoidNamespace "$vdir" || {
419 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
420 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
421 OPT_VCONTEXT_CHROOT=--pivot-root
425 function _generateChcontextOptions
428 local ctx hostname domainname
433 read ctx <"$vdir"/context || :
435 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
436 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
439 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
441 _generateCapabilityOptions "$vdir"
442 _generateFlagOptions "$vdir"
444 CHCONTEXT_OPTS=( $SILENT_OPT \
445 "${CHCONTEXT_FLAG_OPTS[@]}" \
448 ${ctx:+--ctx "$ctx"} \
449 ${hostname:+--hostname "$hostname"} \
450 ${domainname:+--domainname "$domainname"} )
452 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
453 ${ctx:+--xid "$ctx"} )
454 ## put '--secure' at front so that it can be overridden
455 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
458 function _generateScheduleOptions
461 if test -d "$vdir"/sched; then
462 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
466 local f="$vdir"/schedule
467 test -e "$f" || return 0
469 local fill_rate interval tokens tokens_min tokens_max prio_bias
477 read prio_bias || prio_bias=
481 test -n "$prio_bias" || {
482 echo $"Bad content in '$f'; aborting..." >&2
486 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
487 --tokens "$tokens" --tokens_min "$tokens_min" \
488 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
491 function _getInterfaceValue
501 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
504 : ${_giv_tmp:=$_giv_dflt}
505 eval $_giv_val=\$_giv_tmp
508 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
509 function _transformMask2Prefix
513 test -n "$_tm2p_tmp" || {
514 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
521 function _addInterfaceCmd
523 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
524 let ++INTERFACE_CMDS_IDX
527 ## Usage: _generateMac <var> <iface> <ctx>
528 function _generateMac
531 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
535 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
538 function _getVLANInfo
543 creation of VLAN_PLUS_VID devices is not supported; please create them
544 before starting the vserver and use the 'nodev' flag then"
545 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
549 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
550 create them before starting the vserver and use the 'nodev' flag then"
551 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
553 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
554 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
565 test -e "$iface/tun" -o -e "$iface/tap" || return 1
566 test ! -e "$iface/tun" || echo --tun
567 test ! -e "$iface/tap" || echo --tap
568 test ! -e "$iface/nocsum" || echo --~checksum
569 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
570 if test -e "$iface/uid"; then
572 getFileValue uid "$iface/uid"
575 if test -e "$iface/gid"; then
577 getFileValue gid "$iface/gid"
580 if test -e "$iface/linktype"; then
582 getFileValue linktype "$iface/linktype"
583 echo --linktype "$linktype"
588 ## Usage: _processSingleInterface <interface-directory>
589 function _processSingleInterface
605 _getInterfaceValue ip '' "$iface"
606 _getInterfaceValue extip '' "$iface" "$iface/.."
607 _getInterfaceValue dev '' "$iface" "$iface/.."
608 _getInterfaceValue prefix '' "$iface" "$iface/.."
609 _getInterfaceValue mask '' "$iface" "$iface/.."
610 _getInterfaceValue bcast '' "$iface" "$iface/.."
611 _getInterfaceValue name '' "$iface"
612 _getInterfaceValue scope '' "$iface" "$iface/.."
613 _getInterfaceValue mac '' "$iface"
614 _getInterfaceValue peer '' "$iface"
616 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
617 test -n "$dev" -o -e "$iface"/nodev || {
618 echo $"No device specified for '$iface'" >&2
622 test ! -e "$iface"/down || up=
625 _transformMask2Prefix prefix "$prefix" "$mask"
626 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
628 test ! -e "$iface"/nodev || break
630 test ! -e "$iface"/only_ip || break
632 test -e "$iface/vlandev" \
633 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
634 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
635 -a ! -e "$iface/novlandev" \
636 -a ! -e "$iface/../novlandev" \) && {
638 if vlan_info=$(_getVLANInfo "$dev"); then
639 test -d /proc/net/vlan || {
640 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
643 _addInterfaceCmd VCONFIG $vlan_info
647 if ! test -e "$iface"/indirect; then
649 local use_bcast="broadcast ${bcast:-+}"
650 echo "$ip" | $_GREP -q : && use_bcast=
653 if tun_info=$(_getTunInfo "$iface"); then
654 _addInterfaceCmd TUNCTL "$dev" $tun_info
657 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
658 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
659 _addInterfaceCmd IP_LINK "$dev" $up
660 elif ! test -n "$N_CONTEXT"; then
661 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
664 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
665 _addInterfaceCmd MODPROBE dummy "$dev"
666 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
667 _addInterfaceCmd NAMEIF "$dev" "$mac"
668 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
669 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
676 ## Usage: _generateInterfaceOptions <vserver-directory>
677 function _generateInterfaceOptions
681 # XXX: This is here instead of in _generateChbindOptions
682 # to avoid a circular dependency
683 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
684 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
686 for iface in "$1/interfaces/"*; do
687 test -d "$iface" || continue
688 test ! -e "$iface"/disabled || continue
690 _processSingleInterface "$iface"
692 _HAVE_INTERFACE_OPTIONS=1
695 function enableInterfaces
700 lock "$__LOCKDIR"/vserver.interfaces
702 while test $i -lt $INTERFACE_CMDS_IDX; do
703 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
714 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
716 NAMEIF) $_NAMEIF "$@";;
717 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
718 $_VCONFIG add "$2" "$3" >/dev/null;;
719 IP_ADDR) $_IP addr add "$@";;
720 IP_ADDR_FLUSH) $_IP addr flush "$@";;
721 IP_LINK) $_IP link set "$@";;
722 IP_ROUTE) $_IP route add "$@";;
726 $_TUNCTL --persist "$@" "$dev"
728 *) echo "Unknown interface-command type '$type'" >&2; false;;
737 function disableInterfaces
739 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
741 local i=$INTERFACE_CMDS_IDX
744 lock "$__LOCKDIR"/vserver.interfaces
746 while test $i -gt 0; do
749 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
756 MODPROBE) $_RMMOD "${2:-$1}";;
758 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
759 IP_ADDR) $_IP addr del "$@";;
761 IP_LINK) ;; ## Ignore the link-down command for now
762 IP_ROUTE) $_IP route del "$@";;
763 TUNCTL) $_TUNCTL --~persist "$1";;
764 *) echo "Unknown interface-command type '$type'" >&2; false;;
771 function _generateTagOptions
776 getFileValue tag "$vdir/tag" "$vdir/context"
777 test -n "$tag" || return 0
779 OPTS_VTAG_CREATE=( --tag "$tag" )
780 OPTS_VTAG_ENTER=( --tag "$tag" )
783 function _generateMemctrlOptions
788 getFileValue badness "$vdir/badness"
789 test -n "$badness" || return 0
791 OPTS_VMEMCTRL=( --badness "$badness" )
794 function _generateSpaceOptions
797 local d="$vdir"/spaces
801 for space in pid net; do
802 if test -e "$d"/$space; then
803 getFileValue shared "$d"/$space || shared=""
804 if test -z "$shared"; then
805 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
806 elif test "$shared" = "0"; then
809 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
810 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
816 getFileValue mask "$d"/mask || \
817 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
820 ## Usage: prepareInit <vserver-directory>
823 pushd "$1/vdir" >/dev/null
826 { $_FIND var/run ! -type d -print0; \
827 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
830 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
831 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
836 "${INITCMD_PREPARE[@]}"
840 ## Usage: prepareInit <vserver-directory>
843 pushd "$1/vdir" >/dev/null
846 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
849 "${STOPCMD_PREPARE[@]}"
854 function generateOptions
856 _generateInterfaceOptions "$1"
857 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
858 _generateNiceCommand "$1"
859 _generateIONiceCommand "$1"
860 _generateInitOptions "$1"
861 _generateChcontextOptions "$1"
862 _generateScheduleOptions "$1"
863 _generatePersonalityOptions "$1"
864 _generateTagOptions "$1"
865 _generateMemctrlOptions "$1"
866 _generateSpaceOptions "$1"
867 _generateCgroupOptions
869 if test -n "$_IS_FAKEINIT"; then
870 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
871 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
879 local f="$vdir"/cpuset
883 test -d "$f" || return 0
884 test -e "$f"/name || return 0
886 read cpuset < "$f"/name
887 test -e "$f"/nocreate || {
888 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
889 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
890 if test -e "$f"/"$i"; then
891 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
899 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
900 if [ "$configured" -ne 0 ]; then
902 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
903 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
908 function removeCPUSET
912 local f="$vdir"/cpuset
914 test -d "$f" || return 0
915 test -e "$f"/name || return 0
917 read cpuset < "$f"/name
918 test -e "$f"/nocreate || {
919 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
923 function _mountVserverInternal
928 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 if test -h etc/mtab; then
937 local l=$($_READLINK etc/mtab)
938 test "${l##/proc/}" = "$l" || xflag=-n
940 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
948 local fstab="$cfgdir"/fstab
951 test -e "$fstab" || return 0
952 pushd "$vdir" >/dev/null
953 # check whether / is mounted readonly or whether there is special
954 # magic regarding the mtab file; when etc/mtab can not be touched,
955 # add the '-n' flag to mount
956 test -w etc -o -w etc/mtab || xflag=-n
957 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
961 function mountVserver
970 test -e "$cfgdir"/fstab -o \
971 -e "$cfgdir"/fstab.local -o \
972 -e "$cfgdir"/fstab.remote || return 0
974 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
976 pushd "$vdir" >/dev/null
977 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
980 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
982 _mountVserverInternal "$cfgdir"/fstab
983 _mountVserverInternal "$cfgdir"/fstab.local
984 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
986 isNamespaceCleanup "$cfgdir" && \
987 _namespaceCleanup "$cfgdir"
989 real_vdir=$(getPhysicalDir "$vdir")
990 isAvoidNamespace "$cfgdir" || \
991 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
992 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
993 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
996 function _umountVserverInternal
999 test -e "$fstab" || return 0
1004 while read src dst tmp; do
1005 test -n "$tmp" || continue
1011 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1017 function umountVserver
1023 isAvoidNamespace "$cfgdir" || return 0
1024 test -e "$cfgdir"/fstab -o \
1025 -e "$cfgdir"/fstab.local -o \
1026 -e "$cfgdir"/fstab.remote || return 0
1027 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1029 pushd "$vdir/" >/dev/null || return 1
1030 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1031 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1032 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1033 popd >/dev/null || return 1
1041 local fstab="$cfgdir"/fstab
1045 test -e "$fstab" || return 0
1047 export FSTAB_FILE="$fstab"
1050 test "$fsck_exitcode" -eq 0 -o \
1051 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1054 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1058 test -n "$_NEED_VSHELPER_SYNC" && \
1059 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1061 vshelper.initSync "$1" "$3" "$_is_meth"
1064 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1067 if $_VSERVER_INFO - FEATURE vwait; then
1069 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1072 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1073 --status-fd 3 "$2" \
1074 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1077 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1078 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1079 killContext "$S_CONTEXT" 9
1083 ) 4>$_is_tmpdir/procs &
1085 echo "$!" >$_is_tmpdir/pid
1086 eval "$3"=$_is_tmpdir
1091 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1092 function _waitForVWait
1097 declare -r procs=$(cat $4)
1099 getFileArray status "$2"
1104 'vwait' exited with error '$2' which indicates that vserver could not
1105 be stopped properly"
1108 (KILLED) warning $"\
1109 A timeout occured while waiting for the vserver to finish and it was
1110 killed by sending a SIGKILL signal. Please investigate the reasons
1111 and/or increase the timeout in apps/vshelper/sync-timeout."
1114 (TIMEOUT) warning $"\
1115 A timeout occured while waiting for the vserver to finish and it will
1116 be killed by sending a SIGKILL signal. The following process list
1117 might be useful for finding out the reason of this behavior:
1119 ----------------------------------------------------------------------
1121 }----------------------------------------------------------------------"
1124 (\?\?\?|*) warning $"\
1125 internal error: 'vwait' exited with an unexpected status '$1'; I will
1126 try to continue but be prepared for unexpected events."
1133 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1134 function waitForSync
1138 local vwait_statdir=$3
1141 if test -d "$vwait_statdir"; then
1142 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1143 elif test -n "$_NEED_VSHELPER_SYNC"; then
1144 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1146 A timeout or other error occured while waiting for the synchronization
1147 signal from vserver '$VSERVER_NAME'.
1148 The vserver will be killed nevertheless..."
1149 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1150 "${INITCMD_STOP_SYNC[@]}" || \
1152 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1153 will be killed nevertheless..."
1156 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1160 function _sourceWrap
1162 local vdir name flavor start i already_handled base
1166 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1167 function execScriptlets
1171 declare -r flavor=$3
1174 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1175 local DONT_SKIP_DEFAULTS=
1176 local already_handled=
1178 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1179 isRegularFile "$i" || continue
1180 test -r "$i" || continue
1184 test -x "$i" || start=_sourceWrap
1185 $start "$i" "$flavor" "$name"
1188 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1193 function sanityCheck
1195 declare -r cfgdir=$1
1197 ! test -e "$cfgdir"/fstab.local ||
1199 WARNING: 'fstab' will *not* be executed in the network context of the
1200 vserver anymore. Therefore, 'fstab.local' has the same functionality
1201 and is obsoleted. When you need the old behaviour, put the mounts
1202 into 'fstab.remote'"
1204 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1206 WARNING: The hostname is now configured in 'uts/nodename' but not in
1209 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1211 WARNING: The domainname is now configured in 'uts/domainname' but not
1212 in 'domainname'." >&2
1216 for i in "$cfgdir"/interfaces/*/only_ip; do
1217 if test -e "$i"; then
1219 iface=${i##$cfgdir/interfaces/}
1220 iface=${iface%%/only_ip}
1222 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1227 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1229 WARNING: There is no cachedirectory configured for this vserver;
1230 please create '$cfgdir/cache' e.g. by executing
1232 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1235 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1237 vshelper.doSanityCheck
1239 $_VSERVER_INFO - VERIFYCAP ||
1240 panic $"capabilities are not enabled in kernel-setup"
1242 $_VSERVER_INFO - VERIFYPROC ||
1244 /proc/uptime can not be accessed. Usually, this is caused by
1245 procfs-security. Please read the FAQ for more details
1246 http://linux-vserver.org/Proc-Security"
1248 test -e "$cfgdir"/context || {
1249 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1250 test "$TYPE" != "static" || panic $"\
1251 The kernel does not have dynamic contexts enabled. Please configure
1252 a static one by executing
1254 echo [number between 2 and 49151] > $cfgdir/context"
1259 function _setSingleDiskLimit
1271 getFileValue ctx "$vdir/context"
1272 getFileValue directory "$dlimit/directory" || return 0
1273 getFileValue space_total "$dlimit/space_total" || return 0
1274 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1275 getFileValue reserved "$dlimit/reserved" || return 0
1277 local cachename=$ctx$directory
1278 cachename=dlimits/${cachename//\//_}
1280 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1281 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1282 $_RM -f "$vdir/cache/$cachename"
1284 if test -z "$inodes_used" -o -z "$space_used"; then
1286 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1287 inodes_used=${tmpvdu##* }
1288 space_used=${tmpvdu%% *}
1291 $_VDLIMIT --xid $ctx \
1292 --set space_used=$space_used \
1293 --set space_total=$space_total \
1294 --set inodes_used=$inodes_used \
1295 --set inodes_total=$inodes_total \
1296 --set reserved=$reserved \
1301 function setDiskLimits
1306 # Disk Limits without a static context are useless
1307 test -e "$vdir"/context || return 0
1309 for dlimit in "$vdir/dlimits/"*; do
1310 test -d "$dlimit" || continue
1311 test ! -e "$dlimit/disabled" || continue
1313 _setSingleDiskLimit "$vdir" "$dlimit"
1318 function _saveSingleDiskLimit
1325 getFileValue ctx "$vdir/context"
1326 getFileValue directory "$dlimit/directory" || return 0
1328 local cachename=$ctx$directory
1329 cachename=${cachename//\//_}
1331 # Things are getting ugly here... LFS says that /var/cache (where
1332 # cachename is usually pointing to) can vanish and applications
1333 # have to deal with it. So, we have to interprete the $vdir/cache
1334 # symlink and have to create the needed directories manually.
1335 if test -d "$vdir/cache"; then
1336 : # ok, exists already
1337 elif test -L "$vdir/cache"; then
1338 # it's a dangling symlink
1340 link=$($_READLINK "$vdir/cache")
1341 ( cd $vdir && $_MKDIR -p "$link" )
1346 test -d "$vdir/cache"
1347 $_MKDIR -p "$vdir"/cache/dlimits
1349 $_VDLIMIT --xid $ctx "$directory" | \
1350 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1352 $_VDLIMIT --xid $ctx --remove "$directory"
1356 function saveDiskLimits
1361 test -e "$vdir"/context || return 0
1363 for dlimit in "$vdir/dlimits/"*; do
1364 test -d "$dlimit" || continue
1365 test ! -e "$dlimit/disabled" || continue
1367 _saveSingleDiskLimit "$vdir" "$dlimit"
1371 function _namespaceCleanup
1374 local root=$($_VSERVER_INFO "$1" VDIR 1)
1380 getFileArray skip "$vdir"/namespace-cleanup-skip \
1381 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1383 # these are things that have to be accessible post-cleanup
1384 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1385 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1386 local real=`getPhysicalDir "$i"`
1387 test "$i" != "$real" || real=
1388 for j in "$i" "$real"; do
1389 while test -n "$j"; do
1390 list=( "${list[@]}" "$j" )
1396 local -a list_umount
1397 while read -r dev path opts; do
1398 test -n "$path" || continue
1399 for i in "$root" /dev /proc; do
1401 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1403 for i in "${list[@]}" /; do
1404 test "$path" = "$i" && continue 2
1406 # unmount them in reverse order so mounts further down the tree get unmounted first
1407 list_umount=( "$path" "${list_umount[@]}" )
1409 # separate loop to avoid races while reading /proc/mounts
1410 for i in "${list_umount[@]}"; do
1411 $_UMOUNT -l -n -i "$i"
1415 function handleDeviceMap
1420 local flags device target
1422 test -d "$dir" || return 0
1423 test -n "$xid" || return 0
1425 for i in "$dir"/*; do
1426 test -d "$i" || continue
1428 local -a vdevmap_opts=()
1429 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1430 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1431 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1433 getFileValue flags "$i/flags" || :
1434 getFileValue device "$i/device" || :
1435 getFileValue target "$i/target" || :
1436 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1437 ${device:+--device "$device"} ${target:+--target "$target"} )
1439 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1445 $_GREP -q "cgroup" /proc/filesystems
1448 function _generateCgroupOptions
1452 hasCgroup || return 0
1454 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1455 if test -n "$file"; then
1456 read CGROUP_MNT < "$file"
1458 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1459 if test -n "$file"; then
1460 read CGROUP_SUBSYS < "$file"
1461 elif $_GREP -q '^ns[[:space:]]' /proc/cgroups; then
1462 # Hack for the ns subsystem, with which we are incompatible
1463 CGROUP_SUBSYS=$($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups | \
1464 (s=""; while read x; do test -n "$s" && s="$s,"; s="$s$x"; done; echo "$s"))
1466 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1467 if test -n "$file"; then
1468 _readFileToArray CGROUP_INHERIT "$file" ""
1476 hasCgroup || return 1
1477 test -d "$CGROUP_MNT" || return 1
1478 test -d "$1/cgroup" -o \
1479 \( -d "$__CONFDIR/.defaults/cgroup" -a \
1480 ! -e "$1/nocgroup" \)
1483 function _handleCgroup
1492 useCgroup "$vdir" || return 0
1494 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1495 test -d "$dir" || return 0
1497 if test -r "$dir"/name; then
1498 read name < "$dir"/name
1500 name="$VSERVER_NAME"
1503 if test "$action" = "attach"; then
1504 if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
1505 parent="$CGROUP_MNT/$name"
1506 parent="${parent%/*}"
1507 for i in "${CGROUP_INHERIT[@]}"; do
1508 test -f "$parent/$i" || continue
1509 cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
1513 for i in "$dir"/*; do
1515 test "$f" != mnt -a "$f" != subsys -a \
1516 "$f" != inherit -a "$f" != name || continue
1517 cat "$i" > "$CGROUP_MNT/$name/$f"
1520 echo "$$" > "$CGROUP_MNT/$name/tasks"
1521 elif test "$action" = "destroy"; then
1522 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1528 function attachToCgroup
1530 _handleCgroup attach "$@"
1533 function destroyCgroup
1535 _handleCgroup destroy "$@"