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 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
45 declare -a OPTS_VSCHED=()
46 declare -a OPTS_ENV=()
47 declare -a OPTS_VTAG_CREATE=()
48 declare -a OPTS_VTAG_ENTER=()
49 declare -a OPTS_VMEMCTRL=()
50 declare -a OPTS_VSPACE=()
52 declare -a STOPCMD_PREPARE=()
54 declare -a VSERVER_EXTRA_CMDS=()
57 VSHELPER_SYNC_TIMEOUT=30
62 _HAVE_INTERFACE_OPTIONS=
74 CGROUP_MNT=/dev/cgroup
76 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
78 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
80 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
86 function _readFileToArray
93 test -e "$_rfta_f" || return 0
94 while read _rfta_v; do
97 (*) eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
102 function _generateChbindOptions
110 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
112 local f="$vdir"/interfaces/bcast
113 getFileValue bcast "$f"
114 f="$vdir"/interfaces/lback
115 getFileValue lback "$f"
117 CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
118 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
121 for i in "${INTERFACES[@]}"; do
122 CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
125 _readFileToArray "$vdir"/nflags CHBIND_CMD --flag
126 _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
128 _HAVE_CHBIND_OPTIONS=1
131 function _generateNiceCommand
135 local current_nice=`$_NICE`
137 test -r "$vdir/nice" && read nice <"$vdir"/nice
139 let nice=$nice-$current_nice || :
140 NICE_CMD=( $_NICE -n $nice )
143 function _generateIONiceCommand
147 local ionice_priority=0
149 test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
150 test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
152 IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
155 function _generatePersonalityOptions
158 local f="$vdir"/personality
161 test -s "$f" || return 0
170 (*) flags=$flags$delim$tmp
177 OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
178 --personality-type "$type"
179 ${flags:+--personality-flags "$flags"} )
182 function _generateCCapabilityOptions
186 _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
189 function _generateBCapabilityOptions
193 _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
196 function _generateCapabilityOptions
201 _generateBCapabilityOptions "$vdir"
202 _generateCCapabilityOptions "$vdir"
204 test -e "$vdir"/capabilities || return 0
213 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
214 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
217 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
220 done <"$vdir"/capabilities
223 function getEnterShell
230 getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
232 test -n "$ENTER_SHELL" || {
234 for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
236 test -x "$vdir/vdir/$1" || continue
243 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
244 function sendKillSequence
250 while isCtxRunning "$ctx"; do
251 test -z "$wait" || sleep "$wait"
253 killContext "$ctx" "$1"
254 test -n "$2" || break
260 function _generateInitOptions
263 local cfgdir=$vdir/apps/init
268 INITCMD_START_SYNC=()
273 INITKILL_SEQ=( 15 5 9 )
274 CHCONTEXT_INIT_OPTS=()
277 test x"$INITSTYLE" = xrescue || \
278 getFileValue INITSTYLE "$cfgdir"/style
279 getFileValue RUNLEVEL_START "$cfgdir"/runlevel
280 getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
281 getFileValue RUNLEVEL_STOP "$cfgdir"/runlevel.stop
282 getFileArray INITKILL_SEQ "$cfgdir"/killseq || :
284 findFile _gio_env "$cfgdir"/environment \
285 "$__CONFDIR"/.defaults/apps/init/environment \
286 "$__PKGLIBDEFAULTDIR"/environment
287 getFileArray OPTS_ENV "$_gio_env" || :
289 case x"$INITSTYLE" in
291 INITCMD_START=( "${INITCMD_RESCUE[@]}" )
292 INITCMD_STOP=( /sbin/killall5 )
296 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
297 test -n "$RUNLEVEL_STOP" || RUNLEVEL_STOP=6
299 for i in /etc/init.d/rc /etc/rc.d/rc; do
300 test -x "$vdir/vdir/$i" || continue
301 INITCMD_START=( "$i" "$RUNLEVEL_START" )
302 INITCMD_STOP=( "$i" "$RUNLEVEL_STOP" )
304 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
305 OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
306 if test -n "$OPTION_DEBUG_SYSV"; then
307 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
308 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
313 INITCMD_START=( /sbin/init )
314 INITCMD_STOP=( /sbin/init )
316 _NEED_VSHELPER_SYNC=1
317 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
318 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
322 INITCMD_START=( /sbin/minit-start )
323 INITCMD_STOP=( /sbin/minit-stop )
325 INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
326 _NEED_VSHELPER_SYNC=1
327 test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
328 test -z "$RUNLEVEL_STOP" || INITCMD_STOP=( "${INITCMD_STOP[@]}" "$RUNLEVEL_STOP" )
329 ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
333 test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
334 RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
336 if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
337 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
338 elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
339 RC_WRAP=/lib/rc/sh/init-vserver.sh
341 panic "init-vserver.sh not found; aborting"
344 INITCMD_START=( env TERM=$TERM $RC_WRAP "$RUNLEVEL_START" )
345 INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
346 INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
350 test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
351 INITCMD_START=( /etc/rc.multi )
352 INITCMD_STOP=( /etc/rc.shutdown )
353 INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
357 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
360 if test x"$INITSTYLE" != xrescue; then
361 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
362 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
363 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
364 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
365 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
368 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
369 INITCMD_START_SYNC=()
374 if vshelper.isEnabled; then
375 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
381 function _generateFlagOptions
385 CHCONTEXT_FLAG_OPTS=()
387 test ! -e "$vdir"/flags || \
396 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
397 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
403 isAvoidNamespace "$vdir" || {
405 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
409 function _generateChcontextOptions
412 local ctx hostname domainname
417 read ctx <"$vdir"/context || :
419 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
420 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
423 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
425 _generateCapabilityOptions "$vdir"
426 _generateFlagOptions "$vdir"
428 CHCONTEXT_OPTS=( $SILENT_OPT \
429 "${CHCONTEXT_FLAG_OPTS[@]}" \
432 ${ctx:+--ctx "$ctx"} \
433 ${hostname:+--hostname "$hostname"} \
434 ${domainname:+--domainname "$domainname"} )
436 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
437 ${ctx:+--xid "$ctx"} )
438 ## put '--secure' at front so that it can be overridden
439 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
442 function _generateScheduleOptions
445 if test -d "$vdir"/sched; then
446 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
450 local f="$vdir"/schedule
451 test -e "$f" || return 0
453 local fill_rate interval tokens tokens_min tokens_max prio_bias
461 read prio_bias || prio_bias=
465 test -n "$prio_bias" || {
466 echo $"Bad content in '$f'; aborting..." >&2
470 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
471 --tokens "$tokens" --tokens_min "$tokens_min" \
472 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
475 function _getInterfaceValue
485 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
488 : ${_giv_tmp:=$_giv_dflt}
489 eval $_giv_val=\$_giv_tmp
492 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
493 function _transformMask2Prefix
497 test -n "$_tm2p_tmp" || {
498 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
505 function _addInterfaceCmd
507 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
508 let ++INTERFACE_CMDS_IDX
511 ## Usage: _generateMac <var> <iface> <ctx>
512 function _generateMac
515 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
519 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
522 function _getVLANInfo
527 creation of VLAN_PLUS_VID devices is not supported; please create them
528 before starting the vserver and use the 'nodev' flag then"
529 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
533 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
534 create them before starting the vserver and use the 'nodev' flag then"
535 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
537 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
538 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
549 test -e "$iface/tun" -o -e "$iface/tap" || return 1
550 test ! -e "$iface/tun" || echo --tun
551 test ! -e "$iface/tap" || echo --tap
552 test ! -e "$iface/nocsum" || echo --~checksum
553 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
554 if test -e "$iface/uid"; then
556 getFileValue uid "$iface/uid"
559 if test -e "$iface/gid"; then
561 getFileValue gid "$iface/gid"
564 if test -e "$iface/linktype"; then
566 getFileValue linktype "$iface/linktype"
567 echo --linktype "$linktype"
572 ## Usage: _processSingleInterface <interface-directory>
573 function _processSingleInterface
589 _getInterfaceValue ip '' "$iface"
590 _getInterfaceValue extip '' "$iface" "$iface/.."
591 _getInterfaceValue dev '' "$iface" "$iface/.."
592 _getInterfaceValue prefix '' "$iface" "$iface/.."
593 _getInterfaceValue mask '' "$iface" "$iface/.."
594 _getInterfaceValue bcast '' "$iface" "$iface/.."
595 _getInterfaceValue name '' "$iface"
596 _getInterfaceValue scope '' "$iface" "$iface/.."
597 _getInterfaceValue mac '' "$iface"
598 _getInterfaceValue peer '' "$iface"
600 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
601 test -n "$dev" -o -e "$iface"/nodev || {
602 echo $"No device specified for '$iface'" >&2
606 test ! -e "$iface"/down || up=
609 _transformMask2Prefix prefix "$prefix" "$mask"
610 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
612 test ! -e "$iface"/nodev || break
614 test ! -e "$iface"/only_ip || break
616 test -e "$iface/vlandev" \
617 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
618 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
619 -a ! -e "$iface/novlandev" \
620 -a ! -e "$iface/../novlandev" \) && {
622 if vlan_info=$(_getVLANInfo "$dev"); then
623 test -d /proc/net/vlan || {
624 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
627 _addInterfaceCmd VCONFIG $vlan_info
631 if ! test -e "$iface"/indirect; then
633 local use_bcast="broadcast ${bcast:-+}"
634 echo "$ip" | $_GREP -q : && use_bcast=
637 if tun_info=$(_getTunInfo "$iface"); then
638 _addInterfaceCmd TUNCTL "$dev" $tun_info
641 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
642 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
643 _addInterfaceCmd IP_LINK "$dev" $up
644 elif ! test -n "$N_CONTEXT"; then
645 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
648 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
649 _addInterfaceCmd MODPROBE dummy "$dev"
650 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
651 _addInterfaceCmd NAMEIF "$dev" "$mac"
652 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
653 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
660 ## Usage: _generateInterfaceOptions <vserver-directory>
661 function _generateInterfaceOptions
665 # XXX: This is here instead of in _generateChbindOptions
666 # to avoid a circular dependency
667 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
668 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
670 for iface in "$1/interfaces/"*; do
671 test -d "$iface" || continue
672 test ! -e "$iface"/disabled || continue
674 _processSingleInterface "$iface"
676 _HAVE_INTERFACE_OPTIONS=1
679 function enableInterfaces
684 lock "$__LOCKDIR"/vserver.interfaces
686 while test $i -lt $INTERFACE_CMDS_IDX; do
687 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
698 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
700 NAMEIF) $_NAMEIF "$@";;
701 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
702 $_VCONFIG add "$2" "$3" >/dev/null;;
703 IP_ADDR) $_IP addr add "$@";;
704 IP_ADDR_FLUSH) $_IP addr flush "$@";;
705 IP_LINK) $_IP link set "$@";;
706 IP_ROUTE) $_IP route add "$@";;
710 $_TUNCTL --persist "$@" "$dev"
712 *) echo "Unknown interface-command type '$type'" >&2; false;;
721 function disableInterfaces
723 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
725 local i=$INTERFACE_CMDS_IDX
728 lock "$__LOCKDIR"/vserver.interfaces
730 while test $i -gt 0; do
733 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
740 MODPROBE) $_RMMOD "${2:-$1}";;
742 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
743 IP_ADDR) $_IP addr del "$@";;
745 IP_LINK) ;; ## Ignore the link-down command for now
746 IP_ROUTE) $_IP route del "$@";;
747 TUNCTL) $_TUNCTL --~persist "$1";;
748 *) echo "Unknown interface-command type '$type'" >&2; false;;
755 function _generateTagOptions
760 getFileValue tag "$vdir/tag" "$vdir/context"
761 test -n "$tag" || return 0
763 OPTS_VTAG_CREATE=( --tag "$tag" )
764 OPTS_VTAG_ENTER=( --tag "$tag" )
767 function _generateMemctrlOptions
772 getFileValue badness "$vdir/badness"
773 test -n "$badness" || return 0
775 OPTS_VMEMCTRL=( --badness "$badness" )
778 function _generateSpaceOptions
781 local d="$vdir"/spaces
783 ( test ! -e "$d"/pid ) || \
784 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
786 test ! -e "$d"/net || {
787 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
788 # network context and namespace don't make much sense
789 _HAVE_CHBIND_OPTIONS=1
794 getFileValue mask "$d"/mask || \
795 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
798 ## Usage: prepareInit <vserver-directory>
801 pushd "$1/vdir" >/dev/null
804 { find var/run ! -type d -print0; \
805 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
808 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
809 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
814 "${INITCMD_PREPARE[@]}"
818 ## Usage: prepareInit <vserver-directory>
821 pushd "$1/vdir" >/dev/null
824 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
827 "${STOPCMD_PREPARE[@]}"
832 function generateOptions
834 _generateInterfaceOptions "$1"
835 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
836 _generateNiceCommand "$1"
837 _generateIONiceCommand "$1"
838 _generateInitOptions "$1"
839 _generateChcontextOptions "$1"
840 _generateScheduleOptions "$1"
841 _generatePersonalityOptions "$1"
842 _generateTagOptions "$1"
843 _generateMemctrlOptions "$1"
844 _generateSpaceOptions "$1"
845 _generateCgroupOptions
847 if test -n "$_IS_FAKEINIT"; then
848 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
849 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
857 local f="$vdir"/cpuset
861 test -d "$f" || return 0
862 test -e "$f"/name || return 0
864 read cpuset < "$f"/name
865 test -e "$f"/nocreate || {
866 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
867 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
868 if test -e "$f"/"$i"; then
869 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
877 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
878 if [ "$configured" -ne 0 ]; then
880 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
881 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
886 function removeCPUSET
890 local f="$vdir"/cpuset
892 test -d "$f" || return 0
893 test -e "$f"/name || return 0
895 read cpuset < "$f"/name
896 test -e "$f"/nocreate || {
897 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
901 function _mountVserverInternal
906 test -e "$fstab" || return 0
909 pushd "$vdir" >/dev/null
910 # check whether / is mounted readonly or whether there is special
911 # magic regarding the mtab file; when etc/mtab can not be touched,
912 # add the '-n' flag to mount
913 test -w etc -o -w etc/mtab || xflag=-n
914 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
922 local fstab="$cfgdir"/fstab
925 test -e "$fstab" || return 0
926 pushd "$vdir" >/dev/null
927 # check whether / is mounted readonly or whether there is special
928 # magic regarding the mtab file; when etc/mtab can not be touched,
929 # add the '-n' flag to mount
930 test -w etc -o -w etc/mtab || xflag=-n
931 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
935 function mountVserver
942 test -e "$cfgdir"/fstab -o \
943 -e "$cfgdir"/fstab.local -o \
944 -e "$cfgdir"/fstab.remote || return 0
946 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
948 pushd "$vdir" >/dev/null
949 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
952 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
954 _mountVserverInternal "$cfgdir"/fstab
955 _mountVserverInternal "$cfgdir"/fstab.local
956 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
958 isNamespaceCleanup "$cfgdir" && \
959 _namespaceCleanup "$cfgdir"
961 isAvoidNamespace "$cfgdir" || \
962 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "/"
965 function _umountVserverInternal
968 test -e "$fstab" || return 0
973 while read src dst tmp; do
974 test -n "$tmp" || continue
980 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
986 function umountVserver
992 isAvoidNamespace "$cfgdir" || return 0
993 test -e "$cfgdir"/fstab -o \
994 -e "$cfgdir"/fstab.local -o \
995 -e "$cfgdir"/fstab.remote || return 0
996 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
998 pushd "$vdir/" >/dev/null || return 1
999 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
1000 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
1001 _umountVserverInternal "$cfgdir"/fstab || is_ok=
1002 popd >/dev/null || return 1
1010 local fstab="$cfgdir"/fstab
1014 test -e "$fstab" || return 0
1016 export FSTAB_FILE="$fstab"
1019 test "$fsck_exitcode" -eq 0 -o \
1020 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1023 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1027 test -n "$_NEED_VSHELPER_SYNC" && \
1028 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1030 vshelper.initSync "$1" "$3" "$_is_meth"
1033 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1036 if $_VSERVER_INFO - FEATURE vwait; then
1038 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1041 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1042 --status-fd 3 "$2" \
1043 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1046 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1047 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1048 killContext "$S_CONTEXT" 9
1052 ) 4>$_is_tmpdir/procs &
1054 echo "$!" >$_is_tmpdir/pid
1055 eval "$3"=$_is_tmpdir
1060 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1061 function _waitForVWait
1066 declare -r procs=$(cat $4)
1068 getFileArray status "$2"
1073 'vwait' exited with error '$2' which indicates that vserver could not
1074 be stopped properly"
1077 (KILLED) warning $"\
1078 A timeout occured while waiting for the vserver to finish and it was
1079 killed by sending a SIGKILL signal. Please investigate the reasons
1080 and/or increase the timeout in apps/vshelper/sync-timeout."
1083 (TIMEOUT) warning $"\
1084 A timeout occured while waiting for the vserver to finish and it will
1085 be killed by sending a SIGKILL signal. The following process list
1086 might be useful for finding out the reason of this behavior:
1088 ----------------------------------------------------------------------
1090 }----------------------------------------------------------------------"
1093 (\?\?\?|*) warning $"\
1094 internal error: 'vwait' exited with an unexpected status '$1'; I will
1095 try to continue but be prepared for unexpected events."
1102 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1103 function waitForSync
1107 local vwait_statdir=$3
1110 if test -d "$vwait_statdir"; then
1111 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1112 elif test -n "$_NEED_VSHELPER_SYNC"; then
1113 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1115 A timeout or other error occured while waiting for the synchronization
1116 signal from vserver '$VSERVER_NAME'.
1117 The vserver will be killed nevertheless..."
1118 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1119 "${INITCMD_STOP_SYNC[@]}" || \
1121 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1122 will be killed nevertheless..."
1125 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1129 function _sourceWrap
1131 local vdir name flavor start i already_handled base
1135 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1136 function execScriptlets
1140 declare -r flavor=$3
1143 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1144 local DONT_SKIP_DEFAULTS=
1145 local already_handled=
1147 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1148 isRegularFile "$i" || continue
1149 test -r "$i" || continue
1153 test -x "$i" || start=_sourceWrap
1154 $start "$i" "$flavor" "$name"
1157 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1162 function sanityCheck
1164 declare -r cfgdir=$1
1166 ! test -e "$cfgdir"/fstab.local ||
1168 WARNING: 'fstab' will *not* be executed in the network context of the
1169 vserver anymore. Therefore, 'fstab.local' has the same functionality
1170 and is obsoleted. When you need the old behaviour, put the mounts
1171 into 'fstab.remote'"
1173 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1175 WARNING: The hostname is now configured in 'uts/nodename' but not in
1178 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1180 WARNING: The domainname is now configured in 'uts/domainname' but not
1181 in 'domainname'." >&2
1185 for i in "$cfgdir"/interfaces/*/only_ip; do
1186 if test -e "$i"; then
1188 iface=${i##$cfgdir/interfaces/}
1189 iface=${iface%%/only_ip}
1191 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1196 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1198 WARNING: There is no cachedirectory configured for this vserver;
1199 please create '$cfgdir/cache' e.g. by executing
1201 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1204 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1206 vshelper.doSanityCheck
1208 $_VSERVER_INFO - VERIFYCAP ||
1209 panic $"capabilities are not enabled in kernel-setup"
1211 $_VSERVER_INFO - VERIFYPROC ||
1213 /proc/uptime can not be accessed. Usually, this is caused by
1214 procfs-security. Please read the FAQ for more details
1215 http://linux-vserver.org/Proc-Security"
1217 test -e "$cfgdir"/context || {
1218 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1219 test "$TYPE" != "static" || panic $"\
1220 The kernel does not have dynamic contexts enabled. Please configure
1221 a static one by executing
1223 echo [number between 2 and 49151] > $cfgdir/context"
1228 function _setSingleDiskLimit
1240 getFileValue ctx "$vdir/context"
1241 getFileValue directory "$dlimit/directory" || return 0
1242 getFileValue space_total "$dlimit/space_total" || return 0
1243 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1244 getFileValue reserved "$dlimit/reserved" || return 0
1246 local cachename=$ctx$directory
1247 cachename=dlimits/${cachename//\//_}
1249 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1250 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1251 $_RM -f "$vdir/cache/$cachename"
1253 if test -z "$inodes_used" -o -z "$space_used"; then
1255 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1256 inodes_used=${tmpvdu##* }
1257 space_used=${tmpvdu%% *}
1260 $_VDLIMIT --xid $ctx \
1261 --set space_used=$space_used \
1262 --set space_total=$space_total \
1263 --set inodes_used=$inodes_used \
1264 --set inodes_total=$inodes_total \
1265 --set reserved=$reserved \
1270 function setDiskLimits
1275 # Disk Limits without a static context are useless
1276 test -e "$vdir"/context || return 0
1278 for dlimit in "$vdir/dlimits/"*; do
1279 test -d "$dlimit" || continue
1280 test ! -e "$dlimit/disabled" || continue
1282 _setSingleDiskLimit "$vdir" "$dlimit"
1287 function _saveSingleDiskLimit
1294 getFileValue ctx "$vdir/context"
1295 getFileValue directory "$dlimit/directory" || return 0
1297 local cachename=$ctx$directory
1298 cachename=${cachename//\//_}
1300 # Things are getting ugly here... LFS says that /var/cache (where
1301 # cachename is usually pointing to) can vanish and applications
1302 # have to deal with it. So, we have to interprete the $vdir/cache
1303 # symlink and have to create the needed directories manually.
1304 if test -d "$vdir/cache"; then
1305 : # ok, exists already
1306 elif test -L "$vdir/cache"; then
1307 # it's a dangling symlink
1309 link=$($_READLINK "$vdir/cache")
1310 ( cd $vdir && $_MKDIR -p "$link" )
1315 test -d "$vdir/cache"
1316 $_MKDIR -p "$vdir"/cache/dlimits
1318 $_VDLIMIT --xid $ctx "$directory" | \
1319 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1321 $_VDLIMIT --xid $ctx --remove "$directory"
1325 function saveDiskLimits
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 _saveSingleDiskLimit "$vdir" "$dlimit"
1340 function _namespaceCleanup
1343 local root=$($_VSERVER_INFO "$1" VDIR 1)
1349 getFileArray skip "$vdir"/namespace-cleanup-skip \
1350 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1352 # these are things that have to be accessible post-cleanup
1353 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1354 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1355 local real=`getPhysicalDir "$i"`
1356 test "$i" != "$real" || real=
1357 for j in "$i" "$real"; do
1358 while test -n "$j"; do
1359 list=( "${list[@]}" "$j" )
1365 local -a list_umount
1366 while read -r dev path opts; do
1367 test -n "$path" || continue
1368 for i in "$root" /dev /proc; do
1369 test "${path#$i}" != "$path" && continue 2
1371 for i in "${list[@]}" /; do
1372 test "$path" = "$i" && continue 2
1374 # unmount them in reverse order so mounts further down the tree get unmounted first
1375 list_umount=( "$path" "${list_umount[@]}" )
1377 # separate loop to avoid races while reading /proc/mounts
1378 for i in "${list_umount[@]}"; do
1379 $_UMOUNT -l -n -i "$i"
1383 function handleDeviceMap
1388 local flags device target
1390 test -d "$dir" || return 0
1391 test -n "$xid" || return 0
1393 for i in "$dir"/*; do
1394 test -d "$i" || continue
1396 local -a vdevmap_opts=()
1397 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1398 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1399 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1401 getFileValue flags "$i/flags" || :
1402 getFileValue device "$i/device" || :
1403 getFileValue target "$i/target" || :
1404 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1405 ${device:+--device "$device"} ${target:+--target "$target"} )
1407 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1413 $_GREP -q "cgroup" /proc/filesystems
1416 function _generateCgroupOptions
1420 hasCgroup || return 0
1422 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1423 if test -n "$file"; then
1424 read CGROUP_MNT < "$file"
1426 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1427 if test -n "$file"; then
1428 read CGROUP_SUBSYS < "$file"
1430 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1431 if test -n "$file"; then
1432 _readFileToArray CGROUP_INHERIT "$file" ""
1440 hasCgroup || return 1
1441 test -d "$CGROUP_MNT" || return 1
1442 test -d "$1/cgroup" -o \
1443 \( -d "$__CONFDIR/.defaults/cgroup" -a \
1444 ! -e "$1/nocgroup" \)
1447 function _handleCgroup
1456 useCgroup "$vdir" || return 0
1458 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1459 test -d "$dir" || return 0
1461 if test -r "$dir"/name; then
1462 read name < "$dir"/name
1464 name="$VSERVER_NAME"
1467 if test "$action" = "attach"; then
1468 if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
1469 parent="$CGROUP_MNT/$name"
1470 parent="${parent%/*}"
1471 for i in "${CGROUP_INHERIT[@]}"; do
1472 test -f "$parent/$i" || continue
1473 cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
1477 for i in "$dir"/*; do
1478 cat "$i" > "$CGROUP_MNT/$name/${i##*/}"
1481 echo "$$" > "$CGROUP_MNT/$name/tasks"
1482 elif test "$action" = "destroy"; then
1483 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1489 function attachToCgroup
1491 _handleCgroup attach "$@"
1494 function destroyCgroup
1496 _handleCgroup destroy "$@"