3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # $VSERVER_DIR ... path to vserver-cfg dir
20 # $VSERVER_NAME ... name of vserver
22 declare -a NICE_CMD=()
23 declare -a IONICE_CMD=()
24 declare -a CHBIND_CMD=()
25 declare -a CAP_OPTS=()
26 declare -a CHCONTEXT_INIT_OPTS=()
27 declare -a CHCONTEXT_FLAG_OPTS=()
28 declare -a CHCONTEXT_OPTS=()
29 declare -a CAPCHROOT_OPTS=()
30 declare -a INTERFACES=()
32 declare -a INITCMD_RESCUE=( /bin/sleep 900 )
33 declare -a INITCMD_START=()
34 declare -a INITCMD_START_SYNC=()
35 declare -a INITCMD_STOP=()
36 declare -a INITCMD_STOP_SYNC=()
37 declare -a INITCMD_PREPARE=()
38 declare -a INITKILL_SEQ=()
39 declare -a ENTER_SHELL=()
41 declare -a OPTS_VCONTEXT_CREATE=()
42 declare -a OPTS_VCONTEXT_MIGRATE=()
43 declare -a OPTS_VCONTEXT_ENTER=()
44 OPT_VCONTEXT_CHROOT=--chroot
45 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
46 declare -a OPTS_VSCHED=()
47 declare -a OPTS_ENV=()
48 declare -a OPTS_VTAG_CREATE=()
49 declare -a OPTS_VTAG_ENTER=()
50 declare -a OPTS_VMEMCTRL=()
51 declare -a OPTS_VSPACE=( --default )
52 declare -a OPTS_VSPACE_SHARED=()
53 declare -a VSPACE_SHARED_CMD=()
55 declare -a STOPCMD_PREPARE=()
57 declare -a VSERVER_EXTRA_CMDS=()
60 VSHELPER_SYNC_TIMEOUT=30
65 _HAVE_INTERFACE_OPTIONS=
77 CGROUP_MNT=/dev/cgroup
79 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
81 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
83 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
89 function _readFileToArray
96 test -e "$_rfta_f" || return 0
97 while read _rfta_v; do
100 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
105 function _generateChbindOptions
113 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
115 local f="$vdir"/interfaces/bcast
116 getFileValue bcast "$f"
117 f="$vdir"/interfaces/lback
118 getFileValue lback "$f"
120 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
121 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
124 for i in "${INTERFACES[@]}"; do
125 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
128 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
129 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
131 _HAVE_CHBIND_OPTIONS=1
134 function _generateNiceCommand
138 local current_nice=`$_NICE`
140 test -r "$vdir/nice" && read nice <"$vdir"/nice
142 let nice=$nice-$current_nice || :
143 NICE_CMD=( $_NICE -n $nice )
146 function _generateIONiceCommand
150 local ionice_priority=0
152 test -n "$_IONICE" || return 0
154 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
155 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
157 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
160 function _generatePersonalityOptions
163 local f="$vdir"/personality
166 test -s "$f" || return 0
175 (*) flags=$flags$delim$tmp
182 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
183 --personality-type "$type"
184 ${flags:+--personality-flags "$flags"} )
187 function _generateCCapabilityOptions
191 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
194 function _generateBCapabilityOptions
198 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
201 function _generateCapabilityOptions
206 _generateBCapabilityOptions "$vdir"
207 _generateCCapabilityOptions "$vdir"
209 test -e "$vdir"/capabilities || return 0
218 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
219 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
222 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
225 done <"$vdir"/capabilities
228 function getEnterShell
235 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
237 test -n "$ENTER_SHELL" || {
239 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
241 test -x "$vdir/vdir/$1" || continue
248 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
249 function sendKillSequence
255 while isCtxRunning "$ctx"; do
256 test -z "$wait" || sleep "$wait"
258 killContext "$ctx" "$1"
259 test -n "$2" || break
265 function _generateInitOptions
268 local cfgdir=$vdir/apps/init
273 INITCMD_START_SYNC=()
278 INITKILL_SEQ=( 15 5 9 )
279 CHCONTEXT_INIT_OPTS=()
282 test x"$INITSTYLE" = xrescue || \
283 getFileValue INITSTYLE "$cfgdir"/style
284 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
285 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
286 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
287 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
289 findFile _gio_env "$cfgdir"/environment \
290 "$__CONFDIR"/.defaults/apps/init/environment \
291 "$__PKGLIBDEFAULTDIR"/environment
292 getFileArray OPTS_ENV "$_gio_env" || :
294 case x"$INITSTYLE" in
296 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
297 INITCMD_STOP=( /sbin/killall5 )
301 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
302 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
304 for i in /etc/init.d/rc /etc/rc.d/rc; do
305 test -x "$vdir/vdir/$i" || continue
306 INITCMD_START=( "$i" "$RUNLEVEL_START" )
307 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
309 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
310 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
311 if test -n "$OPTION_DEBUG_SYSV"; then
312 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
313 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
318 INITCMD_START=( /sbin/init )
319 INITCMD_STOP=( /sbin/init )
321 _NEED_VSHELPER_SYNC=1
322 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
323 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
327 INITCMD_START=( /sbin/minit-start )
328 INITCMD_STOP=( /sbin/minit-stop )
330 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
331 _NEED_VSHELPER_SYNC=1
332 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
333 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
334 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
338 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
339 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
341 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
342 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
343 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
344 RC_WRAP=/lib/rc/sh/init-vserver.sh
346 panic "init-vserver.sh not found; aborting"
349 OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
350 INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
351 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
352 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
356 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
357 INITCMD_START=( /etc/rc.multi )
358 INITCMD_STOP=( /etc/rc.shutdown )
359 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
363 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
366 if test x"$INITSTYLE" != xrescue; then
367 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
368 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
369 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
370 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
371 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
374 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
375 INITCMD_START_SYNC=()
380 if vshelper.isEnabled; then
381 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
387 function _generateFlagOptions
392 CHCONTEXT_FLAG_OPTS=()
394 findFile file "$vdir"/cflags "$vdir"/flags ""
404 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
405 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
411 isAvoidNamespace "$vdir" || {
413 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
414 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
415 OPT_VCONTEXT_CHROOT=--pivot-root
419 function _generateChcontextOptions
422 local ctx hostname domainname
427 read ctx <"$vdir"/context || :
429 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
430 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
433 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
435 _generateCapabilityOptions "$vdir"
436 _generateFlagOptions "$vdir"
438 CHCONTEXT_OPTS=( $SILENT_OPT \
439 "${CHCONTEXT_FLAG_OPTS[@]}" \
442 ${ctx:+--ctx "$ctx"} \
443 ${hostname:+--hostname "$hostname"} \
444 ${domainname:+--domainname "$domainname"} )
446 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
447 ${ctx:+--xid "$ctx"} )
448 ## put '--secure' at front so that it can be overridden
449 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
452 function _generateScheduleOptions
455 if test -d "$vdir"/sched; then
456 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
460 local f="$vdir"/schedule
461 test -e "$f" || return 0
463 local fill_rate interval tokens tokens_min tokens_max prio_bias
471 read prio_bias || prio_bias=
475 test -n "$prio_bias" || {
476 echo $"Bad content in '$f'; aborting..." >&2
480 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
481 --tokens "$tokens" --tokens_min "$tokens_min" \
482 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
485 function _getInterfaceValue
495 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
498 : ${_giv_tmp:=$_giv_dflt}
499 eval $_giv_val=\$_giv_tmp
502 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
503 function _transformMask2Prefix
507 test -n "$_tm2p_tmp" || {
508 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
515 function _addInterfaceCmd
517 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
518 let ++INTERFACE_CMDS_IDX
521 ## Usage: _generateMac <var> <iface> <ctx>
522 function _generateMac
525 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
529 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
532 function _getVLANInfo
537 creation of VLAN_PLUS_VID devices is not supported; please create them
538 before starting the vserver and use the 'nodev' flag then"
539 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
543 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
544 create them before starting the vserver and use the 'nodev' flag then"
545 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
547 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
548 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
559 test -e "$iface/tun" -o -e "$iface/tap" || return 1
560 test ! -e "$iface/tun" || echo --tun
561 test ! -e "$iface/tap" || echo --tap
562 test ! -e "$iface/nocsum" || echo --~checksum
563 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
564 if test -e "$iface/uid"; then
566 getFileValue uid "$iface/uid"
569 if test -e "$iface/gid"; then
571 getFileValue gid "$iface/gid"
574 if test -e "$iface/linktype"; then
576 getFileValue linktype "$iface/linktype"
577 echo --linktype "$linktype"
582 ## Usage: _processSingleInterface <interface-directory>
583 function _processSingleInterface
599 _getInterfaceValue ip '' "$iface"
600 _getInterfaceValue extip '' "$iface" "$iface/.."
601 _getInterfaceValue dev '' "$iface" "$iface/.."
602 _getInterfaceValue prefix '' "$iface" "$iface/.."
603 _getInterfaceValue mask '' "$iface" "$iface/.."
604 _getInterfaceValue bcast '' "$iface" "$iface/.."
605 _getInterfaceValue name '' "$iface"
606 _getInterfaceValue scope '' "$iface" "$iface/.."
607 _getInterfaceValue mac '' "$iface"
608 _getInterfaceValue peer '' "$iface"
610 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
611 test -n "$dev" -o -e "$iface"/nodev || {
612 echo $"No device specified for '$iface'" >&2
616 test ! -e "$iface"/down || up=
619 _transformMask2Prefix prefix "$prefix" "$mask"
620 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
622 test ! -e "$iface"/nodev || break
624 test ! -e "$iface"/only_ip || break
626 test -e "$iface/vlandev" \
627 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
628 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
629 -a ! -e "$iface/novlandev" \
630 -a ! -e "$iface/../novlandev" \) && {
632 if vlan_info=$(_getVLANInfo "$dev"); then
633 test -d /proc/net/vlan || {
634 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
637 _addInterfaceCmd VCONFIG $vlan_info
641 if ! test -e "$iface"/indirect; then
643 local use_bcast="broadcast ${bcast:-+}"
644 echo "$ip" | $_GREP -q : && use_bcast=
647 if tun_info=$(_getTunInfo "$iface"); then
648 _addInterfaceCmd TUNCTL "$dev" $tun_info
651 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
652 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
653 _addInterfaceCmd IP_LINK "$dev" $up
654 elif ! test -n "$N_CONTEXT"; then
655 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
658 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
659 _addInterfaceCmd MODPROBE dummy "$dev"
660 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
661 _addInterfaceCmd NAMEIF "$dev" "$mac"
662 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
663 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
670 ## Usage: _generateInterfaceOptions <vserver-directory>
671 function _generateInterfaceOptions
675 # XXX: This is here instead of in _generateChbindOptions
676 # to avoid a circular dependency
677 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
678 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
680 for iface in "$1/interfaces/"*; do
681 test -d "$iface" || continue
682 test ! -e "$iface"/disabled || continue
684 _processSingleInterface "$iface"
686 _HAVE_INTERFACE_OPTIONS=1
689 function enableInterfaces
694 lock "$__LOCKDIR"/vserver.interfaces
696 while test $i -lt $INTERFACE_CMDS_IDX; do
697 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
708 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
710 NAMEIF) $_NAMEIF "$@";;
711 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
712 $_VCONFIG add "$2" "$3" >/dev/null;;
713 IP_ADDR) $_IP addr add "$@";;
714 IP_ADDR_FLUSH) $_IP addr flush "$@";;
715 IP_LINK) $_IP link set "$@";;
716 IP_ROUTE) $_IP route add "$@";;
720 $_TUNCTL --persist "$@" "$dev"
722 *) echo "Unknown interface-command type '$type'" >&2; false;;
731 function disableInterfaces
733 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
735 local i=$INTERFACE_CMDS_IDX
738 lock "$__LOCKDIR"/vserver.interfaces
740 while test $i -gt 0; do
743 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
750 MODPROBE) $_RMMOD "${2:-$1}";;
752 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
753 IP_ADDR) $_IP addr del "$@";;
755 IP_LINK) ;; ## Ignore the link-down command for now
756 IP_ROUTE) $_IP route del "$@";;
757 TUNCTL) $_TUNCTL --~persist "$1";;
758 *) echo "Unknown interface-command type '$type'" >&2; false;;
765 function _generateTagOptions
770 getFileValue tag "$vdir/tag" "$vdir/context"
771 test -n "$tag" || return 0
773 OPTS_VTAG_CREATE=( --tag "$tag" )
774 OPTS_VTAG_ENTER=( --tag "$tag" )
777 function _generateMemctrlOptions
782 getFileValue badness "$vdir/badness"
783 test -n "$badness" || return 0
785 OPTS_VMEMCTRL=( --badness "$badness" )
788 function _generateSpaceOptions
791 local d="$vdir"/spaces
794 if test -e "$d"/pid; then
795 getFileValue shared "$d"/pid
796 if test -z "$shared"; then
797 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
799 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --pid )
800 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter --xid "$shared" --pid -- )
804 if test -e "$d"/net; then
805 getFileValue shared "$d"/net
806 # network context and namespace don't make much sense
807 _HAVE_CHBIND_OPTIONS=1
809 if test -z "$shared"; then
810 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
812 OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --net )
813 VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter --xid "$shared" --net -- )
818 getFileValue mask "$d"/mask || \
819 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
822 ## Usage: prepareInit <vserver-directory>
825 pushd "$1/vdir" >/dev/null
828 { $_FIND var/run ! -type d -print0; \
829 $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
832 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
833 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
838 "${INITCMD_PREPARE[@]}"
842 ## Usage: prepareInit <vserver-directory>
845 pushd "$1/vdir" >/dev/null
848 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
851 "${STOPCMD_PREPARE[@]}"
856 function generateOptions
858 _generateInterfaceOptions "$1"
859 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
860 _generateNiceCommand "$1"
861 _generateIONiceCommand "$1"
862 _generateInitOptions "$1"
863 _generateChcontextOptions "$1"
864 _generateScheduleOptions "$1"
865 _generatePersonalityOptions "$1"
866 _generateTagOptions "$1"
867 _generateMemctrlOptions "$1"
868 _generateSpaceOptions "$1"
869 _generateCgroupOptions
871 if test -n "$_IS_FAKEINIT"; then
872 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
873 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
881 local f="$vdir"/cpuset
885 test -d "$f" || return 0
886 test -e "$f"/name || return 0
888 read cpuset < "$f"/name
889 test -e "$f"/nocreate || {
890 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
891 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
892 if test -e "$f"/"$i"; then
893 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
901 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
902 if [ "$configured" -ne 0 ]; then
904 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
905 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
910 function removeCPUSET
914 local f="$vdir"/cpuset
916 test -d "$f" || return 0
917 test -e "$f"/name || return 0
919 read cpuset < "$f"/name
920 test -e "$f"/nocreate || {
921 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
925 function _mountVserverInternal
930 test -e "$fstab" || return 0
933 pushd "$vdir" >/dev/null
934 # check whether / is mounted readonly or whether there is special
935 # magic regarding the mtab file; when etc/mtab can not be touched,
936 # add the '-n' flag to mount
937 test -w etc -o -w etc/mtab || xflag=-n
938 if test -h etc/mtab; then
939 local l=$($_READLINK etc/mtab)
940 test "${l##/proc/}" = "$l" || xflag=-n
942 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
950 local fstab="$cfgdir"/fstab
953 test -e "$fstab" || return 0
954 pushd "$vdir" >/dev/null
955 # check whether / is mounted readonly or whether there is special
956 # magic regarding the mtab file; when etc/mtab can not be touched,
957 # add the '-n' flag to mount
958 test -w etc -o -w etc/mtab || xflag=-n
959 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
963 function mountVserver
972 test -e "$cfgdir"/fstab -o \
973 -e "$cfgdir"/fstab.local -o \
974 -e "$cfgdir"/fstab.remote || return 0
976 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
978 pushd "$vdir" >/dev/null
979 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
982 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
984 _mountVserverInternal "$cfgdir"/fstab
985 _mountVserverInternal "$cfgdir"/fstab.local
986 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
988 isNamespaceCleanup "$cfgdir" && \
989 _namespaceCleanup "$cfgdir"
991 real_vdir=$(getPhysicalDir "$vdir")
992 isAvoidNamespace "$cfgdir" || \
993 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
994 ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
995 $_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
998 function _umountVserverInternal
1001 test -e "$fstab" || return 0
1006 while read src dst tmp; do
1007 test -n "$tmp" || continue
1013 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
1019 function umountVserver
1025 isAvoidNamespace "$cfgdir" || return 0
1026 test -e "$cfgdir"/fstab -o \
1027 -e "$cfgdir"/fstab.local -o \
1028 -e "$cfgdir"/fstab.remote || return 0
1029 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
1031 pushd "$vdir/" >/dev/null || return 1
1032 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1033 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1034 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1035 popd >/dev/null || return 1
1043 local fstab="$cfgdir"/fstab
1047 test -e "$fstab" || return 0
1049 export FSTAB_FILE="$fstab"
1052 test "$fsck_exitcode" -eq 0 -o \
1053 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1056 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1060 test -n "$_NEED_VSHELPER_SYNC" && \
1061 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1063 vshelper.initSync "$1" "$3" "$_is_meth"
1066 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1069 if $_VSERVER_INFO - FEATURE vwait; then
1071 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1074 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1075 --status-fd 3 "$2" \
1076 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1079 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1080 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1081 killContext "$S_CONTEXT" 9
1085 ) 4>$_is_tmpdir/procs &
1087 echo "$!" >$_is_tmpdir/pid
1088 eval "$3"=$_is_tmpdir
1093 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1094 function _waitForVWait
1099 declare -r procs=$(cat $4)
1101 getFileArray status "$2"
1106 'vwait' exited with error '$2' which indicates that vserver could not
1107 be stopped properly"
1110 (KILLED) warning $"\
1111 A timeout occured while waiting for the vserver to finish and it was
1112 killed by sending a SIGKILL signal. Please investigate the reasons
1113 and/or increase the timeout in apps/vshelper/sync-timeout."
1116 (TIMEOUT) warning $"\
1117 A timeout occured while waiting for the vserver to finish and it will
1118 be killed by sending a SIGKILL signal. The following process list
1119 might be useful for finding out the reason of this behavior:
1121 ----------------------------------------------------------------------
1123 }----------------------------------------------------------------------"
1126 (\?\?\?|*) warning $"\
1127 internal error: 'vwait' exited with an unexpected status '$1'; I will
1128 try to continue but be prepared for unexpected events."
1135 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1136 function waitForSync
1140 local vwait_statdir=$3
1143 if test -d "$vwait_statdir"; then
1144 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1145 elif test -n "$_NEED_VSHELPER_SYNC"; then
1146 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1148 A timeout or other error occured while waiting for the synchronization
1149 signal from vserver '$VSERVER_NAME'.
1150 The vserver will be killed nevertheless..."
1151 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1152 "${INITCMD_STOP_SYNC[@]}" || \
1154 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1155 will be killed nevertheless..."
1158 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1162 function _sourceWrap
1164 local vdir name flavor start i already_handled base
1168 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1169 function execScriptlets
1173 declare -r flavor=$3
1176 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1177 local DONT_SKIP_DEFAULTS=
1178 local already_handled=
1180 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1181 isRegularFile "$i" || continue
1182 test -r "$i" || continue
1186 test -x "$i" || start=_sourceWrap
1187 $start "$i" "$flavor" "$name"
1190 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1195 function sanityCheck
1197 declare -r cfgdir=$1
1199 ! test -e "$cfgdir"/fstab.local ||
1201 WARNING: 'fstab' will *not* be executed in the network context of the
1202 vserver anymore. Therefore, 'fstab.local' has the same functionality
1203 and is obsoleted. When you need the old behaviour, put the mounts
1204 into 'fstab.remote'"
1206 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1208 WARNING: The hostname is now configured in 'uts/nodename' but not in
1211 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1213 WARNING: The domainname is now configured in 'uts/domainname' but not
1214 in 'domainname'." >&2
1218 for i in "$cfgdir"/interfaces/*/only_ip; do
1219 if test -e "$i"; then
1221 iface=${i##$cfgdir/interfaces/}
1222 iface=${iface%%/only_ip}
1224 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1229 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1231 WARNING: There is no cachedirectory configured for this vserver;
1232 please create '$cfgdir/cache' e.g. by executing
1234 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1237 $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1239 vshelper.doSanityCheck
1241 $_VSERVER_INFO - VERIFYCAP ||
1242 panic $"capabilities are not enabled in kernel-setup"
1244 $_VSERVER_INFO - VERIFYPROC ||
1246 /proc/uptime can not be accessed. Usually, this is caused by
1247 procfs-security. Please read the FAQ for more details
1248 http://linux-vserver.org/Proc-Security"
1250 test -e "$cfgdir"/context || {
1251 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1252 test "$TYPE" != "static" || panic $"\
1253 The kernel does not have dynamic contexts enabled. Please configure
1254 a static one by executing
1256 echo [number between 2 and 49151] > $cfgdir/context"
1261 function _setSingleDiskLimit
1273 getFileValue ctx "$vdir/context"
1274 getFileValue directory "$dlimit/directory" || return 0
1275 getFileValue space_total "$dlimit/space_total" || return 0
1276 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1277 getFileValue reserved "$dlimit/reserved" || return 0
1279 local cachename=$ctx$directory
1280 cachename=dlimits/${cachename//\//_}
1282 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1283 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1284 $_RM -f "$vdir/cache/$cachename"
1286 if test -z "$inodes_used" -o -z "$space_used"; then
1288 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1289 inodes_used=${tmpvdu##* }
1290 space_used=${tmpvdu%% *}
1293 $_VDLIMIT --xid $ctx \
1294 --set space_used=$space_used \
1295 --set space_total=$space_total \
1296 --set inodes_used=$inodes_used \
1297 --set inodes_total=$inodes_total \
1298 --set reserved=$reserved \
1303 function setDiskLimits
1308 # Disk Limits without a static context are useless
1309 test -e "$vdir"/context || return 0
1311 for dlimit in "$vdir/dlimits/"*; do
1312 test -d "$dlimit" || continue
1313 test ! -e "$dlimit/disabled" || continue
1315 _setSingleDiskLimit "$vdir" "$dlimit"
1320 function _saveSingleDiskLimit
1327 getFileValue ctx "$vdir/context"
1328 getFileValue directory "$dlimit/directory" || return 0
1330 local cachename=$ctx$directory
1331 cachename=${cachename//\//_}
1333 # Things are getting ugly here... LFS says that /var/cache (where
1334 # cachename is usually pointing to) can vanish and applications
1335 # have to deal with it. So, we have to interprete the $vdir/cache
1336 # symlink and have to create the needed directories manually.
1337 if test -d "$vdir/cache"; then
1338 : # ok, exists already
1339 elif test -L "$vdir/cache"; then
1340 # it's a dangling symlink
1342 link=$($_READLINK "$vdir/cache")
1343 ( cd $vdir && $_MKDIR -p "$link" )
1348 test -d "$vdir/cache"
1349 $_MKDIR -p "$vdir"/cache/dlimits
1351 $_VDLIMIT --xid $ctx "$directory" | \
1352 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1354 $_VDLIMIT --xid $ctx --remove "$directory"
1358 function saveDiskLimits
1363 test -e "$vdir"/context || return 0
1365 for dlimit in "$vdir/dlimits/"*; do
1366 test -d "$dlimit" || continue
1367 test ! -e "$dlimit/disabled" || continue
1369 _saveSingleDiskLimit "$vdir" "$dlimit"
1373 function _namespaceCleanup
1376 local root=$($_VSERVER_INFO "$1" VDIR 1)
1382 getFileArray skip "$vdir"/namespace-cleanup-skip \
1383 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1385 # these are things that have to be accessible post-cleanup
1386 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1387 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1388 local real=`getPhysicalDir "$i"`
1389 test "$i" != "$real" || real=
1390 for j in "$i" "$real"; do
1391 while test -n "$j"; do
1392 list=( "${list[@]}" "$j" )
1398 local -a list_umount
1399 while read -r dev path opts; do
1400 test -n "$path" || continue
1401 for i in "$root" /dev /proc; do
1403 test "${path_dir#${i}/}" != "${path_dir}" && continue 2
1405 for i in "${list[@]}" /; do
1406 test "$path" = "$i" && continue 2
1408 # unmount them in reverse order so mounts further down the tree get unmounted first
1409 list_umount=( "$path" "${list_umount[@]}" )
1411 # separate loop to avoid races while reading /proc/mounts
1412 for i in "${list_umount[@]}"; do
1413 $_UMOUNT -l -n -i "$i"
1417 function handleDeviceMap
1422 local flags device target
1424 test -d "$dir" || return 0
1425 test -n "$xid" || return 0
1427 for i in "$dir"/*; do
1428 test -d "$i" || continue
1430 local -a vdevmap_opts=()
1431 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1432 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1433 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1435 getFileValue flags "$i/flags" || :
1436 getFileValue device "$i/device" || :
1437 getFileValue target "$i/target" || :
1438 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1439 ${device:+--device "$device"} ${target:+--target "$target"} )
1441 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1447 $_GREP -q "cgroup" /proc/filesystems
1450 function _generateCgroupOptions
1454 hasCgroup || return 0
1456 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1457 if test -n "$file"; then
1458 read CGROUP_MNT < "$file"
1460 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1461 if test -n "$file"; then
1462 read CGROUP_SUBSYS < "$file"
1463 elif $_GREP -q '^ns[[:space:]]' /proc/cgroups; then
1464 # Hack for the ns subsystem, with which we are incompatible
1465 CGROUP_SUBSYS=$($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups | \
1466 (s=""; while read x; do test -n "$s" && s="$s,"; s="$s$x"; done; echo "$s"))
1468 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1469 if test -n "$file"; then
1470 _readFileToArray CGROUP_INHERIT "$file" ""
1478 hasCgroup || return 1
1479 test -d "$CGROUP_MNT" || return 1
1480 test -d "$1/cgroup" -o \
1481 \( -d "$__CONFDIR/.defaults/cgroup" -a \
1482 ! -e "$1/nocgroup" \)
1485 function _handleCgroup
1494 useCgroup "$vdir" || return 0
1496 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1497 test -d "$dir" || return 0
1499 if test -r "$dir"/name; then
1500 read name < "$dir"/name
1502 name="$VSERVER_NAME"
1505 if test "$action" = "attach"; then
1506 if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
1507 parent="$CGROUP_MNT/$name"
1508 parent="${parent%/*}"
1509 for i in "${CGROUP_INHERIT[@]}"; do
1510 test -f "$parent/$i" || continue
1511 cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
1515 for i in "$dir"/*; do
1517 test "$f" != mnt -a "$f" != subsys -a \
1518 "$f" != inherit -a "$f" != name || continue
1519 cat "$i" > "$CGROUP_MNT/$name/$f"
1522 echo "$$" > "$CGROUP_MNT/$name/tasks"
1523 elif test "$action" = "destroy"; then
1524 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1530 function attachToCgroup
1532 _handleCgroup attach "$@"
1535 function destroyCgroup
1537 _handleCgroup destroy "$@"