3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # $VSERVER_DIR ... path to vserver-cfg dir
20 # $VSERVER_NAME ... name of vserver
22 declare -a NICE_CMD=()
23 declare -a IONICE_CMD=()
24 declare -a CHBIND_CMD=()
25 declare -a CAP_OPTS=()
26 declare -a CHCONTEXT_INIT_OPTS=()
27 declare -a CHCONTEXT_FLAG_OPTS=()
28 declare -a CHCONTEXT_OPTS=()
29 declare -a CAPCHROOT_OPTS=()
30 declare -a INTERFACES=()
32 declare -a INITCMD_RESCUE=( /bin/sleep 900 )
33 declare -a INITCMD_START=()
34 declare -a INITCMD_START_SYNC=()
35 declare -a INITCMD_STOP=()
36 declare -a INITCMD_STOP_SYNC=()
37 declare -a INITCMD_PREPARE=()
38 declare -a INITKILL_SEQ=()
39 declare -a ENTER_SHELL=()
41 declare -a OPTS_VCONTEXT_CREATE=()
42 declare -a OPTS_VCONTEXT_MIGRATE=()
43 declare -a OPTS_VCONTEXT_ENTER=()
44 OPT_VCONTEXT_CHROOT=--chroot
45 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
46 declare -a OPTS_VSCHED=()
47 declare -a OPTS_ENV=()
48 declare -a OPTS_VTAG_CREATE=()
49 declare -a OPTS_VTAG_ENTER=()
50 declare -a OPTS_VMEMCTRL=()
51 declare -a OPTS_VSPACE=( --default )
52 declare -a OPTS_VSPACE_SHARED=()
53 declare -a VSPACE_SHARED_CMD=()
55 declare -a STOPCMD_PREPARE=()
57 declare -a VSERVER_EXTRA_CMDS=()
60 VSHELPER_SYNC_TIMEOUT=30
65 _HAVE_INTERFACE_OPTIONS=
77 CGROUP_MNT=/dev/cgroup
78 declare -a CGROUP_SUBSYS=()
79 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
83 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
85 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
91 function _readFileToArray
98 test -e "$_rfta_f" || return 0
99 while read _rfta_v; do
102 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
107 function _generateChbindOptions
115 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
117 if test -e "$vdir"/noncontext -o \
118 \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
119 _HAVE_CHBIND_OPTIONS=1
123 local f="$vdir"/interfaces/bcast
124 getFileValue bcast "$f"
125 f="$vdir"/interfaces/lback
126 getFileValue lback "$f"
128 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
129 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
132 for i in "${INTERFACES[@]}"; do
133 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
136 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
137 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
139 _HAVE_CHBIND_OPTIONS=1
142 function _generateNiceCommand
146 local current_nice=`$_NICE`
148 test -r "$vdir/nice" && read nice <"$vdir"/nice
150 let nice=$nice-$current_nice || :
151 NICE_CMD=( $_NICE -n $nice )
154 function _generateIONiceCommand
158 local ionice_priority=0
160 test -n "$_IONICE" || return 0
162 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
163 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
165 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
168 function _generatePersonalityOptions
171 local f="$vdir"/personality
174 test -s "$f" || return 0
183 (*) flags=$flags$delim$tmp
190 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
191 --personality-type "$type"
192 ${flags:+--personality-flags "$flags"} )
195 function _generateCCapabilityOptions
199 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
202 function _generateBCapabilityOptions
206 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
209 function _generateCapabilityOptions
214 _generateBCapabilityOptions "$vdir"
215 _generateCCapabilityOptions "$vdir"
217 test -e "$vdir"/capabilities || return 0
226 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
227 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
230 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
233 done <"$vdir"/capabilities
236 function getEnterShell
243 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
245 test -n "$ENTER_SHELL" || {
247 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
249 test -x "$vdir/vdir/$1" || continue
256 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
257 function sendKillSequence
263 while isCtxRunning "$ctx"; do
264 test -z "$wait" || sleep "$wait"
266 killContext "$ctx" "$1"
267 test -n "$2" || break
273 function _generateInitOptions
276 local cfgdir=$vdir/apps/init
281 INITCMD_START_SYNC=()
286 INITKILL_SEQ=( 15 5 9 )
287 CHCONTEXT_INIT_OPTS=()
290 test x"$INITSTYLE" = xrescue || \
291 getFileValue INITSTYLE "$cfgdir"/style
292 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
293 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
294 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
295 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
297 findFile _gio_env "$cfgdir"/environment \
298 "$__CONFDIR"/.defaults/apps/init/environment \
299 "$__PKGLIBDEFAULTDIR"/environment
300 getFileArray OPTS_ENV "$_gio_env" || :
302 case x"$INITSTYLE" in
304 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
305 INITCMD_STOP=( /sbin/killall5 )
309 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
310 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
312 for i in /etc/init.d/rc /etc/rc.d/rc; do
313 test -x "$vdir/vdir/$i" || continue
314 INITCMD_START=( "$i" "$RUNLEVEL_START" )
315 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
317 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
318 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
319 if test -n "$OPTION_DEBUG_SYSV"; then
320 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
321 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
326 INITCMD_START=( /sbin/init )
327 INITCMD_STOP=( /sbin/init )
329 _NEED_VSHELPER_SYNC=1
330 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
331 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
335 INITCMD_START=( /sbin/minit-start )
336 INITCMD_STOP=( /sbin/minit-stop )
338 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
339 _NEED_VSHELPER_SYNC=1
340 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
341 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
342 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
346 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
347 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
349 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
350 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
351 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
352 RC_WRAP=/lib/rc/sh/init-vserver.sh
354 panic "init-vserver.sh not found; aborting"
357 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
358 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
359 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
360 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
364 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
365 INITCMD_START=( /etc/rc.multi )
366 INITCMD_STOP=( /etc/rc.shutdown )
367 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
371 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
374 if test x"$INITSTYLE" != xrescue; then
375 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
376 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
377 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
378 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
379 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
382 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
383 INITCMD_START_SYNC=()
388 if vshelper.isEnabled; then
389 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
395 function _generateFlagOptions
400 CHCONTEXT_FLAG_OPTS=()
402 findFile file "$vdir"/cflags "$vdir"/flags ""
412 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
413 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
419 isAvoidNamespace "$vdir" || {
421 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
422 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
423 OPT_VCONTEXT_CHROOT=--pivot-root
427 function _generateChcontextOptions
430 local ctx hostname domainname
435 read ctx <"$vdir"/context || :
437 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
438 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
441 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
443 _generateCapabilityOptions "$vdir"
444 _generateFlagOptions "$vdir"
446 CHCONTEXT_OPTS=( $SILENT_OPT \
447 "${CHCONTEXT_FLAG_OPTS[@]}" \
450 ${ctx:+--ctx "$ctx"} \
451 ${hostname:+--hostname "$hostname"} \
452 ${domainname:+--domainname "$domainname"} )
454 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
455 ${ctx:+--xid "$ctx"} )
456 ## put '--secure' at front so that it can be overridden
457 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
460 function _generateScheduleOptions
463 if test -d "$vdir"/sched; then
464 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
468 local f="$vdir"/schedule
469 test -e "$f" || return 0
471 local fill_rate interval tokens tokens_min tokens_max prio_bias
479 read prio_bias || prio_bias=
483 test -n "$prio_bias" || {
484 echo $"Bad content in '$f'; aborting..." >&2
488 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
489 --tokens "$tokens" --tokens_min "$tokens_min" \
490 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
493 function _getInterfaceValue
503 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
506 : ${_giv_tmp:=$_giv_dflt}
507 eval $_giv_val=\$_giv_tmp
510 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
511 function _transformMask2Prefix
515 test -n "$_tm2p_tmp" || {
516 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
523 function _addInterfaceCmd
525 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
526 let ++INTERFACE_CMDS_IDX
529 ## Usage: _generateMac <var> <iface> <ctx>
530 function _generateMac
533 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
537 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
540 function _getVLANInfo
545 creation of VLAN_PLUS_VID devices is not supported; please create them
546 before starting the vserver and use the 'nodev' flag then"
547 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
551 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
552 create them before starting the vserver and use the 'nodev' flag then"
553 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
555 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
556 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
567 test -e "$iface/tun" -o -e "$iface/tap" || return 1
568 test ! -e "$iface/tun" || echo --tun
569 test ! -e "$iface/tap" || echo --tap
570 test ! -e "$iface/nocsum" || echo --~checksum
571 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
572 if test -e "$iface/uid"; then
574 getFileValue uid "$iface/uid"
577 if test -e "$iface/gid"; then
579 getFileValue gid "$iface/gid"
582 if test -e "$iface/linktype"; then
584 getFileValue linktype "$iface/linktype"
585 echo --linktype "$linktype"
590 ## Usage: _processSingleInterface <interface-directory>
591 function _processSingleInterface
607 _getInterfaceValue ip '' "$iface"
608 _getInterfaceValue extip '' "$iface" "$iface/.."
609 _getInterfaceValue dev '' "$iface" "$iface/.."
610 _getInterfaceValue prefix '' "$iface" "$iface/.."
611 _getInterfaceValue mask '' "$iface" "$iface/.."
612 _getInterfaceValue bcast '' "$iface" "$iface/.."
613 _getInterfaceValue name '' "$iface"
614 _getInterfaceValue scope '' "$iface" "$iface/.."
615 _getInterfaceValue mac '' "$iface"
616 _getInterfaceValue peer '' "$iface"
618 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
619 test -n "$dev" -o -e "$iface"/nodev || {
620 echo $"No device specified for '$iface'" >&2
624 test ! -e "$iface"/down || up=
627 _transformMask2Prefix prefix "$prefix" "$mask"
628 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
630 test ! -e "$iface"/nodev || break
632 test ! -e "$iface"/only_ip || break
634 test -e "$iface/vlandev" \
635 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
636 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
637 -a ! -e "$iface/novlandev" \
638 -a ! -e "$iface/../novlandev" \) && {
640 if vlan_info=$(_getVLANInfo "$dev"); then
641 test -d /proc/net/vlan || {
642 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
645 _addInterfaceCmd VCONFIG $vlan_info
649 if ! test -e "$iface"/indirect; then
651 local use_bcast="broadcast ${bcast:-+}"
652 echo "$ip" | $_GREP -q : && use_bcast=
655 if tun_info=$(_getTunInfo "$iface"); then
656 _addInterfaceCmd TUNCTL "$dev" $tun_info
659 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
660 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
661 _addInterfaceCmd IP_LINK "$dev" $up
662 elif ! test -n "$N_CONTEXT"; then
663 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
666 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
667 _addInterfaceCmd MODPROBE dummy "$dev"
668 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
669 _addInterfaceCmd NAMEIF "$dev" "$mac"
670 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
671 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
678 ## Usage: _generateInterfaceOptions <vserver-directory>
679 function _generateInterfaceOptions
683 # XXX: This is here instead of in _generateChbindOptions
684 # to avoid a circular dependency
685 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
686 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
688 for iface in "$1/interfaces/"*; do
689 test -d "$iface" || continue
690 test ! -e "$iface"/disabled || continue
692 _processSingleInterface "$iface"
694 _HAVE_INTERFACE_OPTIONS=1
697 function enableInterfaces
702 lock "$__LOCKDIR"/vserver.interfaces
704 while test $i -lt $INTERFACE_CMDS_IDX; do
705 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
716 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
718 NAMEIF) $_NAMEIF "$@";;
719 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
720 $_VCONFIG add "$2" "$3" >/dev/null;;
721 IP_ADDR) $_IP addr add "$@";;
722 IP_ADDR_FLUSH) $_IP addr flush "$@";;
723 IP_LINK) $_IP link set "$@";;
724 IP_ROUTE) $_IP route add "$@";;
728 $_TUNCTL --persist "$@" "$dev"
730 *) echo "Unknown interface-command type '$type'" >&2; false;;
739 function disableInterfaces
741 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
743 local i=$INTERFACE_CMDS_IDX
746 lock "$__LOCKDIR"/vserver.interfaces
748 while test $i -gt 0; do
751 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
758 MODPROBE) $_RMMOD "${2:-$1}";;
760 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
761 IP_ADDR) $_IP addr del "$@";;
763 IP_LINK) ;; ## Ignore the link-down command for now
764 IP_ROUTE) $_IP route del "$@";;
765 TUNCTL) $_TUNCTL --~persist "$1";;
766 *) echo "Unknown interface-command type '$type'" >&2; false;;
773 function _generateTagOptions
778 getFileValue tag "$vdir/tag" "$vdir/context"
779 test -n "$tag" || return 0
781 OPTS_VTAG_CREATE=( --tag "$tag" )
782 OPTS_VTAG_ENTER=( --tag "$tag" )
785 function _generateMemctrlOptions
790 getFileValue badness "$vdir/badness"
791 test -n "$badness" || return 0
793 OPTS_VMEMCTRL=( --badness "$badness" )
796 function _generateSpaceOptions
799 local d="$vdir"/spaces
803 for space in pid net; do
804 if test -e "$d"/$space; then
805 getFileValue shared "$d"/$space || shared=""
806 if test -z "$shared"; then
807 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
808 elif test "$shared" = "0"; then
811 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
812 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
818 getFileValue mask "$d"/mask || \
819 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
822 ## Usage: prepareInit <vserver-directory>
825 pushd "$1/vdir" >/dev/null
828 { $_FIND var/run ! -type d -print0; \
829 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
832 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
833 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
838 "${INITCMD_PREPARE[@]}"
842 ## Usage: prepareInit <vserver-directory>
845 pushd "$1/vdir" >/dev/null
848 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
851 "${STOPCMD_PREPARE[@]}"
856 function generateOptions
858 _generateInterfaceOptions "$1"
859 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
860 _generateNiceCommand "$1"
861 _generateIONiceCommand "$1"
862 _generateInitOptions "$1"
863 _generateChcontextOptions "$1"
864 _generateScheduleOptions "$1"
865 _generatePersonalityOptions "$1"
866 _generateTagOptions "$1"
867 _generateMemctrlOptions "$1"
868 _generateSpaceOptions "$1"
869 _generateCgroupOptions
871 if test -n "$_IS_FAKEINIT"; then
872 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
873 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
881 local f="$vdir"/cpuset
885 test -d "$f" || return 0
886 test -e "$f"/name || return 0
888 read cpuset < "$f"/name
889 test -e "$f"/nocreate || {
890 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
891 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
892 if test -e "$f"/"$i"; then
893 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
901 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
902 if [ "$configured" -ne 0 ]; then
904 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
905 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
910 function removeCPUSET
914 local f="$vdir"/cpuset
916 test -d "$f" || return 0
917 test -e "$f"/name || return 0
919 read cpuset < "$f"/name
920 test -e "$f"/nocreate || {
921 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
925 function _mountVserverInternal
930 test -e "$fstab" || return 0
933 pushd "$vdir" >/dev/null
934 # check whether / is mounted readonly or whether there is special
935 # magic regarding the mtab file; when etc/mtab can not be touched,
936 # add the '-n' flag to mount
937 test -w etc -o -w etc/mtab || xflag=-n
938 if test -h etc/mtab; then
939 local l=$($_READLINK etc/mtab)
940 test "${l##/proc/}" = "$l" || xflag=-n
942 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
950 local fstab="$cfgdir"/fstab
953 test -e "$fstab" || return 0
954 pushd "$vdir" >/dev/null
955 # check whether / is mounted readonly or whether there is special
956 # magic regarding the mtab file; when etc/mtab can not be touched,
957 # add the '-n' flag to mount
958 test -w etc -o -w etc/mtab || xflag=-n
959 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
963 function mountVserver
972 test -e "$cfgdir"/fstab -o \
973 -e "$cfgdir"/fstab.local -o \
974 -e "$cfgdir"/fstab.remote || return 0
976 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
978 pushd "$vdir" >/dev/null
979 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
982 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
984 _mountVserverInternal "$cfgdir"/fstab
985 _mountVserverInternal "$cfgdir"/fstab.local
986 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
988 isNamespaceCleanup "$cfgdir" && \
989 _namespaceCleanup "$cfgdir"
991 real_vdir=$(getPhysicalDir "$vdir")
992 isAvoidNamespace "$cfgdir" || \
993 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
994 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
995 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
998 function _umountVserverInternal
1001 test -e "$fstab" || return 0
1006 while read src dst tmp; do
1007 test -n "$tmp" || continue
1013 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1019 function umountVserver
1025 isAvoidNamespace "$cfgdir" || return 0
1026 test -e "$cfgdir"/fstab -o \
1027 -e "$cfgdir"/fstab.local -o \
1028 -e "$cfgdir"/fstab.remote || return 0
1029 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1031 pushd "$vdir/" >/dev/null || return 1
1032 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1033 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1034 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1035 popd >/dev/null || return 1
1043 local fstab="$cfgdir"/fstab
1047 test -e "$fstab" || return 0
1049 export FSTAB_FILE="$fstab"
1052 test "$fsck_exitcode" -eq 0 -o \
1053 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1056 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1060 test -n "$_NEED_VSHELPER_SYNC" && \
1061 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1063 vshelper.initSync "$1" "$3" "$_is_meth"
1066 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1069 if $_VSERVER_INFO - FEATURE vwait; then
1071 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1074 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1075 --status-fd 3 "$2" \
1076 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1079 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1080 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1081 killContext "$S_CONTEXT" 9
1085 ) 4>$_is_tmpdir/procs &
1087 echo "$!" >$_is_tmpdir/pid
1088 eval "$3"=$_is_tmpdir
1093 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1094 function _waitForVWait
1099 declare -r procs=$(cat $4)
1101 getFileArray status "$2"
1106 'vwait' exited with error '$2' which indicates that vserver could not
1107 be stopped properly"
1110 (KILLED) warning $"\
1111 A timeout occured while waiting for the vserver to finish and it was
1112 killed by sending a SIGKILL signal. Please investigate the reasons
1113 and/or increase the timeout in apps/vshelper/sync-timeout."
1116 (TIMEOUT) warning $"\
1117 A timeout occured while waiting for the vserver to finish and it will
1118 be killed by sending a SIGKILL signal. The following process list
1119 might be useful for finding out the reason of this behavior:
1121 ----------------------------------------------------------------------
1123 }----------------------------------------------------------------------"
1126 (\?\?\?|*) warning $"\
1127 internal error: 'vwait' exited with an unexpected status '$1'; I will
1128 try to continue but be prepared for unexpected events."
1135 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1136 function waitForSync
1140 local vwait_statdir=$3
1143 if test -d "$vwait_statdir"; then
1144 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1145 elif test -n "$_NEED_VSHELPER_SYNC"; then
1146 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1148 A timeout or other error occured while waiting for the synchronization
1149 signal from vserver '$VSERVER_NAME'.
1150 The vserver will be killed nevertheless..."
1151 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1152 "${INITCMD_STOP_SYNC[@]}" || \
1154 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1155 will be killed nevertheless..."
1158 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1162 function _sourceWrap
1164 local vdir name flavor start i already_handled base
1168 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1169 function execScriptlets
1173 declare -r flavor=$3
1176 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1177 local DONT_SKIP_DEFAULTS=
1178 local already_handled=
1180 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1181 isRegularFile "$i" || continue
1182 test -r "$i" || continue
1186 test -x "$i" || start=_sourceWrap
1187 $start "$i" "$flavor" "$name"
1190 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1195 function sanityCheck
1197 declare -r cfgdir=$1
1199 ! test -e "$cfgdir"/fstab.local ||
1201 WARNING: 'fstab' will *not* be executed in the network context of the
1202 vserver anymore. Therefore, 'fstab.local' has the same functionality
1203 and is obsoleted. When you need the old behaviour, put the mounts
1204 into 'fstab.remote'"
1206 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1208 WARNING: The hostname is now configured in 'uts/nodename' but not in
1211 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1213 WARNING: The domainname is now configured in 'uts/domainname' but not
1214 in 'domainname'." >&2
1218 for i in "$cfgdir"/interfaces/*/only_ip; do
1219 if test -e "$i"; then
1221 iface=${i##$cfgdir/interfaces/}
1222 iface=${iface%%/only_ip}
1224 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1229 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1231 WARNING: There is no cachedirectory configured for this vserver;
1232 please create '$cfgdir/cache' e.g. by executing
1234 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1237 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1239 vshelper.doSanityCheck
1241 $_VSERVER_INFO - VERIFYCAP ||
1242 panic $"capabilities are not enabled in kernel-setup"
1244 $_VSERVER_INFO - VERIFYPROC ||
1246 /proc/uptime can not be accessed. Usually, this is caused by
1247 procfs-security. Please read the FAQ for more details
1248 http://linux-vserver.org/Proc-Security"
1250 test -e "$cfgdir"/context || {
1251 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1252 test "$TYPE" != "static" || panic $"\
1253 The kernel does not have dynamic contexts enabled. Please configure
1254 a static one by executing
1256 echo [number between 2 and 49151] > $cfgdir/context"
1261 function _setSingleDiskLimit
1273 getFileValue ctx "$vdir/context"
1274 getFileValue directory "$dlimit/directory" || return 0
1275 getFileValue space_total "$dlimit/space_total" || return 0
1276 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1277 getFileValue reserved "$dlimit/reserved" || return 0
1279 local cachename=$ctx$directory
1280 cachename=dlimits/${cachename//\//_}
1282 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1283 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1284 $_RM -f "$vdir/cache/$cachename"
1286 if test -z "$inodes_used" -o -z "$space_used"; then
1288 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1289 inodes_used=${tmpvdu##* }
1290 space_used=${tmpvdu%% *}
1293 $_VDLIMIT --xid $ctx \
1294 --set space_used=$space_used \
1295 --set space_total=$space_total \
1296 --set inodes_used=$inodes_used \
1297 --set inodes_total=$inodes_total \
1298 --set reserved=$reserved \
1303 function setDiskLimits
1308 # Disk Limits without a static context are useless
1309 test -e "$vdir"/context || return 0
1311 for dlimit in "$vdir/dlimits/"*; do
1312 test -d "$dlimit" || continue
1313 test ! -e "$dlimit/disabled" || continue
1315 _setSingleDiskLimit "$vdir" "$dlimit"
1320 function _saveSingleDiskLimit
1327 getFileValue ctx "$vdir/context"
1328 getFileValue directory "$dlimit/directory" || return 0
1330 local cachename=$ctx$directory
1331 cachename=${cachename//\//_}
1333 # Things are getting ugly here... LFS says that /var/cache (where
1334 # cachename is usually pointing to) can vanish and applications
1335 # have to deal with it. So, we have to interprete the $vdir/cache
1336 # symlink and have to create the needed directories manually.
1337 if test -d "$vdir/cache"; then
1338 : # ok, exists already
1339 elif test -L "$vdir/cache"; then
1340 # it's a dangling symlink
1342 link=$($_READLINK "$vdir/cache")
1343 ( cd $vdir && $_MKDIR -p "$link" )
1348 test -d "$vdir/cache"
1349 $_MKDIR -p "$vdir"/cache/dlimits
1351 $_VDLIMIT --xid $ctx "$directory" | \
1352 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1354 $_VDLIMIT --xid $ctx --remove "$directory"
1358 function saveDiskLimits
1363 test -e "$vdir"/context || return 0
1365 for dlimit in "$vdir/dlimits/"*; do
1366 test -d "$dlimit" || continue
1367 test ! -e "$dlimit/disabled" || continue
1369 _saveSingleDiskLimit "$vdir" "$dlimit"
1373 function _namespaceCleanup
1376 local root=$($_VSERVER_INFO "$1" VDIR 1)
1382 getFileArray skip "$vdir"/namespace-cleanup-skip \
1383 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1385 # these are things that have to be accessible post-cleanup
1386 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1387 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1388 local real=`getPhysicalDir "$i"`
1389 test "$i" != "$real" || real=
1390 for j in "$i" "$real"; do
1391 while test -n "$j"; do
1392 list=( "${list[@]}" "$j" )
1398 local -a list_umount
1399 while read -r dev path opts; do
1400 test -n "$path" || continue
1401 for i in "$root" /dev /proc; do
1403 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1405 for i in "${list[@]}" /; do
1406 test "$path" = "$i" && continue 2
1408 # unmount them in reverse order so mounts further down the tree get unmounted first
1409 list_umount=( "$path" "${list_umount[@]}" )
1411 # separate loop to avoid races while reading /proc/mounts
1412 for i in "${list_umount[@]}"; do
1413 $_UMOUNT -l -n -i "$i"
1417 function handleDeviceMap
1422 local flags device target
1424 test -d "$dir" || return 0
1425 test -n "$xid" || return 0
1427 for i in "$dir"/*; do
1428 test -d "$i" || continue
1430 local -a vdevmap_opts=()
1431 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1432 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1433 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1435 getFileValue flags "$i/flags" || :
1436 getFileValue device "$i/device" || :
1437 getFileValue target "$i/target" || :
1438 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1439 ${device:+--device "$device"} ${target:+--target "$target"} )
1441 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1447 $_GREP -q "cgroup" /proc/filesystems
1450 function _generateCgroupOptions
1454 hasCgroup || return 0
1456 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1457 if test -n "$file"; then
1458 read CGROUP_MNT < "$file"
1460 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1461 if test -n "$file"; then
1462 _readFileToArray CGROUP_SUBSYS "$file"
1464 CGROUP_SUBSYS=( $($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups) )
1466 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1467 if test -n "$file"; then
1468 _readFileToArray CGROUP_INHERIT "$file" ""
1470 findFile file "$__CONFDIR/.defaults/cgroup/base" ""
1471 if test -n "$file"; then
1472 read CGROUP_BASE < "$file"
1473 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
1474 CGROUP_BASE="${CGROUP_BASE}/"
1476 findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
1477 if test -n "$file"; then
1486 hasCgroup || return 1
1487 test -e "$CGROUP_MNT/tasks" || return 1
1489 if $_VSERVER_INFO - FEATURE memcg; then
1492 test -d "$1/cgroup" -o \
1493 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
1494 ! -e "$1/nocgroup" \)
1497 function _handleCgroup
1509 useCgroup "$vdir" || return 0
1511 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1513 if test -n "$dir" -a -r "$dir"/name; then
1514 read name < "$dir"/name
1516 name="$VSERVER_NAME"
1519 if test -n "$CGROUP_MNT_PER_SS"; then
1521 for ss in $($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups); do
1522 mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
1525 mnts=( "$CGROUP_MNT" )
1527 for mnt in "${mnts[@]}"; do
1528 if test "$action" = "attach"; then
1529 if test -n "$CGROUP_BASE"; then
1531 i="$mnt/$CGROUP_BASE"
1532 while test "$mnt" != "$i"; do
1533 dirs=( "$i" "${dirs[@]}" )
1536 for i in "${dirs[@]}"; do
1537 if mkdir "$i" 2>/dev/null; then
1539 for j in "${CGROUP_INHERIT[@]}"; do
1540 test -f "$parent/$j" || continue
1541 cat "$parent/$j" > "$i/$j"
1546 if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
1547 parent="$mnt/$CGROUP_BASE$name"
1548 parent="${parent%/*}"
1549 for i in "${CGROUP_INHERIT[@]}"; do
1550 test -f "$parent/$i" || continue
1551 cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i"
1554 if test -n "$dir"; then
1556 for i in "$dir"/*; do
1558 test "$f" != mnt -a "$f" != subsys -a \
1559 "$f" != inherit -a "$f" != name -a "$f" != base \
1561 cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
1565 echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
1566 elif test "$action" = "destroy"; then
1567 rmdir "$mnt/$name" 2>/dev/null || :
1574 function attachToCgroup
1576 _handleCgroup attach "$@"
1579 function destroyCgroup
1581 _handleCgroup destroy "$@"