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 OPT_VCONTEXT_CLOSE_FD=""
46 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
47 declare -a OPTS_VSCHED=()
48 declare -a OPTS_ENV=()
49 declare -a OPTS_VTAG_CREATE=()
50 declare -a OPTS_VTAG_ENTER=()
51 declare -a OPTS_VMEMCTRL=()
52 declare -a OPTS_VSPACE=( --default )
53 declare -a OPTS_VSPACE_SHARED=()
54 declare -a VSPACE_SHARED_CMD=()
56 declare -a STOPCMD_PREPARE=()
58 declare -a VSERVER_EXTRA_CMDS=()
61 VSHELPER_SYNC_TIMEOUT=30
66 _HAVE_INTERFACE_OPTIONS=
78 CGROUP_MNT=/dev/cgroup
79 declare -a CGROUP_SUBSYS=()
80 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
84 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
86 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
92 function _readFileToArray
99 test -e "$_rfta_f" || return 0
100 while read _rfta_v; do
103 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
108 function _generateChbindOptions
116 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
118 if test -e "$vdir"/noncontext -o \
119 \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
120 _HAVE_CHBIND_OPTIONS=1
124 local f="$vdir"/interfaces/bcast
125 getFileValue bcast "$f"
126 f="$vdir"/interfaces/lback
127 getFileValue lback "$f"
129 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
130 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
133 for i in "${INTERFACES[@]}"; do
134 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
137 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
138 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
140 _HAVE_CHBIND_OPTIONS=1
143 function _generateNiceCommand
147 local current_nice=`$_NICE`
149 test -r "$vdir/nice" && read nice <"$vdir"/nice
151 let nice=$nice-$current_nice || :
152 NICE_CMD=( $_NICE -n $nice )
155 function _generateIONiceCommand
159 local ionice_priority=
161 test -n "$_IONICE" || return 0
163 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
164 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
166 test -n "$ionice_class$ionice_priority" || return 0
168 if test -z "$ionice_class" -a -n "$ionice_priority"; then
169 IONICE_CMD=( $_IONICE -c2 -n"$ionice_priority" )
171 IONICE_CMD=( $_IONICE ${ionice_class:+-c$ionice_class} ${ionice_priority:+-n$ionice_priority} )
175 function _generatePersonalityOptions
178 local f="$vdir"/personality
181 test -s "$f" || return 0
190 (*) flags=$flags$delim$tmp
197 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
198 --personality-type "$type"
199 ${flags:+--personality-flags "$flags"} )
202 function _generateCCapabilityOptions
206 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
209 function _generateBCapabilityOptions
213 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
216 function _generateUMaskOptions
220 _readFileToArray "$vdir"/umask OPTS_VATTRIBUTE --umask
223 function _generateCapabilityOptions
228 _generateBCapabilityOptions "$vdir"
229 _generateCCapabilityOptions "$vdir"
231 test -e "$vdir"/capabilities || return 0
240 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
241 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
244 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
247 done <"$vdir"/capabilities
250 function getEnterShell
257 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
259 test -n "$ENTER_SHELL" || {
261 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
263 test -x "$vdir/vdir/$1" || continue
270 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
271 function sendKillSequence
277 while isCtxRunning "$ctx"; do
278 test -z "$wait" || sleep "$wait"
280 killContext "$ctx" "$1"
281 test -n "$2" || break
287 function _generateInitOptions
290 local cfgdir=$vdir/apps/init
295 INITCMD_START_SYNC=()
300 INITKILL_SEQ=( 15 5 9 )
301 CHCONTEXT_INIT_OPTS=()
304 test x"$INITSTYLE" = xrescue || \
305 getFileValue INITSTYLE "$cfgdir"/style
306 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
307 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
308 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
309 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
311 findFile _gio_env "$cfgdir"/environment \
312 "$__CONFDIR"/.defaults/apps/init/environment \
313 "$__PKGLIBDEFAULTDIR"/environment
314 getFileArray OPTS_ENV "$_gio_env" || :
316 case x"$INITSTYLE" in
318 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
319 INITCMD_STOP=( /sbin/killall5 )
323 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
324 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
326 for i in /etc/init.d/rc /etc/rc.d/rc; do
327 test -x "$vdir/vdir/$i" || continue
328 INITCMD_START=( "$i" "$RUNLEVEL_START" )
329 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
331 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
332 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
333 if test -n "$OPTION_DEBUG_SYSV"; then
334 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
335 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
340 INITCMD_START=( /sbin/init )
341 INITCMD_STOP=( /sbin/init )
343 _NEED_VSHELPER_SYNC=1
344 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
345 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
349 INITCMD_START=( /sbin/minit-start )
350 INITCMD_STOP=( /sbin/minit-stop )
352 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
353 _NEED_VSHELPER_SYNC=1
354 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
355 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
356 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
360 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
361 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
363 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
364 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
365 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
366 RC_WRAP=/lib/rc/sh/init-vserver.sh
368 panic "init-vserver.sh not found; aborting"
371 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
372 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
373 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
374 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
378 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
379 INITCMD_START=( /etc/rc.multi )
380 INITCMD_STOP=( /etc/rc.shutdown )
381 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
385 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
388 if test x"$INITSTYLE" != xrescue; then
389 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
390 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
391 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
392 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
393 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
396 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
397 INITCMD_START_SYNC=()
402 if vshelper.isEnabled; then
403 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
409 function _generateFlagOptions
414 CHCONTEXT_FLAG_OPTS=()
416 findFile file "$vdir"/cflags "$vdir"/flags ""
426 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
427 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
433 isAvoidNamespace "$vdir" || {
435 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
436 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
437 OPT_VCONTEXT_CHROOT=--pivot-root
441 function _generateChcontextOptions
444 local ctx hostname domainname
449 read ctx <"$vdir"/context || :
451 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
452 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
455 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
457 _generateCapabilityOptions "$vdir"
458 _generateFlagOptions "$vdir"
459 _generateUMaskOptions "$vdir"
461 CHCONTEXT_OPTS=( $SILENT_OPT \
462 "${CHCONTEXT_FLAG_OPTS[@]}" \
465 ${ctx:+--ctx "$ctx"} \
466 ${hostname:+--hostname "$hostname"} \
467 ${domainname:+--domainname "$domainname"} )
469 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
470 ${ctx:+--xid "$ctx"} )
471 findFile file "$vdir"/keepfds "$__CONFDIR/.defaults/keepfds" ""
472 test -n "$file" || OPT_VCONTEXT_CLOSE_FD=( "--closefd" )
473 ## put '--secure' at front so that it can be overridden
474 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
477 function _generateScheduleOptions
480 if test -d "$vdir"/sched; then
481 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
485 local f="$vdir"/schedule
486 test -e "$f" || return 0
488 local fill_rate interval tokens tokens_min tokens_max prio_bias
496 read prio_bias || prio_bias=
500 test -n "$prio_bias" || {
501 echo $"Bad content in '$f'; aborting..." >&2
505 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
506 --tokens "$tokens" --tokens_min "$tokens_min" \
507 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
510 function _getInterfaceValue
520 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
523 : ${_giv_tmp:=$_giv_dflt}
524 eval $_giv_val=\$_giv_tmp
527 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
528 function _transformMask2Prefix
532 test -n "$_tm2p_tmp" || {
533 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
540 function _addInterfaceCmd
542 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
543 let ++INTERFACE_CMDS_IDX
546 ## Usage: _generateMac <var> <iface> <ctx>
547 function _generateMac
550 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
554 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
557 function _getVLANInfo
562 creation of VLAN_PLUS_VID devices is not supported; please create them
563 before starting the vserver and use the 'nodev' flag then"
564 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
568 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
569 create them before starting the vserver and use the 'nodev' flag then"
570 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
572 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
573 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
584 test -e "$iface/tun" -o -e "$iface/tap" || return 1
585 test ! -e "$iface/tun" || echo --tun
586 test ! -e "$iface/tap" || echo --tap
587 test ! -e "$iface/nocsum" || echo --~checksum
588 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
589 if test -e "$iface/uid"; then
591 getFileValue uid "$iface/uid"
594 if test -e "$iface/gid"; then
596 getFileValue gid "$iface/gid"
599 if test -e "$iface/linktype"; then
601 getFileValue linktype "$iface/linktype"
602 echo --linktype "$linktype"
607 ## Usage: _processSingleInterface <interface-directory>
608 function _processSingleInterface
624 _getInterfaceValue ip '' "$iface"
625 _getInterfaceValue extip '' "$iface" "$iface/.."
626 _getInterfaceValue dev '' "$iface" "$iface/.."
627 _getInterfaceValue prefix '' "$iface" "$iface/.."
628 _getInterfaceValue mask '' "$iface" "$iface/.."
629 _getInterfaceValue bcast '' "$iface" "$iface/.."
630 _getInterfaceValue name '' "$iface"
631 _getInterfaceValue scope '' "$iface" "$iface/.."
632 _getInterfaceValue mac '' "$iface"
633 _getInterfaceValue peer '' "$iface"
635 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
636 test -n "$dev" -o -e "$iface"/nodev || {
637 echo $"No device specified for '$iface'" >&2
641 test ! -e "$iface"/down || up=
644 _transformMask2Prefix prefix "$prefix" "$mask"
645 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
647 test ! -e "$iface"/nodev || break
649 test ! -e "$iface"/only_ip || break
651 test -e "$iface/vlandev" \
652 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
653 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
654 -a ! -e "$iface/novlandev" \
655 -a ! -e "$iface/../novlandev" \) && {
657 if vlan_info=$(_getVLANInfo "$dev"); then
658 test -d /proc/net/vlan || {
659 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
662 _addInterfaceCmd VCONFIG $vlan_info
666 if ! test -e "$iface"/indirect; then
668 local use_bcast="broadcast ${bcast:-+}"
669 echo "$ip" | $_GREP -q : && use_bcast=
672 if tun_info=$(_getTunInfo "$iface"); then
673 _addInterfaceCmd TUNCTL "$dev" $tun_info
676 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
677 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
678 _addInterfaceCmd IP_LINK "$dev" $up
679 elif ! test -n "$N_CONTEXT"; then
680 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
683 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
684 _addInterfaceCmd MODPROBE dummy "$dev"
685 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
686 _addInterfaceCmd NAMEIF "$dev" "$mac"
687 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
688 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
695 ## Usage: _generateInterfaceOptions <vserver-directory>
696 function _generateInterfaceOptions
700 # XXX: This is here instead of in _generateChbindOptions
701 # to avoid a circular dependency
702 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
703 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
705 for iface in "$1/interfaces/"*; do
706 test -d "$iface" || continue
707 test ! -e "$iface"/disabled || continue
709 _processSingleInterface "$iface"
711 _HAVE_INTERFACE_OPTIONS=1
714 function enableInterfaces
719 lock "$__LOCKDIR"/vserver.interfaces
721 while test $i -lt $INTERFACE_CMDS_IDX; do
722 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
733 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
735 NAMEIF) $_NAMEIF "$@";;
736 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
737 $_VCONFIG add "$2" "$3" >/dev/null;;
738 IP_ADDR) $_IP addr add "$@";;
739 IP_ADDR_FLUSH) $_IP addr flush "$@";;
740 IP_LINK) $_IP link set "$@";;
741 IP_ROUTE) $_IP route add "$@";;
745 $_TUNCTL --persist "$@" "$dev"
747 *) echo "Unknown interface-command type '$type'" >&2; false;;
756 function disableInterfaces
758 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
760 local i=$INTERFACE_CMDS_IDX
763 lock "$__LOCKDIR"/vserver.interfaces
765 while test $i -gt 0; do
768 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
775 MODPROBE) $_RMMOD "${2:-$1}";;
777 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
778 IP_ADDR) $_IP addr del "$@";;
780 IP_LINK) ;; ## Ignore the link-down command for now
781 IP_ROUTE) $_IP route del "$@";;
785 $_TUNCTL --~persist "$@" "$dev"
787 *) echo "Unknown interface-command type '$type'" >&2; false;;
794 function _generateTagOptions
799 getFileValue tag "$vdir/tag" "$vdir/context"
800 test -n "$tag" || return 0
802 OPTS_VTAG_CREATE=( --tag "$tag" )
803 OPTS_VTAG_ENTER=( --tag "$tag" )
806 function _generateMemctrlOptions
811 getFileValue badness "$vdir/badness"
812 test -n "$badness" || return 0
814 OPTS_VMEMCTRL=( --badness "$badness" )
817 function _generateSpaceOptions
820 local d="$vdir"/spaces
824 for space in pid net; do
825 if test -e "$d"/$space; then
826 getFileValue shared "$d"/$space || shared=""
827 if test -z "$shared"; then
828 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
829 elif test "$shared" = "0"; then
832 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
833 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
839 getFileValue mask "$d"/mask || \
840 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
843 ## Usage: prepareInit <vserver-directory>
846 pushd "$1/vdir" >/dev/null
849 local -a dirs=( $($_CHROOT_SH realpath /var/run /var/lock | $_SED 's!^/*!!' || :) )
851 for dir in "${dirs[@]}"; do
852 $_FIND $dir ! -type d -print0 | xargs -0r $_CHROOT_SH rm
856 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
857 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
862 "${INITCMD_PREPARE[@]}"
866 ## Usage: prepareInit <vserver-directory>
869 pushd "$1/vdir" >/dev/null
872 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
875 "${STOPCMD_PREPARE[@]}"
880 function generateOptions
882 _generateInterfaceOptions "$1"
883 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
884 _generateNiceCommand "$1"
885 _generateIONiceCommand "$1"
886 _generateInitOptions "$1"
887 _generateChcontextOptions "$1"
888 _generateScheduleOptions "$1"
889 _generatePersonalityOptions "$1"
890 _generateTagOptions "$1"
891 _generateMemctrlOptions "$1"
892 _generateSpaceOptions "$1"
893 _generateCgroupOptions
895 if test -n "$_IS_FAKEINIT"; then
896 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
897 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
905 local f="$vdir"/cpuset
909 test -d "$f" || return 0
910 test -e "$f"/name || return 0
912 read cpuset < "$f"/name
913 test -e "$f"/nocreate || {
914 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
915 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
916 if test -e "$f"/"$i"; then
917 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
925 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
926 if [ "$configured" -ne 0 ]; then
928 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
929 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
934 function removeCPUSET
938 local f="$vdir"/cpuset
940 test -d "$f" || return 0
941 test -e "$f"/name || return 0
943 read cpuset < "$f"/name
944 test -e "$f"/nocreate || {
945 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
949 function _mountVserverInternal
954 test -e "$fstab" || return 0
957 pushd "$vdir" >/dev/null
958 # check whether / is mounted readonly or whether there is special
959 # magic regarding the mtab file; when etc/mtab can not be touched,
960 # add the '-n' flag to mount
961 test -w etc -o -w etc/mtab || xflag=-n
962 if test -h etc/mtab; then
963 local l=$($_READLINK etc/mtab)
964 test "${l##/proc/}" = "$l" || xflag=-n
966 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
974 local fstab="$cfgdir"/fstab
977 test -e "$fstab" || return 0
978 pushd "$vdir" >/dev/null
979 # check whether / is mounted readonly or whether there is special
980 # magic regarding the mtab file; when etc/mtab can not be touched,
981 # add the '-n' flag to mount
982 test -w etc -o -w etc/mtab || xflag=-n
983 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
987 function mountVserver
996 test -e "$cfgdir"/fstab -o \
997 -e "$cfgdir"/fstab.local -o \
998 -e "$cfgdir"/fstab.remote || return 0
1000 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
1002 pushd "$vdir" >/dev/null
1003 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
1006 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1008 _mountVserverInternal "$cfgdir"/fstab
1009 _mountVserverInternal "$cfgdir"/fstab.local
1010 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
1012 isNamespaceCleanup "$cfgdir" && \
1013 _namespaceCleanup "$cfgdir"
1015 real_vdir=$(getPhysicalDir "$vdir")
1016 isAvoidNamespace "$cfgdir" || \
1017 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
1018 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
1019 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
1022 function _umountVserverInternal
1025 test -e "$fstab" || return 0
1030 while read src dst tmp; do
1031 test -n "$tmp" || continue
1037 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1043 function umountVserver
1049 isAvoidNamespace "$cfgdir" || return 0
1050 test -e "$cfgdir"/fstab -o \
1051 -e "$cfgdir"/fstab.local -o \
1052 -e "$cfgdir"/fstab.remote || return 0
1053 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1055 pushd "$vdir/" >/dev/null || return 1
1056 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1057 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1058 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1059 popd >/dev/null || return 1
1067 local fstab="$cfgdir"/fstab
1071 test -e "$fstab" || return 0
1073 export FSTAB_FILE="$fstab"
1076 test "$fsck_exitcode" -eq 0 -o \
1077 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1080 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1084 test -n "$_NEED_VSHELPER_SYNC" && \
1085 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1087 vshelper.initSync "$1" "$3" "$_is_meth"
1090 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1093 if $_VSERVER_INFO - FEATURE vwait; then
1095 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1098 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1099 --status-fd 3 "$2" \
1100 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1103 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1104 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1105 killContext "$S_CONTEXT" 9
1109 ) 4>$_is_tmpdir/procs &
1111 echo "$!" >$_is_tmpdir/pid
1112 eval "$3"=$_is_tmpdir
1117 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1118 function _waitForVWait
1123 declare -r procs=$(cat $4)
1125 getFileArray status "$2"
1130 'vwait' exited with error '$2' which indicates that vserver could not
1131 be stopped properly"
1134 (KILLED) warning $"\
1135 A timeout occured while waiting for the vserver to finish and it was
1136 killed by sending a SIGKILL signal. Please investigate the reasons
1137 and/or increase the timeout in apps/vshelper/sync-timeout."
1140 (TIMEOUT) warning $"\
1141 A timeout occured while waiting for the vserver to finish and it will
1142 be killed by sending a SIGKILL signal. The following process list
1143 might be useful for finding out the reason of this behavior:
1145 ----------------------------------------------------------------------
1147 }----------------------------------------------------------------------"
1150 (\?\?\?|*) warning $"\
1151 internal error: 'vwait' exited with an unexpected status '$1'; I will
1152 try to continue but be prepared for unexpected events."
1159 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1160 function waitForSync
1164 local vwait_statdir=$3
1167 if test -d "$vwait_statdir"; then
1168 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1169 elif test -n "$_NEED_VSHELPER_SYNC"; then
1170 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1172 A timeout or other error occured while waiting for the synchronization
1173 signal from vserver '$VSERVER_NAME'.
1174 The vserver will be killed nevertheless..."
1175 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1176 "${INITCMD_STOP_SYNC[@]}" || \
1178 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1179 will be killed nevertheless..."
1182 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1186 function _sourceWrap
1188 local vdir name flavor start i already_handled base
1192 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1193 function execScriptlets
1197 declare -r flavor=$3
1200 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1201 local DONT_SKIP_DEFAULTS=
1202 local already_handled=
1204 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1205 isRegularFile "$i" || continue
1206 test -r "$i" || continue
1210 test -x "$i" || start=_sourceWrap
1211 $start "$i" "$flavor" "$name"
1214 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1219 function sanityCheck
1221 declare -r cfgdir=$1
1223 ! test -e "$cfgdir"/fstab.local ||
1225 WARNING: 'fstab' will *not* be executed in the network context of the
1226 vserver anymore. Therefore, 'fstab.local' has the same functionality
1227 and is obsoleted. When you need the old behaviour, put the mounts
1228 into 'fstab.remote'"
1230 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1232 WARNING: The hostname is now configured in 'uts/nodename' but not in
1235 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1237 WARNING: The domainname is now configured in 'uts/domainname' but not
1238 in 'domainname'." >&2
1242 for i in "$cfgdir"/interfaces/*/only_ip; do
1243 if test -e "$i"; then
1245 iface=${i##$cfgdir/interfaces/}
1246 iface=${iface%%/only_ip}
1248 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1253 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1255 WARNING: There is no cachedirectory configured for this vserver;
1256 please create '$cfgdir/cache' e.g. by executing
1258 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1261 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1263 vshelper.doSanityCheck
1265 $_VSERVER_INFO - VERIFYCAP ||
1266 panic $"capabilities are not enabled in kernel-setup"
1268 $_VSERVER_INFO - VERIFYPROC ||
1270 /proc/uptime can not be accessed. Usually, this is caused by
1271 procfs-security. Please read the FAQ for more details
1272 http://linux-vserver.org/Proc-Security"
1274 test -e "$cfgdir"/context || {
1275 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1276 test "$TYPE" != "static" || panic $"\
1277 The kernel does not have dynamic contexts enabled. Please configure
1278 a static one by executing
1280 echo [number between 2 and 49151] > $cfgdir/context"
1285 function _setSingleDiskLimit
1297 getFileValue ctx "$vdir/context"
1298 getFileValue directory "$dlimit/directory" || return 0
1299 getFileValue space_total "$dlimit/space_total" || return 0
1300 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1301 getFileValue reserved "$dlimit/reserved" || return 0
1303 local cachename=$ctx$directory
1304 cachename=dlimits/${cachename//\//_}
1306 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1307 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1308 $_RM -f "$vdir/cache/$cachename"
1310 if test -z "$inodes_used" -o -z "$space_used"; then
1312 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1313 inodes_used=${tmpvdu##* }
1314 space_used=${tmpvdu%% *}
1317 $_VDLIMIT --xid $ctx \
1318 --set space_used=$space_used \
1319 --set space_total=$space_total \
1320 --set inodes_used=$inodes_used \
1321 --set inodes_total=$inodes_total \
1322 --set reserved=$reserved \
1327 function setDiskLimits
1332 # Disk Limits without a static context are useless
1333 test -e "$vdir"/context || return 0
1335 for dlimit in "$vdir/dlimits/"*; do
1336 test -d "$dlimit" || continue
1337 test ! -e "$dlimit/disabled" || continue
1339 _setSingleDiskLimit "$vdir" "$dlimit"
1344 function _saveSingleDiskLimit
1351 getFileValue ctx "$vdir/context"
1352 getFileValue directory "$dlimit/directory" || return 0
1354 local cachename=$ctx$directory
1355 cachename=${cachename//\//_}
1357 # Things are getting ugly here... LFS says that /var/cache (where
1358 # cachename is usually pointing to) can vanish and applications
1359 # have to deal with it. So, we have to interprete the $vdir/cache
1360 # symlink and have to create the needed directories manually.
1361 if test -d "$vdir/cache"; then
1362 : # ok, exists already
1363 elif test -L "$vdir/cache"; then
1364 # it's a dangling symlink
1366 link=$($_READLINK "$vdir/cache")
1367 ( cd $vdir && $_MKDIR -p "$link" )
1372 test -d "$vdir/cache"
1373 $_MKDIR -p "$vdir"/cache/dlimits
1375 $_VDLIMIT --xid $ctx "$directory" | \
1376 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1378 $_VDLIMIT --xid $ctx --remove "$directory"
1382 function saveDiskLimits
1387 test -e "$vdir"/context || return 0
1389 for dlimit in "$vdir/dlimits/"*; do
1390 test -d "$dlimit" || continue
1391 test ! -e "$dlimit/disabled" || continue
1393 _saveSingleDiskLimit "$vdir" "$dlimit"
1397 function _namespaceCleanup
1400 local root=$($_VSERVER_INFO "$1" VDIR 1)
1406 getFileArray skip "$vdir"/namespace-cleanup-skip \
1407 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1409 # these are things that have to be accessible post-cleanup
1410 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1411 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1412 local real=`getPhysicalDir "$i"`
1413 test "$i" != "$real" || real=
1414 for j in "$i" "$real"; do
1415 while test -n "$j"; do
1416 list=( "${list[@]}" "$j" )
1422 # keep cgroup mount points
1423 list=( "${list[@]}" "${CGROUP_MNT}" )
1424 if test -n "$CGROUP_MNT_PER_SS"; then
1425 for ss in "${CGROUP_SUBSYS[@]}"; do
1426 list=( "${list[@]}" "${CGROUP_MNT}/${ss}" )
1430 local -a list_umount
1431 while read -r dev path opts; do
1432 test -n "$path" || continue
1434 for i in "$root" /dev /proc /sys; do
1435 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1437 for i in "${list[@]}" /; do
1438 test "$path" = "$i" && continue 2
1440 # unmount them in reverse order so mounts further down the tree get unmounted first
1441 list_umount=( "$path" "${list_umount[@]}" )
1443 # separate loop to avoid races while reading /proc/mounts
1444 for i in "${list_umount[@]}"; do
1445 $_UMOUNT -l -n -i "$i"
1449 function handleDeviceMap
1454 local flags device target
1456 test -d "$dir" || return 0
1457 test -n "$xid" || return 0
1459 for i in "$dir"/*; do
1460 test -d "$i" || continue
1462 local -a vdevmap_opts=()
1463 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1464 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1465 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1467 getFileValue flags "$i/flags" || :
1468 getFileValue device "$i/device" || :
1469 getFileValue target "$i/target" || :
1470 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1471 ${device:+--device "$device"} ${target:+--target "$target"} )
1473 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1479 $_GREP -q "cgroup" /proc/filesystems
1482 function _generateCgroupOptions
1486 hasCgroup || return 0
1488 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1489 if test -n "$file"; then
1490 _readFileToArray CGROUP_SUBSYS "$file"
1492 CGROUP_SUBSYS=( $($_AWK '/^#/ { next; } $1 == "ns" { next; } $4 != "0" { print $1; }' /proc/cgroups) )
1494 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1495 if test -n "$file"; then
1496 read CGROUP_MNT < "$file"
1497 elif test -d /sys/fs/cgroup -a -d /sys/fs/cgroup/"${CGROUP_SUBSYS[0]}"; then
1498 CGROUP_MNT=/sys/fs/cgroup
1501 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1502 if test -n "$file"; then
1503 _readFileToArray CGROUP_INHERIT "$file" ""
1505 findFile file "$__CONFDIR/.defaults/cgroup/base" ""
1506 if test -n "$file"; then
1507 read CGROUP_BASE < "$file"
1508 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
1509 CGROUP_BASE="${CGROUP_BASE}/"
1511 findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
1512 if test -n "$file"; then
1521 hasCgroup || return 1
1522 if test -n "$CGROUP_MNT_PER_SS"; then
1525 for ss in "${CGROUP_SUBSYS[@]}"; do
1526 if test -e "$CGROUP_MNT/$ss/tasks"; then
1527 let existing=${existing}+1
1530 test "$existing" -gt 0 || return 1
1532 test -e "$CGROUP_MNT/tasks" || return 1
1535 if $_VSERVER_INFO - FEATURE memcg; then
1538 test -d "$1/cgroup" -o \
1539 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
1540 ! -e "$1/nocgroup" \)
1543 function _handleCgroup
1555 useCgroup "$vdir" || return 0
1557 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1559 if test -n "$dir" -a -r "$dir"/name; then
1560 read name < "$dir"/name
1562 name="$VSERVER_NAME"
1565 if test -n "$CGROUP_MNT_PER_SS"; then
1567 for ss in "${CGROUP_SUBSYS[@]}"; do
1568 mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
1571 mnts=( "$CGROUP_MNT" )
1573 for mnt in "${mnts[@]}"; do
1574 test -d "$mnt" || continue
1575 if test "$action" = "attach"; then
1576 if test -n "$CGROUP_BASE"; then
1578 i="$mnt/$CGROUP_BASE"
1579 while test "$mnt" != "$i"; do
1580 dirs=( "$i" "${dirs[@]}" )
1583 for i in "${dirs[@]}"; do
1584 if mkdir "$i" 2>/dev/null; then
1586 for j in "${CGROUP_INHERIT[@]}"; do
1587 test -f "$parent/$j" || continue
1588 cat "$parent/$j" > "$i/$j"
1593 if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
1594 parent="$mnt/$CGROUP_BASE$name"
1595 parent="${parent%/*}"
1596 for i in "${CGROUP_INHERIT[@]}"; do
1597 test -f "$parent/$i" || continue
1598 cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i"
1601 if test -n "$dir"; then
1603 for i in "$dir"/*; do
1605 test "$f" != mnt -a "$f" != subsys -a \
1606 "$f" != inherit -a "$f" != name -a "$f" != base -a \
1609 if test -n "$CGROUP_MNT_PER_SS"; then
1611 test "$ss" = "${mnt##*/}" || continue
1613 cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
1617 echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
1618 elif test "$action" = "destroy"; then
1619 rmdir "$mnt/$name" 2>/dev/null || :
1626 function attachToCgroup
1628 _handleCgroup attach "$@"
1631 function destroyCgroup
1633 _handleCgroup destroy "$@"