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 )
82 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
84 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
90 function _readFileToArray
97 test -e "$_rfta_f" || return 0
98 while read _rfta_v; do
101 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
106 function _generateChbindOptions
114 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
116 if test -e "$vdir"/noncontext -o \
117 \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
118 _HAVE_CHBIND_OPTIONS=1
122 local f="$vdir"/interfaces/bcast
123 getFileValue bcast "$f"
124 f="$vdir"/interfaces/lback
125 getFileValue lback "$f"
127 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
128 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
131 for i in "${INTERFACES[@]}"; do
132 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
135 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
136 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
138 _HAVE_CHBIND_OPTIONS=1
141 function _generateNiceCommand
145 local current_nice=`$_NICE`
147 test -r "$vdir/nice" && read nice <"$vdir"/nice
149 let nice=$nice-$current_nice || :
150 NICE_CMD=( $_NICE -n $nice )
153 function _generateIONiceCommand
157 local ionice_priority=0
159 test -n "$_IONICE" || return 0
161 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
162 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
164 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
167 function _generatePersonalityOptions
170 local f="$vdir"/personality
173 test -s "$f" || return 0
182 (*) flags=$flags$delim$tmp
189 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
190 --personality-type "$type"
191 ${flags:+--personality-flags "$flags"} )
194 function _generateCCapabilityOptions
198 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
201 function _generateBCapabilityOptions
205 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
208 function _generateCapabilityOptions
213 _generateBCapabilityOptions "$vdir"
214 _generateCCapabilityOptions "$vdir"
216 test -e "$vdir"/capabilities || return 0
225 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
226 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
229 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
232 done <"$vdir"/capabilities
235 function getEnterShell
242 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
244 test -n "$ENTER_SHELL" || {
246 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
248 test -x "$vdir/vdir/$1" || continue
255 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
256 function sendKillSequence
262 while isCtxRunning "$ctx"; do
263 test -z "$wait" || sleep "$wait"
265 killContext "$ctx" "$1"
266 test -n "$2" || break
272 function _generateInitOptions
275 local cfgdir=$vdir/apps/init
280 INITCMD_START_SYNC=()
285 INITKILL_SEQ=( 15 5 9 )
286 CHCONTEXT_INIT_OPTS=()
289 test x"$INITSTYLE" = xrescue || \
290 getFileValue INITSTYLE "$cfgdir"/style
291 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
292 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
293 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
294 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
296 findFile _gio_env "$cfgdir"/environment \
297 "$__CONFDIR"/.defaults/apps/init/environment \
298 "$__PKGLIBDEFAULTDIR"/environment
299 getFileArray OPTS_ENV "$_gio_env" || :
301 case x"$INITSTYLE" in
303 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
304 INITCMD_STOP=( /sbin/killall5 )
308 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
309 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
311 for i in /etc/init.d/rc /etc/rc.d/rc; do
312 test -x "$vdir/vdir/$i" || continue
313 INITCMD_START=( "$i" "$RUNLEVEL_START" )
314 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
316 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
317 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
318 if test -n "$OPTION_DEBUG_SYSV"; then
319 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
320 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
325 INITCMD_START=( /sbin/init )
326 INITCMD_STOP=( /sbin/init )
328 _NEED_VSHELPER_SYNC=1
329 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
330 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
334 INITCMD_START=( /sbin/minit-start )
335 INITCMD_STOP=( /sbin/minit-stop )
337 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
338 _NEED_VSHELPER_SYNC=1
339 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
340 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
341 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
345 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
346 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
348 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
349 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
350 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
351 RC_WRAP=/lib/rc/sh/init-vserver.sh
353 panic "init-vserver.sh not found; aborting"
356 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
357 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
358 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
359 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
363 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
364 INITCMD_START=( /etc/rc.multi )
365 INITCMD_STOP=( /etc/rc.shutdown )
366 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
370 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
373 if test x"$INITSTYLE" != xrescue; then
374 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
375 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
376 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
377 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
378 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
381 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
382 INITCMD_START_SYNC=()
387 if vshelper.isEnabled; then
388 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
394 function _generateFlagOptions
399 CHCONTEXT_FLAG_OPTS=()
401 findFile file "$vdir"/cflags "$vdir"/flags ""
411 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
412 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
418 isAvoidNamespace "$vdir" || {
420 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
421 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
422 OPT_VCONTEXT_CHROOT=--pivot-root
426 function _generateChcontextOptions
429 local ctx hostname domainname
434 read ctx <"$vdir"/context || :
436 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
437 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
440 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
442 _generateCapabilityOptions "$vdir"
443 _generateFlagOptions "$vdir"
445 CHCONTEXT_OPTS=( $SILENT_OPT \
446 "${CHCONTEXT_FLAG_OPTS[@]}" \
449 ${ctx:+--ctx "$ctx"} \
450 ${hostname:+--hostname "$hostname"} \
451 ${domainname:+--domainname "$domainname"} )
453 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
454 ${ctx:+--xid "$ctx"} )
455 ## put '--secure' at front so that it can be overridden
456 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
459 function _generateScheduleOptions
462 if test -d "$vdir"/sched; then
463 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
467 local f="$vdir"/schedule
468 test -e "$f" || return 0
470 local fill_rate interval tokens tokens_min tokens_max prio_bias
478 read prio_bias || prio_bias=
482 test -n "$prio_bias" || {
483 echo $"Bad content in '$f'; aborting..." >&2
487 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
488 --tokens "$tokens" --tokens_min "$tokens_min" \
489 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
492 function _getInterfaceValue
502 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
505 : ${_giv_tmp:=$_giv_dflt}
506 eval $_giv_val=\$_giv_tmp
509 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
510 function _transformMask2Prefix
514 test -n "$_tm2p_tmp" || {
515 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
522 function _addInterfaceCmd
524 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
525 let ++INTERFACE_CMDS_IDX
528 ## Usage: _generateMac <var> <iface> <ctx>
529 function _generateMac
532 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
536 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
539 function _getVLANInfo
544 creation of VLAN_PLUS_VID devices is not supported; please create them
545 before starting the vserver and use the 'nodev' flag then"
546 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
550 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
551 create them before starting the vserver and use the 'nodev' flag then"
552 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
554 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
555 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
566 test -e "$iface/tun" -o -e "$iface/tap" || return 1
567 test ! -e "$iface/tun" || echo --tun
568 test ! -e "$iface/tap" || echo --tap
569 test ! -e "$iface/nocsum" || echo --~checksum
570 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
571 if test -e "$iface/uid"; then
573 getFileValue uid "$iface/uid"
576 if test -e "$iface/gid"; then
578 getFileValue gid "$iface/gid"
581 if test -e "$iface/linktype"; then
583 getFileValue linktype "$iface/linktype"
584 echo --linktype "$linktype"
589 ## Usage: _processSingleInterface <interface-directory>
590 function _processSingleInterface
606 _getInterfaceValue ip '' "$iface"
607 _getInterfaceValue extip '' "$iface" "$iface/.."
608 _getInterfaceValue dev '' "$iface" "$iface/.."
609 _getInterfaceValue prefix '' "$iface" "$iface/.."
610 _getInterfaceValue mask '' "$iface" "$iface/.."
611 _getInterfaceValue bcast '' "$iface" "$iface/.."
612 _getInterfaceValue name '' "$iface"
613 _getInterfaceValue scope '' "$iface" "$iface/.."
614 _getInterfaceValue mac '' "$iface"
615 _getInterfaceValue peer '' "$iface"
617 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
618 test -n "$dev" -o -e "$iface"/nodev || {
619 echo $"No device specified for '$iface'" >&2
623 test ! -e "$iface"/down || up=
626 _transformMask2Prefix prefix "$prefix" "$mask"
627 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
629 test ! -e "$iface"/nodev || break
631 test ! -e "$iface"/only_ip || break
633 test -e "$iface/vlandev" \
634 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
635 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
636 -a ! -e "$iface/novlandev" \
637 -a ! -e "$iface/../novlandev" \) && {
639 if vlan_info=$(_getVLANInfo "$dev"); then
640 test -d /proc/net/vlan || {
641 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
644 _addInterfaceCmd VCONFIG $vlan_info
648 if ! test -e "$iface"/indirect; then
650 local use_bcast="broadcast ${bcast:-+}"
651 echo "$ip" | $_GREP -q : && use_bcast=
654 if tun_info=$(_getTunInfo "$iface"); then
655 _addInterfaceCmd TUNCTL "$dev" $tun_info
658 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
659 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
660 _addInterfaceCmd IP_LINK "$dev" $up
661 elif ! test -n "$N_CONTEXT"; then
662 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
665 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
666 _addInterfaceCmd MODPROBE dummy "$dev"
667 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
668 _addInterfaceCmd NAMEIF "$dev" "$mac"
669 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
670 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
677 ## Usage: _generateInterfaceOptions <vserver-directory>
678 function _generateInterfaceOptions
682 # XXX: This is here instead of in _generateChbindOptions
683 # to avoid a circular dependency
684 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
685 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
687 for iface in "$1/interfaces/"*; do
688 test -d "$iface" || continue
689 test ! -e "$iface"/disabled || continue
691 _processSingleInterface "$iface"
693 _HAVE_INTERFACE_OPTIONS=1
696 function enableInterfaces
701 lock "$__LOCKDIR"/vserver.interfaces
703 while test $i -lt $INTERFACE_CMDS_IDX; do
704 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
715 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
717 NAMEIF) $_NAMEIF "$@";;
718 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
719 $_VCONFIG add "$2" "$3" >/dev/null;;
720 IP_ADDR) $_IP addr add "$@";;
721 IP_ADDR_FLUSH) $_IP addr flush "$@";;
722 IP_LINK) $_IP link set "$@";;
723 IP_ROUTE) $_IP route add "$@";;
727 $_TUNCTL --persist "$@" "$dev"
729 *) echo "Unknown interface-command type '$type'" >&2; false;;
738 function disableInterfaces
740 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
742 local i=$INTERFACE_CMDS_IDX
745 lock "$__LOCKDIR"/vserver.interfaces
747 while test $i -gt 0; do
750 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
757 MODPROBE) $_RMMOD "${2:-$1}";;
759 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
760 IP_ADDR) $_IP addr del "$@";;
762 IP_LINK) ;; ## Ignore the link-down command for now
763 IP_ROUTE) $_IP route del "$@";;
764 TUNCTL) $_TUNCTL --~persist "$1";;
765 *) echo "Unknown interface-command type '$type'" >&2; false;;
772 function _generateTagOptions
777 getFileValue tag "$vdir/tag" "$vdir/context"
778 test -n "$tag" || return 0
780 OPTS_VTAG_CREATE=( --tag "$tag" )
781 OPTS_VTAG_ENTER=( --tag "$tag" )
784 function _generateMemctrlOptions
789 getFileValue badness "$vdir/badness"
790 test -n "$badness" || return 0
792 OPTS_VMEMCTRL=( --badness "$badness" )
795 function _generateSpaceOptions
798 local d="$vdir"/spaces
802 for space in pid net; do
803 if test -e "$d"/$space; then
804 getFileValue shared "$d"/$space || shared=""
805 if test -z "$shared"; then
806 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
807 elif test "$shared" = "0"; then
810 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
811 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
817 getFileValue mask "$d"/mask || \
818 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
821 ## Usage: prepareInit <vserver-directory>
824 pushd "$1/vdir" >/dev/null
827 { $_FIND var/run ! -type d -print0; \
828 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
831 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
832 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
837 "${INITCMD_PREPARE[@]}"
841 ## Usage: prepareInit <vserver-directory>
844 pushd "$1/vdir" >/dev/null
847 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
850 "${STOPCMD_PREPARE[@]}"
855 function generateOptions
857 _generateInterfaceOptions "$1"
858 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
859 _generateNiceCommand "$1"
860 _generateIONiceCommand "$1"
861 _generateInitOptions "$1"
862 _generateChcontextOptions "$1"
863 _generateScheduleOptions "$1"
864 _generatePersonalityOptions "$1"
865 _generateTagOptions "$1"
866 _generateMemctrlOptions "$1"
867 _generateSpaceOptions "$1"
868 _generateCgroupOptions
870 if test -n "$_IS_FAKEINIT"; then
871 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
872 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
880 local f="$vdir"/cpuset
884 test -d "$f" || return 0
885 test -e "$f"/name || return 0
887 read cpuset < "$f"/name
888 test -e "$f"/nocreate || {
889 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
890 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
891 if test -e "$f"/"$i"; then
892 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
900 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
901 if [ "$configured" -ne 0 ]; then
903 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
904 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
909 function removeCPUSET
913 local f="$vdir"/cpuset
915 test -d "$f" || return 0
916 test -e "$f"/name || return 0
918 read cpuset < "$f"/name
919 test -e "$f"/nocreate || {
920 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
924 function _mountVserverInternal
929 test -e "$fstab" || return 0
932 pushd "$vdir" >/dev/null
933 # check whether / is mounted readonly or whether there is special
934 # magic regarding the mtab file; when etc/mtab can not be touched,
935 # add the '-n' flag to mount
936 test -w etc -o -w etc/mtab || xflag=-n
937 if test -h etc/mtab; then
938 local l=$($_READLINK etc/mtab)
939 test "${l##/proc/}" = "$l" || xflag=-n
941 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
949 local fstab="$cfgdir"/fstab
952 test -e "$fstab" || return 0
953 pushd "$vdir" >/dev/null
954 # check whether / is mounted readonly or whether there is special
955 # magic regarding the mtab file; when etc/mtab can not be touched,
956 # add the '-n' flag to mount
957 test -w etc -o -w etc/mtab || xflag=-n
958 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
962 function mountVserver
971 test -e "$cfgdir"/fstab -o \
972 -e "$cfgdir"/fstab.local -o \
973 -e "$cfgdir"/fstab.remote || return 0
975 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
977 pushd "$vdir" >/dev/null
978 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
981 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
983 _mountVserverInternal "$cfgdir"/fstab
984 _mountVserverInternal "$cfgdir"/fstab.local
985 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
987 isNamespaceCleanup "$cfgdir" && \
988 _namespaceCleanup "$cfgdir"
990 real_vdir=$(getPhysicalDir "$vdir")
991 isAvoidNamespace "$cfgdir" || \
992 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
993 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
994 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
997 function _umountVserverInternal
1000 test -e "$fstab" || return 0
1005 while read src dst tmp; do
1006 test -n "$tmp" || continue
1012 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1018 function umountVserver
1024 isAvoidNamespace "$cfgdir" || return 0
1025 test -e "$cfgdir"/fstab -o \
1026 -e "$cfgdir"/fstab.local -o \
1027 -e "$cfgdir"/fstab.remote || return 0
1028 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1030 pushd "$vdir/" >/dev/null || return 1
1031 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1032 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1033 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1034 popd >/dev/null || return 1
1042 local fstab="$cfgdir"/fstab
1046 test -e "$fstab" || return 0
1048 export FSTAB_FILE="$fstab"
1051 test "$fsck_exitcode" -eq 0 -o \
1052 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1055 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1059 test -n "$_NEED_VSHELPER_SYNC" && \
1060 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1062 vshelper.initSync "$1" "$3" "$_is_meth"
1065 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1068 if $_VSERVER_INFO - FEATURE vwait; then
1070 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1073 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1074 --status-fd 3 "$2" \
1075 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1078 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1079 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1080 killContext "$S_CONTEXT" 9
1084 ) 4>$_is_tmpdir/procs &
1086 echo "$!" >$_is_tmpdir/pid
1087 eval "$3"=$_is_tmpdir
1092 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1093 function _waitForVWait
1098 declare -r procs=$(cat $4)
1100 getFileArray status "$2"
1105 'vwait' exited with error '$2' which indicates that vserver could not
1106 be stopped properly"
1109 (KILLED) warning $"\
1110 A timeout occured while waiting for the vserver to finish and it was
1111 killed by sending a SIGKILL signal. Please investigate the reasons
1112 and/or increase the timeout in apps/vshelper/sync-timeout."
1115 (TIMEOUT) warning $"\
1116 A timeout occured while waiting for the vserver to finish and it will
1117 be killed by sending a SIGKILL signal. The following process list
1118 might be useful for finding out the reason of this behavior:
1120 ----------------------------------------------------------------------
1122 }----------------------------------------------------------------------"
1125 (\?\?\?|*) warning $"\
1126 internal error: 'vwait' exited with an unexpected status '$1'; I will
1127 try to continue but be prepared for unexpected events."
1134 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1135 function waitForSync
1139 local vwait_statdir=$3
1142 if test -d "$vwait_statdir"; then
1143 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1144 elif test -n "$_NEED_VSHELPER_SYNC"; then
1145 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1147 A timeout or other error occured while waiting for the synchronization
1148 signal from vserver '$VSERVER_NAME'.
1149 The vserver will be killed nevertheless..."
1150 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1151 "${INITCMD_STOP_SYNC[@]}" || \
1153 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1154 will be killed nevertheless..."
1157 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1161 function _sourceWrap
1163 local vdir name flavor start i already_handled base
1167 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1168 function execScriptlets
1172 declare -r flavor=$3
1175 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1176 local DONT_SKIP_DEFAULTS=
1177 local already_handled=
1179 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1180 isRegularFile "$i" || continue
1181 test -r "$i" || continue
1185 test -x "$i" || start=_sourceWrap
1186 $start "$i" "$flavor" "$name"
1189 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1194 function sanityCheck
1196 declare -r cfgdir=$1
1198 ! test -e "$cfgdir"/fstab.local ||
1200 WARNING: 'fstab' will *not* be executed in the network context of the
1201 vserver anymore. Therefore, 'fstab.local' has the same functionality
1202 and is obsoleted. When you need the old behaviour, put the mounts
1203 into 'fstab.remote'"
1205 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1207 WARNING: The hostname is now configured in 'uts/nodename' but not in
1210 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1212 WARNING: The domainname is now configured in 'uts/domainname' but not
1213 in 'domainname'." >&2
1217 for i in "$cfgdir"/interfaces/*/only_ip; do
1218 if test -e "$i"; then
1220 iface=${i##$cfgdir/interfaces/}
1221 iface=${iface%%/only_ip}
1223 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1228 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1230 WARNING: There is no cachedirectory configured for this vserver;
1231 please create '$cfgdir/cache' e.g. by executing
1233 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1236 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1238 vshelper.doSanityCheck
1240 $_VSERVER_INFO - VERIFYCAP ||
1241 panic $"capabilities are not enabled in kernel-setup"
1243 $_VSERVER_INFO - VERIFYPROC ||
1245 /proc/uptime can not be accessed. Usually, this is caused by
1246 procfs-security. Please read the FAQ for more details
1247 http://linux-vserver.org/Proc-Security"
1249 test -e "$cfgdir"/context || {
1250 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1251 test "$TYPE" != "static" || panic $"\
1252 The kernel does not have dynamic contexts enabled. Please configure
1253 a static one by executing
1255 echo [number between 2 and 49151] > $cfgdir/context"
1260 function _setSingleDiskLimit
1272 getFileValue ctx "$vdir/context"
1273 getFileValue directory "$dlimit/directory" || return 0
1274 getFileValue space_total "$dlimit/space_total" || return 0
1275 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1276 getFileValue reserved "$dlimit/reserved" || return 0
1278 local cachename=$ctx$directory
1279 cachename=dlimits/${cachename//\//_}
1281 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1282 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1283 $_RM -f "$vdir/cache/$cachename"
1285 if test -z "$inodes_used" -o -z "$space_used"; then
1287 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1288 inodes_used=${tmpvdu##* }
1289 space_used=${tmpvdu%% *}
1292 $_VDLIMIT --xid $ctx \
1293 --set space_used=$space_used \
1294 --set space_total=$space_total \
1295 --set inodes_used=$inodes_used \
1296 --set inodes_total=$inodes_total \
1297 --set reserved=$reserved \
1302 function setDiskLimits
1307 # Disk Limits without a static context are useless
1308 test -e "$vdir"/context || return 0
1310 for dlimit in "$vdir/dlimits/"*; do
1311 test -d "$dlimit" || continue
1312 test ! -e "$dlimit/disabled" || continue
1314 _setSingleDiskLimit "$vdir" "$dlimit"
1319 function _saveSingleDiskLimit
1326 getFileValue ctx "$vdir/context"
1327 getFileValue directory "$dlimit/directory" || return 0
1329 local cachename=$ctx$directory
1330 cachename=${cachename//\//_}
1332 # Things are getting ugly here... LFS says that /var/cache (where
1333 # cachename is usually pointing to) can vanish and applications
1334 # have to deal with it. So, we have to interprete the $vdir/cache
1335 # symlink and have to create the needed directories manually.
1336 if test -d "$vdir/cache"; then
1337 : # ok, exists already
1338 elif test -L "$vdir/cache"; then
1339 # it's a dangling symlink
1341 link=$($_READLINK "$vdir/cache")
1342 ( cd $vdir && $_MKDIR -p "$link" )
1347 test -d "$vdir/cache"
1348 $_MKDIR -p "$vdir"/cache/dlimits
1350 $_VDLIMIT --xid $ctx "$directory" | \
1351 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1353 $_VDLIMIT --xid $ctx --remove "$directory"
1357 function saveDiskLimits
1362 test -e "$vdir"/context || return 0
1364 for dlimit in "$vdir/dlimits/"*; do
1365 test -d "$dlimit" || continue
1366 test ! -e "$dlimit/disabled" || continue
1368 _saveSingleDiskLimit "$vdir" "$dlimit"
1372 function _namespaceCleanup
1375 local root=$($_VSERVER_INFO "$1" VDIR 1)
1381 getFileArray skip "$vdir"/namespace-cleanup-skip \
1382 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1384 # these are things that have to be accessible post-cleanup
1385 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1386 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1387 local real=`getPhysicalDir "$i"`
1388 test "$i" != "$real" || real=
1389 for j in "$i" "$real"; do
1390 while test -n "$j"; do
1391 list=( "${list[@]}" "$j" )
1397 local -a list_umount
1398 while read -r dev path opts; do
1399 test -n "$path" || continue
1400 for i in "$root" /dev /proc; do
1402 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1404 for i in "${list[@]}" /; do
1405 test "$path" = "$i" && continue 2
1407 # unmount them in reverse order so mounts further down the tree get unmounted first
1408 list_umount=( "$path" "${list_umount[@]}" )
1410 # separate loop to avoid races while reading /proc/mounts
1411 for i in "${list_umount[@]}"; do
1412 $_UMOUNT -l -n -i "$i"
1416 function handleDeviceMap
1421 local flags device target
1423 test -d "$dir" || return 0
1424 test -n "$xid" || return 0
1426 for i in "$dir"/*; do
1427 test -d "$i" || continue
1429 local -a vdevmap_opts=()
1430 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1431 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1432 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1434 getFileValue flags "$i/flags" || :
1435 getFileValue device "$i/device" || :
1436 getFileValue target "$i/target" || :
1437 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1438 ${device:+--device "$device"} ${target:+--target "$target"} )
1440 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1446 $_GREP -q "cgroup" /proc/filesystems
1449 function _generateCgroupOptions
1453 hasCgroup || return 0
1455 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1456 if test -n "$file"; then
1457 read CGROUP_MNT < "$file"
1459 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1460 if test -n "$file"; then
1461 read CGROUP_SUBSYS < "$file"
1462 elif $_GREP -q '^ns[[:space:]]' /proc/cgroups; then
1463 # Hack for the ns subsystem, with which we are incompatible
1464 CGROUP_SUBSYS=$($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups | \
1465 (s=""; while read x; do test -n "$s" && s="$s,"; s="$s$x"; done; echo "$s"))
1467 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1468 if test -n "$file"; then
1469 _readFileToArray CGROUP_INHERIT "$file" ""
1471 findFile file "$__CONFDIR/.defaults/cgroup/base" ""
1472 if test -n "$file"; then
1473 read CGROUP_BASE < "$file"
1474 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
1475 CGROUP_BASE="${CGROUP_BASE}/"
1483 hasCgroup || return 1
1484 test -d "$CGROUP_MNT" || return 1
1486 if $_VSERVER_INFO - FEATURE memcg; then
1489 test -d "$1/cgroup" -o \
1490 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
1491 ! -e "$1/nocgroup" \)
1494 function _handleCgroup
1504 useCgroup "$vdir" || return 0
1506 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1508 if test -n "$dir" -a -r "$dir"/name; then
1509 read name < "$dir"/name
1511 name="$VSERVER_NAME"
1514 if test "$action" = "attach"; then
1515 if test -n "$CGROUP_BASE"; then
1517 i="$CGROUP_MNT/$CGROUP_BASE"
1518 while test "$CGROUP_MNT" != "$i"; do
1519 dirs=( "$i" "${dirs[@]}" )
1522 for i in "${dirs[@]}"; do
1523 if mkdir "$i" 2>/dev/null; then
1525 for j in "${CGROUP_INHERIT[@]}"; do
1526 test -f "$parent/$j" || continue
1527 cat "$parent/$j" > "$i/$j"
1532 if mkdir "$CGROUP_MNT/$CGROUP_BASE$name" 2>/dev/null; then
1533 parent="$CGROUP_MNT/$CGROUP_BASE$name"
1534 parent="${parent%/*}"
1535 for i in "${CGROUP_INHERIT[@]}"; do
1536 test -f "$parent/$i" || continue
1537 cat "$parent/$i" > "$CGROUP_MNT/$CGROUP_BASE$name/$i"
1540 if test -n "$dir"; then
1542 for i in "$dir"/*; do
1544 test "$f" != mnt -a "$f" != subsys -a \
1545 "$f" != inherit -a "$f" != name -a "$f" != base \
1547 cat "$i" > "$CGROUP_MNT/$CGROUP_BASE$name/$f"
1551 echo "$$" > "$CGROUP_MNT/$CGROUP_BASE$name/tasks"
1552 elif test "$action" = "destroy"; then
1553 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1559 function attachToCgroup
1561 _handleCgroup attach "$@"
1564 function destroyCgroup
1566 _handleCgroup destroy "$@"