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=
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 test -n "$ionice_class$ionice_priority" || return 0
167 if test -z "$ionice_class" -a -n "$ionice_priority"; then
168 IONICE_CMD=( $_IONICE -c2 -n"$ionice_priority" )
170 IONICE_CMD=( $_IONICE ${ionice_class:+-c$ionice_class} ${ionice_priority:+-n$ionice_priority} )
174 function _generatePersonalityOptions
177 local f="$vdir"/personality
180 test -s "$f" || return 0
189 (*) flags=$flags$delim$tmp
196 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
197 --personality-type "$type"
198 ${flags:+--personality-flags "$flags"} )
201 function _generateCCapabilityOptions
205 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
208 function _generateBCapabilityOptions
212 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
215 function _generateUMaskOptions
219 _readFileToArray "$vdir"/umask OPTS_VATTRIBUTE --umask
222 function _generateCapabilityOptions
227 _generateBCapabilityOptions "$vdir"
228 _generateCCapabilityOptions "$vdir"
230 test -e "$vdir"/capabilities || return 0
239 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
240 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
243 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
246 done <"$vdir"/capabilities
249 function getEnterShell
256 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
258 test -n "$ENTER_SHELL" || {
260 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
262 test -x "$vdir/vdir/$1" || continue
269 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
270 function sendKillSequence
276 while isCtxRunning "$ctx"; do
277 test -z "$wait" || sleep "$wait"
279 killContext "$ctx" "$1"
280 test -n "$2" || break
286 function _generateInitOptions
289 local cfgdir=$vdir/apps/init
294 INITCMD_START_SYNC=()
299 INITKILL_SEQ=( 15 5 9 )
300 CHCONTEXT_INIT_OPTS=()
303 test x"$INITSTYLE" = xrescue || \
304 getFileValue INITSTYLE "$cfgdir"/style
305 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
306 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
307 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
308 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
310 findFile _gio_env "$cfgdir"/environment \
311 "$__CONFDIR"/.defaults/apps/init/environment \
312 "$__PKGLIBDEFAULTDIR"/environment
313 getFileArray OPTS_ENV "$_gio_env" || :
315 case x"$INITSTYLE" in
317 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
318 INITCMD_STOP=( /sbin/killall5 )
322 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
323 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
325 for i in /etc/init.d/rc /etc/rc.d/rc; do
326 test -x "$vdir/vdir/$i" || continue
327 INITCMD_START=( "$i" "$RUNLEVEL_START" )
328 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
330 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
331 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
332 if test -n "$OPTION_DEBUG_SYSV"; then
333 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
334 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
339 INITCMD_START=( /sbin/init )
340 INITCMD_STOP=( /sbin/init )
342 _NEED_VSHELPER_SYNC=1
343 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
344 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
348 INITCMD_START=( /sbin/minit-start )
349 INITCMD_STOP=( /sbin/minit-stop )
351 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
352 _NEED_VSHELPER_SYNC=1
353 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
354 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
355 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
359 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
360 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
362 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
363 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
364 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
365 RC_WRAP=/lib/rc/sh/init-vserver.sh
367 panic "init-vserver.sh not found; aborting"
370 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
371 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
372 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
373 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
377 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
378 INITCMD_START=( /etc/rc.multi )
379 INITCMD_STOP=( /etc/rc.shutdown )
380 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
384 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
387 if test x"$INITSTYLE" != xrescue; then
388 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
389 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
390 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
391 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
392 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
395 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
396 INITCMD_START_SYNC=()
401 if vshelper.isEnabled; then
402 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
408 function _generateFlagOptions
413 CHCONTEXT_FLAG_OPTS=()
415 findFile file "$vdir"/cflags "$vdir"/flags ""
425 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
426 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
432 isAvoidNamespace "$vdir" || {
434 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
435 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
436 OPT_VCONTEXT_CHROOT=--pivot-root
440 function _generateChcontextOptions
443 local ctx hostname domainname
448 read ctx <"$vdir"/context || :
450 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
451 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
454 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
456 _generateCapabilityOptions "$vdir"
457 _generateFlagOptions "$vdir"
458 _generateUMaskOptions "$vdir"
460 CHCONTEXT_OPTS=( $SILENT_OPT \
461 "${CHCONTEXT_FLAG_OPTS[@]}" \
464 ${ctx:+--ctx "$ctx"} \
465 ${hostname:+--hostname "$hostname"} \
466 ${domainname:+--domainname "$domainname"} )
468 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
469 ${ctx:+--xid "$ctx"} )
470 ## put '--secure' at front so that it can be overridden
471 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
474 function _generateScheduleOptions
477 if test -d "$vdir"/sched; then
478 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
482 local f="$vdir"/schedule
483 test -e "$f" || return 0
485 local fill_rate interval tokens tokens_min tokens_max prio_bias
493 read prio_bias || prio_bias=
497 test -n "$prio_bias" || {
498 echo $"Bad content in '$f'; aborting..." >&2
502 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
503 --tokens "$tokens" --tokens_min "$tokens_min" \
504 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
507 function _getInterfaceValue
517 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
520 : ${_giv_tmp:=$_giv_dflt}
521 eval $_giv_val=\$_giv_tmp
524 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
525 function _transformMask2Prefix
529 test -n "$_tm2p_tmp" || {
530 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
537 function _addInterfaceCmd
539 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
540 let ++INTERFACE_CMDS_IDX
543 ## Usage: _generateMac <var> <iface> <ctx>
544 function _generateMac
547 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
551 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
554 function _getVLANInfo
559 creation of VLAN_PLUS_VID devices is not supported; please create them
560 before starting the vserver and use the 'nodev' flag then"
561 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
565 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
566 create them before starting the vserver and use the 'nodev' flag then"
567 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
569 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
570 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
581 test -e "$iface/tun" -o -e "$iface/tap" || return 1
582 test ! -e "$iface/tun" || echo --tun
583 test ! -e "$iface/tap" || echo --tap
584 test ! -e "$iface/nocsum" || echo --~checksum
585 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
586 if test -e "$iface/uid"; then
588 getFileValue uid "$iface/uid"
591 if test -e "$iface/gid"; then
593 getFileValue gid "$iface/gid"
596 if test -e "$iface/linktype"; then
598 getFileValue linktype "$iface/linktype"
599 echo --linktype "$linktype"
604 ## Usage: _processSingleInterface <interface-directory>
605 function _processSingleInterface
621 _getInterfaceValue ip '' "$iface"
622 _getInterfaceValue extip '' "$iface" "$iface/.."
623 _getInterfaceValue dev '' "$iface" "$iface/.."
624 _getInterfaceValue prefix '' "$iface" "$iface/.."
625 _getInterfaceValue mask '' "$iface" "$iface/.."
626 _getInterfaceValue bcast '' "$iface" "$iface/.."
627 _getInterfaceValue name '' "$iface"
628 _getInterfaceValue scope '' "$iface" "$iface/.."
629 _getInterfaceValue mac '' "$iface"
630 _getInterfaceValue peer '' "$iface"
632 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
633 test -n "$dev" -o -e "$iface"/nodev || {
634 echo $"No device specified for '$iface'" >&2
638 test ! -e "$iface"/down || up=
641 _transformMask2Prefix prefix "$prefix" "$mask"
642 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
644 test ! -e "$iface"/nodev || break
646 test ! -e "$iface"/only_ip || break
648 test -e "$iface/vlandev" \
649 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
650 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
651 -a ! -e "$iface/novlandev" \
652 -a ! -e "$iface/../novlandev" \) && {
654 if vlan_info=$(_getVLANInfo "$dev"); then
655 test -d /proc/net/vlan || {
656 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
659 _addInterfaceCmd VCONFIG $vlan_info
663 if ! test -e "$iface"/indirect; then
665 local use_bcast="broadcast ${bcast:-+}"
666 echo "$ip" | $_GREP -q : && use_bcast=
669 if tun_info=$(_getTunInfo "$iface"); then
670 _addInterfaceCmd TUNCTL "$dev" $tun_info
673 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
674 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
675 _addInterfaceCmd IP_LINK "$dev" $up
676 elif ! test -n "$N_CONTEXT"; then
677 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
680 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
681 _addInterfaceCmd MODPROBE dummy "$dev"
682 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
683 _addInterfaceCmd NAMEIF "$dev" "$mac"
684 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
685 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
692 ## Usage: _generateInterfaceOptions <vserver-directory>
693 function _generateInterfaceOptions
697 # XXX: This is here instead of in _generateChbindOptions
698 # to avoid a circular dependency
699 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
700 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
702 for iface in "$1/interfaces/"*; do
703 test -d "$iface" || continue
704 test ! -e "$iface"/disabled || continue
706 _processSingleInterface "$iface"
708 _HAVE_INTERFACE_OPTIONS=1
711 function enableInterfaces
716 lock "$__LOCKDIR"/vserver.interfaces
718 while test $i -lt $INTERFACE_CMDS_IDX; do
719 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
730 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
732 NAMEIF) $_NAMEIF "$@";;
733 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
734 $_VCONFIG add "$2" "$3" >/dev/null;;
735 IP_ADDR) $_IP addr add "$@";;
736 IP_ADDR_FLUSH) $_IP addr flush "$@";;
737 IP_LINK) $_IP link set "$@";;
738 IP_ROUTE) $_IP route add "$@";;
742 $_TUNCTL --persist "$@" "$dev"
744 *) echo "Unknown interface-command type '$type'" >&2; false;;
753 function disableInterfaces
755 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
757 local i=$INTERFACE_CMDS_IDX
760 lock "$__LOCKDIR"/vserver.interfaces
762 while test $i -gt 0; do
765 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
772 MODPROBE) $_RMMOD "${2:-$1}";;
774 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
775 IP_ADDR) $_IP addr del "$@";;
777 IP_LINK) ;; ## Ignore the link-down command for now
778 IP_ROUTE) $_IP route del "$@";;
782 $_TUNCTL --~persist "$@" "$dev"
784 *) echo "Unknown interface-command type '$type'" >&2; false;;
791 function _generateTagOptions
796 getFileValue tag "$vdir/tag" "$vdir/context"
797 test -n "$tag" || return 0
799 OPTS_VTAG_CREATE=( --tag "$tag" )
800 OPTS_VTAG_ENTER=( --tag "$tag" )
803 function _generateMemctrlOptions
808 getFileValue badness "$vdir/badness"
809 test -n "$badness" || return 0
811 OPTS_VMEMCTRL=( --badness "$badness" )
814 function _generateSpaceOptions
817 local d="$vdir"/spaces
821 for space in pid net; do
822 if test -e "$d"/$space; then
823 getFileValue shared "$d"/$space || shared=""
824 if test -z "$shared"; then
825 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
826 elif test "$shared" = "0"; then
829 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
830 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
836 getFileValue mask "$d"/mask || \
837 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
840 ## Usage: prepareInit <vserver-directory>
843 pushd "$1/vdir" >/dev/null
846 local -a dirs=( $($_CHROOT_SH realpath /var/run /var/lock | $_SED 's!^/*!!' || :) )
848 for dir in "${dirs[@]}"; do
849 $_FIND $dir ! -type d -print0 | xargs -0r $_CHROOT_SH rm
853 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
854 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
859 "${INITCMD_PREPARE[@]}"
863 ## Usage: prepareInit <vserver-directory>
866 pushd "$1/vdir" >/dev/null
869 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
872 "${STOPCMD_PREPARE[@]}"
877 function generateOptions
879 _generateInterfaceOptions "$1"
880 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
881 _generateNiceCommand "$1"
882 _generateIONiceCommand "$1"
883 _generateInitOptions "$1"
884 _generateChcontextOptions "$1"
885 _generateScheduleOptions "$1"
886 _generatePersonalityOptions "$1"
887 _generateTagOptions "$1"
888 _generateMemctrlOptions "$1"
889 _generateSpaceOptions "$1"
890 _generateCgroupOptions
892 if test -n "$_IS_FAKEINIT"; then
893 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
894 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
902 local f="$vdir"/cpuset
906 test -d "$f" || return 0
907 test -e "$f"/name || return 0
909 read cpuset < "$f"/name
910 test -e "$f"/nocreate || {
911 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
912 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
913 if test -e "$f"/"$i"; then
914 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
922 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
923 if [ "$configured" -ne 0 ]; then
925 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
926 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
931 function removeCPUSET
935 local f="$vdir"/cpuset
937 test -d "$f" || return 0
938 test -e "$f"/name || return 0
940 read cpuset < "$f"/name
941 test -e "$f"/nocreate || {
942 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
946 function _mountVserverInternal
951 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 if test -h etc/mtab; then
960 local l=$($_READLINK etc/mtab)
961 test "${l##/proc/}" = "$l" || xflag=-n
963 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
971 local fstab="$cfgdir"/fstab
974 test -e "$fstab" || return 0
975 pushd "$vdir" >/dev/null
976 # check whether / is mounted readonly or whether there is special
977 # magic regarding the mtab file; when etc/mtab can not be touched,
978 # add the '-n' flag to mount
979 test -w etc -o -w etc/mtab || xflag=-n
980 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
984 function mountVserver
993 test -e "$cfgdir"/fstab -o \
994 -e "$cfgdir"/fstab.local -o \
995 -e "$cfgdir"/fstab.remote || return 0
997 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
999 pushd "$vdir" >/dev/null
1000 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
1003 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1005 _mountVserverInternal "$cfgdir"/fstab
1006 _mountVserverInternal "$cfgdir"/fstab.local
1007 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
1009 isNamespaceCleanup "$cfgdir" && \
1010 _namespaceCleanup "$cfgdir"
1012 real_vdir=$(getPhysicalDir "$vdir")
1013 isAvoidNamespace "$cfgdir" || \
1014 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
1015 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
1016 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
1019 function _umountVserverInternal
1022 test -e "$fstab" || return 0
1027 while read src dst tmp; do
1028 test -n "$tmp" || continue
1034 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1040 function umountVserver
1046 isAvoidNamespace "$cfgdir" || return 0
1047 test -e "$cfgdir"/fstab -o \
1048 -e "$cfgdir"/fstab.local -o \
1049 -e "$cfgdir"/fstab.remote || return 0
1050 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1052 pushd "$vdir/" >/dev/null || return 1
1053 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1054 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1055 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1056 popd >/dev/null || return 1
1064 local fstab="$cfgdir"/fstab
1068 test -e "$fstab" || return 0
1070 export FSTAB_FILE="$fstab"
1073 test "$fsck_exitcode" -eq 0 -o \
1074 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1077 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1081 test -n "$_NEED_VSHELPER_SYNC" && \
1082 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1084 vshelper.initSync "$1" "$3" "$_is_meth"
1087 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1090 if $_VSERVER_INFO - FEATURE vwait; then
1092 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1095 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1096 --status-fd 3 "$2" \
1097 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1100 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1101 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1102 killContext "$S_CONTEXT" 9
1106 ) 4>$_is_tmpdir/procs &
1108 echo "$!" >$_is_tmpdir/pid
1109 eval "$3"=$_is_tmpdir
1114 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1115 function _waitForVWait
1120 declare -r procs=$(cat $4)
1122 getFileArray status "$2"
1127 'vwait' exited with error '$2' which indicates that vserver could not
1128 be stopped properly"
1131 (KILLED) warning $"\
1132 A timeout occured while waiting for the vserver to finish and it was
1133 killed by sending a SIGKILL signal. Please investigate the reasons
1134 and/or increase the timeout in apps/vshelper/sync-timeout."
1137 (TIMEOUT) warning $"\
1138 A timeout occured while waiting for the vserver to finish and it will
1139 be killed by sending a SIGKILL signal. The following process list
1140 might be useful for finding out the reason of this behavior:
1142 ----------------------------------------------------------------------
1144 }----------------------------------------------------------------------"
1147 (\?\?\?|*) warning $"\
1148 internal error: 'vwait' exited with an unexpected status '$1'; I will
1149 try to continue but be prepared for unexpected events."
1156 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1157 function waitForSync
1161 local vwait_statdir=$3
1164 if test -d "$vwait_statdir"; then
1165 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1166 elif test -n "$_NEED_VSHELPER_SYNC"; then
1167 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1169 A timeout or other error occured while waiting for the synchronization
1170 signal from vserver '$VSERVER_NAME'.
1171 The vserver will be killed nevertheless..."
1172 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1173 "${INITCMD_STOP_SYNC[@]}" || \
1175 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1176 will be killed nevertheless..."
1179 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1183 function _sourceWrap
1185 local vdir name flavor start i already_handled base
1189 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1190 function execScriptlets
1194 declare -r flavor=$3
1197 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1198 local DONT_SKIP_DEFAULTS=
1199 local already_handled=
1201 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1202 isRegularFile "$i" || continue
1203 test -r "$i" || continue
1207 test -x "$i" || start=_sourceWrap
1208 $start "$i" "$flavor" "$name"
1211 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1216 function sanityCheck
1218 declare -r cfgdir=$1
1220 ! test -e "$cfgdir"/fstab.local ||
1222 WARNING: 'fstab' will *not* be executed in the network context of the
1223 vserver anymore. Therefore, 'fstab.local' has the same functionality
1224 and is obsoleted. When you need the old behaviour, put the mounts
1225 into 'fstab.remote'"
1227 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1229 WARNING: The hostname is now configured in 'uts/nodename' but not in
1232 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1234 WARNING: The domainname is now configured in 'uts/domainname' but not
1235 in 'domainname'." >&2
1239 for i in "$cfgdir"/interfaces/*/only_ip; do
1240 if test -e "$i"; then
1242 iface=${i##$cfgdir/interfaces/}
1243 iface=${iface%%/only_ip}
1245 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1250 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1252 WARNING: There is no cachedirectory configured for this vserver;
1253 please create '$cfgdir/cache' e.g. by executing
1255 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1258 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1260 vshelper.doSanityCheck
1262 $_VSERVER_INFO - VERIFYCAP ||
1263 panic $"capabilities are not enabled in kernel-setup"
1265 $_VSERVER_INFO - VERIFYPROC ||
1267 /proc/uptime can not be accessed. Usually, this is caused by
1268 procfs-security. Please read the FAQ for more details
1269 http://linux-vserver.org/Proc-Security"
1271 test -e "$cfgdir"/context || {
1272 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1273 test "$TYPE" != "static" || panic $"\
1274 The kernel does not have dynamic contexts enabled. Please configure
1275 a static one by executing
1277 echo [number between 2 and 49151] > $cfgdir/context"
1282 function _setSingleDiskLimit
1294 getFileValue ctx "$vdir/context"
1295 getFileValue directory "$dlimit/directory" || return 0
1296 getFileValue space_total "$dlimit/space_total" || return 0
1297 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1298 getFileValue reserved "$dlimit/reserved" || return 0
1300 local cachename=$ctx$directory
1301 cachename=dlimits/${cachename//\//_}
1303 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1304 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1305 $_RM -f "$vdir/cache/$cachename"
1307 if test -z "$inodes_used" -o -z "$space_used"; then
1309 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1310 inodes_used=${tmpvdu##* }
1311 space_used=${tmpvdu%% *}
1314 $_VDLIMIT --xid $ctx \
1315 --set space_used=$space_used \
1316 --set space_total=$space_total \
1317 --set inodes_used=$inodes_used \
1318 --set inodes_total=$inodes_total \
1319 --set reserved=$reserved \
1324 function setDiskLimits
1329 # Disk Limits without a static context are useless
1330 test -e "$vdir"/context || return 0
1332 for dlimit in "$vdir/dlimits/"*; do
1333 test -d "$dlimit" || continue
1334 test ! -e "$dlimit/disabled" || continue
1336 _setSingleDiskLimit "$vdir" "$dlimit"
1341 function _saveSingleDiskLimit
1348 getFileValue ctx "$vdir/context"
1349 getFileValue directory "$dlimit/directory" || return 0
1351 local cachename=$ctx$directory
1352 cachename=${cachename//\//_}
1354 # Things are getting ugly here... LFS says that /var/cache (where
1355 # cachename is usually pointing to) can vanish and applications
1356 # have to deal with it. So, we have to interprete the $vdir/cache
1357 # symlink and have to create the needed directories manually.
1358 if test -d "$vdir/cache"; then
1359 : # ok, exists already
1360 elif test -L "$vdir/cache"; then
1361 # it's a dangling symlink
1363 link=$($_READLINK "$vdir/cache")
1364 ( cd $vdir && $_MKDIR -p "$link" )
1369 test -d "$vdir/cache"
1370 $_MKDIR -p "$vdir"/cache/dlimits
1372 $_VDLIMIT --xid $ctx "$directory" | \
1373 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1375 $_VDLIMIT --xid $ctx --remove "$directory"
1379 function saveDiskLimits
1384 test -e "$vdir"/context || return 0
1386 for dlimit in "$vdir/dlimits/"*; do
1387 test -d "$dlimit" || continue
1388 test ! -e "$dlimit/disabled" || continue
1390 _saveSingleDiskLimit "$vdir" "$dlimit"
1394 function _namespaceCleanup
1397 local root=$($_VSERVER_INFO "$1" VDIR 1)
1403 getFileArray skip "$vdir"/namespace-cleanup-skip \
1404 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1406 # these are things that have to be accessible post-cleanup
1407 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1408 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1409 local real=`getPhysicalDir "$i"`
1410 test "$i" != "$real" || real=
1411 for j in "$i" "$real"; do
1412 while test -n "$j"; do
1413 list=( "${list[@]}" "$j" )
1419 local -a list_umount
1420 while read -r dev path opts; do
1421 test -n "$path" || continue
1422 for i in "$root" /dev /proc; do
1424 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1426 for i in "${list[@]}" /; do
1427 test "$path" = "$i" && continue 2
1429 # unmount them in reverse order so mounts further down the tree get unmounted first
1430 list_umount=( "$path" "${list_umount[@]}" )
1432 # separate loop to avoid races while reading /proc/mounts
1433 for i in "${list_umount[@]}"; do
1434 $_UMOUNT -l -n -i "$i"
1438 function handleDeviceMap
1443 local flags device target
1445 test -d "$dir" || return 0
1446 test -n "$xid" || return 0
1448 for i in "$dir"/*; do
1449 test -d "$i" || continue
1451 local -a vdevmap_opts=()
1452 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1453 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1454 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1456 getFileValue flags "$i/flags" || :
1457 getFileValue device "$i/device" || :
1458 getFileValue target "$i/target" || :
1459 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1460 ${device:+--device "$device"} ${target:+--target "$target"} )
1462 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1468 $_GREP -q "cgroup" /proc/filesystems
1471 function _generateCgroupOptions
1475 hasCgroup || return 0
1477 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1478 if test -n "$file"; then
1479 _readFileToArray CGROUP_SUBSYS "$file"
1481 CGROUP_SUBSYS=( $($_AWK '/^#/ { next; } $1 == "ns" { next; } $4 != "0" { printf "%s%s", s, $1; s=","; }' /proc/cgroups) )
1483 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1484 if test -n "$file"; then
1485 read CGROUP_MNT < "$file"
1486 elif test -d /sys/fs/cgroup -a -d /sys/fs/cgroup/"${CGROUP_SUBSYS[0]}"; then
1487 CGROUP_MNT=/sys/fs/cgroup
1490 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1491 if test -n "$file"; then
1492 _readFileToArray CGROUP_INHERIT "$file" ""
1494 findFile file "$__CONFDIR/.defaults/cgroup/base" ""
1495 if test -n "$file"; then
1496 read CGROUP_BASE < "$file"
1497 test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
1498 CGROUP_BASE="${CGROUP_BASE}/"
1500 findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
1501 if test -n "$file"; then
1510 hasCgroup || return 1
1511 if test -n "$CGROUP_MNT_PER_SS"; then
1514 for ss in "${CGROUP_SUBSYS[@]}"; do
1515 if test -e "$CGROUP_MNT/$ss/tasks"; then
1516 let existing=${existing}+1
1519 test "$existing" -gt 0 || return 1
1521 test -e "$CGROUP_MNT/tasks" || return 1
1524 if $_VSERVER_INFO - FEATURE memcg; then
1527 test -d "$1/cgroup" -o \
1528 \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
1529 ! -e "$1/nocgroup" \)
1532 function _handleCgroup
1544 useCgroup "$vdir" || return 0
1546 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1548 if test -n "$dir" -a -r "$dir"/name; then
1549 read name < "$dir"/name
1551 name="$VSERVER_NAME"
1554 if test -n "$CGROUP_MNT_PER_SS"; then
1556 for ss in "${CGROUP_SUBSYS[@]}"; do
1557 mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
1560 mnts=( "$CGROUP_MNT" )
1562 for mnt in "${mnts[@]}"; do
1563 test -d "$mnt" || continue
1564 if test "$action" = "attach"; then
1565 if test -n "$CGROUP_BASE"; then
1567 i="$mnt/$CGROUP_BASE"
1568 while test "$mnt" != "$i"; do
1569 dirs=( "$i" "${dirs[@]}" )
1572 for i in "${dirs[@]}"; do
1573 if mkdir "$i" 2>/dev/null; then
1575 for j in "${CGROUP_INHERIT[@]}"; do
1576 test -f "$parent/$j" || continue
1577 cat "$parent/$j" > "$i/$j"
1582 if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
1583 parent="$mnt/$CGROUP_BASE$name"
1584 parent="${parent%/*}"
1585 for i in "${CGROUP_INHERIT[@]}"; do
1586 test -f "$parent/$i" || continue
1587 cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i"
1590 if test -n "$dir"; then
1592 for i in "$dir"/*; do
1594 test "$f" != mnt -a "$f" != subsys -a \
1595 "$f" != inherit -a "$f" != name -a "$f" != base -a \
1598 if test -n "$CGROUP_MNT_PER_SS"; then
1600 test "$ss" = "${mnt##*/}" || continue
1602 cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
1606 echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
1607 elif test "$action" = "destroy"; then
1608 rmdir "$mnt/$name" 2>/dev/null || :
1615 function attachToCgroup
1617 _handleCgroup attach "$@"
1620 function destroyCgroup
1622 _handleCgroup destroy "$@"