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 (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
353 if test x"$INITSTYLE" != xrescue; then
354 getFileArray INITCMD_START "$cfgdir"/cmd.start || :
355 getFileArray INITCMD_STOP "$cfgdir"/cmd.stop || :
356 getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
357 getFileArray INITCMD_STOP_SYNC "$cfgdir"/cmd.stop-sync || :
358 getFileArray INITCMD_PREPARE "$cfgdir"/cmd.prepare || :
361 test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
362 INITCMD_START_SYNC=()
367 if vshelper.isEnabled; then
368 vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
374 function _generateFlagOptions
378 CHCONTEXT_FLAG_OPTS=()
380 test ! -e "$vdir"/flags || \
389 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
390 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
396 isAvoidNamespace "$vdir" || {
398 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
402 function _generateChcontextOptions
405 local ctx hostname domainname
410 read ctx <"$vdir"/context || :
412 read hostname <"$vdir"/uts/nodename || read hostname <"$vdir"/hostname || :
413 read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
416 test -z "$S_CONTEXT" || ctx=$S_CONTEXT
418 _generateCapabilityOptions "$vdir"
419 _generateFlagOptions "$vdir"
421 CHCONTEXT_OPTS=( $SILENT_OPT \
422 "${CHCONTEXT_FLAG_OPTS[@]}" \
425 ${ctx:+--ctx "$ctx"} \
426 ${hostname:+--hostname "$hostname"} \
427 ${domainname:+--domainname "$domainname"} )
429 OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
430 ${ctx:+--xid "$ctx"} )
431 ## put '--secure' at front so that it can be overridden
432 OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
435 function _generateScheduleOptions
438 if test -d "$vdir"/sched; then
439 OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
443 local f="$vdir"/schedule
444 test -e "$f" || return 0
446 local fill_rate interval tokens tokens_min tokens_max prio_bias
454 read prio_bias || prio_bias=
458 test -n "$prio_bias" || {
459 echo $"Bad content in '$f'; aborting..." >&2
463 OPTS_VSCHED=( --fill-rate "$fill_rate" --interval "$interval" \
464 --tokens "$tokens" --tokens_min "$tokens_min" \
465 --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
468 function _getInterfaceValue
478 read _giv_tmp <"$_giv_i/$_giv_val" && break || :
481 : ${_giv_tmp:=$_giv_dflt}
482 eval $_giv_val=\$_giv_tmp
485 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
486 function _transformMask2Prefix
490 test -n "$_tm2p_tmp" || {
491 $_MASK2PREFIX "$3" || _tm2p_tmp=$?
498 function _addInterfaceCmd
500 eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
501 let ++INTERFACE_CMDS_IDX
504 ## Usage: _generateMac <var> <iface> <ctx>
505 function _generateMac
508 echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
512 eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
515 function _getVLANInfo
520 creation of VLAN_PLUS_VID devices is not supported; please create them
521 before starting the vserver and use the 'nodev' flag then"
522 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
526 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
527 create them before starting the vserver and use the 'nodev' flag then"
528 echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
530 (*.????) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
531 (*.*) echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
542 test -e "$iface/tun" -o -e "$iface/tap" || return 1
543 test ! -e "$iface/tun" || echo --tun
544 test ! -e "$iface/tap" || echo --tap
545 test ! -e "$iface/nocsum" || echo --~checksum
546 test -e "$iface/shared" || echo --nid-failure-ok "$N_CONTEXT"
547 if test -e "$iface/uid"; then
549 getFileValue uid "$iface/uid"
552 if test -e "$iface/gid"; then
554 getFileValue gid "$iface/gid"
557 if test -e "$iface/linktype"; then
559 getFileValue linktype "$iface/linktype"
560 echo --linktype "$linktype"
565 ## Usage: _processSingleInterface <interface-directory>
566 function _processSingleInterface
582 _getInterfaceValue ip '' "$iface"
583 _getInterfaceValue extip '' "$iface" "$iface/.."
584 _getInterfaceValue dev '' "$iface" "$iface/.."
585 _getInterfaceValue prefix '' "$iface" "$iface/.."
586 _getInterfaceValue mask '' "$iface" "$iface/.."
587 _getInterfaceValue bcast '' "$iface" "$iface/.."
588 _getInterfaceValue name '' "$iface"
589 _getInterfaceValue scope '' "$iface" "$iface/.."
590 _getInterfaceValue mac '' "$iface"
591 _getInterfaceValue peer '' "$iface"
593 test -n "$ip" || { echo $"Can not read ip for '$iface'" >&2; return 1; }
594 test -n "$dev" -o -e "$iface"/nodev || {
595 echo $"No device specified for '$iface'" >&2
599 test ! -e "$iface"/down || up=
602 _transformMask2Prefix prefix "$prefix" "$mask"
603 INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
605 test ! -e "$iface"/nodev || break
607 test ! -e "$iface"/only_ip || break
609 test -e "$iface/vlandev" \
610 -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
611 -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
612 -a ! -e "$iface/novlandev" \
613 -a ! -e "$iface/../novlandev" \) && {
615 if vlan_info=$(_getVLANInfo "$dev"); then
616 test -d /proc/net/vlan || {
617 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers" >&2
620 _addInterfaceCmd VCONFIG $vlan_info
624 if ! test -e "$iface"/indirect; then
626 local use_bcast="broadcast ${bcast:-+}"
627 echo "$ip" | $_GREP -q : && use_bcast=
630 if tun_info=$(_getTunInfo "$iface"); then
631 _addInterfaceCmd TUNCTL "$dev" $tun_info
634 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
635 #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
636 _addInterfaceCmd IP_LINK "$dev" $up
637 elif ! test -n "$N_CONTEXT"; then
638 echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
641 test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
642 _addInterfaceCmd MODPROBE dummy "$dev"
643 _addInterfaceCmd IP_LINK dev dummy0 address "$mac"
644 _addInterfaceCmd NAMEIF "$dev" "$mac"
645 _addInterfaceCmd IP_ADDR "$ip${prefix:+/$prefix}" dev "$dev"
646 test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
653 ## Usage: _generateInterfaceOptions <vserver-directory>
654 function _generateInterfaceOptions
658 # XXX: This is here instead of in _generateChbindOptions
659 # to avoid a circular dependency
660 getFileValue N_CONTEXT "$1/ncontext" "$1/context"
661 test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
663 for iface in "$1/interfaces/"*; do
664 test -d "$iface" || continue
665 test ! -e "$iface"/disabled || continue
667 _processSingleInterface "$iface"
669 _HAVE_INTERFACE_OPTIONS=1
672 function enableInterfaces
677 lock "$__LOCKDIR"/vserver.interfaces
679 while test $i -lt $INTERFACE_CMDS_IDX; do
680 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
691 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
693 NAMEIF) $_NAMEIF "$@";;
694 VCONFIG) $_VCONFIG set_name_type "$4" >/dev/null
695 $_VCONFIG add "$2" "$3" >/dev/null;;
696 IP_ADDR) $_IP addr add "$@";;
697 IP_ADDR_FLUSH) $_IP addr flush "$@";;
698 IP_LINK) $_IP link set "$@";;
699 IP_ROUTE) $_IP route add "$@";;
703 $_TUNCTL --persist "$@" "$dev"
705 *) echo "Unknown interface-command type '$type'" >&2; false;;
714 function disableInterfaces
716 test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
718 local i=$INTERFACE_CMDS_IDX
721 lock "$__LOCKDIR"/vserver.interfaces
723 while test $i -gt 0; do
726 eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
733 MODPROBE) $_RMMOD "${2:-$1}";;
735 VCONFIG) $_VCONFIG rem "$2.$3" >/dev/null;;
736 IP_ADDR) $_IP addr del "$@";;
738 IP_LINK) ;; ## Ignore the link-down command for now
739 IP_ROUTE) $_IP route del "$@";;
740 TUNCTL) $_TUNCTL --~persist "$1";;
741 *) echo "Unknown interface-command type '$type'" >&2; false;;
748 function _generateTagOptions
753 getFileValue tag "$vdir/tag" "$vdir/context"
754 test -n "$tag" || return 0
756 OPTS_VTAG_CREATE=( --tag "$tag" )
757 OPTS_VTAG_ENTER=( --tag "$tag" )
760 function _generateMemctrlOptions
765 getFileValue badness "$vdir/badness"
766 test -n "$badness" || return 0
768 OPTS_VMEMCTRL=( --badness "$badness" )
771 function _generateSpaceOptions
774 local d="$vdir"/spaces
776 ( test ! -e "$d"/pid ) || \
777 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
779 test ! -e "$d"/net || {
780 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
781 # network context and namespace don't make much sense
782 _HAVE_CHBIND_OPTIONS=1
787 getFileValue mask "$d"/mask || \
788 OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
791 ## Usage: prepareInit <vserver-directory>
794 pushd "$1/vdir" >/dev/null
797 { find var/run ! -type d -print0; \
798 find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
801 $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
802 : | $_CHROOT_SH truncate fastboot 2>/dev/null || :
807 "${INITCMD_PREPARE[@]}"
811 ## Usage: prepareInit <vserver-directory>
814 pushd "$1/vdir" >/dev/null
817 export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
820 "${STOPCMD_PREPARE[@]}"
825 function generateOptions
827 _generateInterfaceOptions "$1"
828 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
829 _generateNiceCommand "$1"
830 _generateIONiceCommand "$1"
831 _generateInitOptions "$1"
832 _generateChcontextOptions "$1"
833 _generateScheduleOptions "$1"
834 _generatePersonalityOptions "$1"
835 _generateTagOptions "$1"
836 _generateMemctrlOptions "$1"
837 _generateSpaceOptions "$1"
838 _generateCgroupOptions
840 if test -n "$_IS_FAKEINIT"; then
841 CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
842 OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
850 local f="$vdir"/cpuset
854 test -d "$f" || return 0
855 test -e "$f"/name || return 0
857 read cpuset < "$f"/name
858 test -e "$f"/nocreate || {
859 test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
860 for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
861 if test -e "$f"/"$i"; then
862 cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
870 echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
871 if [ "$configured" -ne 0 ]; then
873 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
874 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
879 function removeCPUSET
883 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 rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
894 function _mountVserverInternal
899 test -e "$fstab" || return 0
902 pushd "$vdir" >/dev/null
903 # check whether / is mounted readonly or whether there is special
904 # magic regarding the mtab file; when etc/mtab can not be touched,
905 # add the '-n' flag to mount
906 test -w etc -o -w etc/mtab || xflag=-n
907 "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
915 local fstab="$cfgdir"/fstab
918 test -e "$fstab" || return 0
919 pushd "$vdir" >/dev/null
920 # check whether / is mounted readonly or whether there is special
921 # magic regarding the mtab file; when etc/mtab can not be touched,
922 # add the '-n' flag to mount
923 test -w etc -o -w etc/mtab || xflag=-n
924 $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
928 function mountVserver
935 test -e "$cfgdir"/fstab -o \
936 -e "$cfgdir"/fstab.local -o \
937 -e "$cfgdir"/fstab.remote || return 0
939 findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
941 pushd "$vdir" >/dev/null
942 $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
945 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
947 _mountVserverInternal "$cfgdir"/fstab
948 _mountVserverInternal "$cfgdir"/fstab.local
949 _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
951 isNamespaceCleanup "$cfgdir" && \
952 _namespaceCleanup "$cfgdir"
954 isAvoidNamespace "$cfgdir" || \
955 $_SECURE_MOUNT --rbind -n -o dev "$vdir" "/"
958 function _umountVserverInternal
961 test -e "$fstab" || return 0
966 while read src dst tmp; do
967 test -n "$tmp" || continue
973 "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
979 function umountVserver
985 isAvoidNamespace "$cfgdir" || return 0
986 test -e "$cfgdir"/fstab -o \
987 -e "$cfgdir"/fstab.local -o \
988 -e "$cfgdir"/fstab.remote || return 0
989 test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
991 pushd "$vdir/" >/dev/null || return 1
992 _umountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
993 _umountVserverInternal "$cfgdir"/fstab.local || is_ok=
994 _umountVserverInternal "$cfgdir"/fstab || is_ok=
995 popd >/dev/null || return 1
1003 local fstab="$cfgdir"/fstab
1007 test -e "$fstab" || return 0
1009 export FSTAB_FILE="$fstab"
1012 test "$fsck_exitcode" -eq 0 -o \
1013 "$fsck_exitcode" -eq 1 || return $fsck_exitcode
1016 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
1020 test -n "$_NEED_VSHELPER_SYNC" && \
1021 ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
1023 vshelper.initSync "$1" "$3" "$_is_meth"
1026 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
1029 if $_VSERVER_INFO - FEATURE vwait; then
1031 _is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
1034 $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
1035 --status-fd 3 "$2" \
1036 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
1039 if test "$rc" -ne 0 -a "$rc" -ne 1; then
1040 $_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
1041 killContext "$S_CONTEXT" 9
1045 ) 4>$_is_tmpdir/procs &
1047 echo "$!" >$_is_tmpdir/pid
1048 eval "$3"=$_is_tmpdir
1053 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
1054 function _waitForVWait
1059 declare -r procs=$(cat $4)
1061 getFileArray status "$2"
1066 'vwait' exited with error '$2' which indicates that vserver could not
1067 be stopped properly"
1070 (KILLED) warning $"\
1071 A timeout occured while waiting for the vserver to finish and it was
1072 killed by sending a SIGKILL signal. Please investigate the reasons
1073 and/or increase the timeout in apps/vshelper/sync-timeout."
1076 (TIMEOUT) warning $"\
1077 A timeout occured while waiting for the vserver to finish and it will
1078 be killed by sending a SIGKILL signal. The following process list
1079 might be useful for finding out the reason of this behavior:
1081 ----------------------------------------------------------------------
1083 }----------------------------------------------------------------------"
1086 (\?\?\?|*) warning $"\
1087 internal error: 'vwait' exited with an unexpected status '$1'; I will
1088 try to continue but be prepared for unexpected events."
1095 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
1096 function waitForSync
1100 local vwait_statdir=$3
1103 if test -d "$vwait_statdir"; then
1104 _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
1105 elif test -n "$_NEED_VSHELPER_SYNC"; then
1106 $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
1108 A timeout or other error occured while waiting for the synchronization
1109 signal from vserver '$VSERVER_NAME'.
1110 The vserver will be killed nevertheless..."
1111 elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
1112 "${INITCMD_STOP_SYNC[@]}" || \
1114 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
1115 will be killed nevertheless..."
1118 test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
1122 function _sourceWrap
1124 local vdir name flavor start i already_handled base
1128 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
1129 function execScriptlets
1133 declare -r flavor=$3
1136 for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
1137 local DONT_SKIP_DEFAULTS=
1138 local already_handled=
1140 for i in "$base/$flavor" "$base/$flavor.d"/*; do
1141 isRegularFile "$i" || continue
1142 test -r "$i" || continue
1146 test -x "$i" || start=_sourceWrap
1147 $start "$i" "$flavor" "$name"
1150 test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
1155 function sanityCheck
1157 declare -r cfgdir=$1
1159 ! test -e "$cfgdir"/fstab.local ||
1161 WARNING: 'fstab' will *not* be executed in the network context of the
1162 vserver anymore. Therefore, 'fstab.local' has the same functionality
1163 and is obsoleted. When you need the old behaviour, put the mounts
1164 into 'fstab.remote'"
1166 ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
1168 WARNING: The hostname is now configured in 'uts/nodename' but not in
1171 ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
1173 WARNING: The domainname is now configured in 'uts/domainname' but not
1174 in 'domainname'." >&2
1178 for i in "$cfgdir"/interfaces/*/only_ip; do
1179 if test -e "$i"; then
1181 iface=${i##$cfgdir/interfaces/}
1182 iface=${iface%%/only_ip}
1184 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
1189 test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
1191 WARNING: There is no cachedirectory configured for this vserver;
1192 please create '$cfgdir/cache' e.g. by executing
1194 ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
1197 find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
1199 vshelper.doSanityCheck
1201 $_VSERVER_INFO - VERIFYCAP ||
1202 panic $"capabilities are not enabled in kernel-setup"
1204 $_VSERVER_INFO - VERIFYPROC ||
1206 /proc/uptime can not be accessed. Usually, this is caused by
1207 procfs-security. Please read the FAQ for more details
1208 http://linux-vserver.org/Proc-Security"
1210 test -e "$cfgdir"/context || {
1211 TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
1212 test "$TYPE" != "static" || panic $"\
1213 The kernel does not have dynamic contexts enabled. Please configure
1214 a static one by executing
1216 echo [number between 2 and 49151] > $cfgdir/context"
1221 function _setSingleDiskLimit
1233 getFileValue ctx "$vdir/context"
1234 getFileValue directory "$dlimit/directory" || return 0
1235 getFileValue space_total "$dlimit/space_total" || return 0
1236 getFileValue inodes_total "$dlimit/inodes_total" || return 0
1237 getFileValue reserved "$dlimit/reserved" || return 0
1239 local cachename=$ctx$directory
1240 cachename=dlimits/${cachename//\//_}
1242 test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1243 # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1244 $_RM -f "$vdir/cache/$cachename"
1246 if test -z "$inodes_used" -o -z "$space_used"; then
1248 tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1249 inodes_used=${tmpvdu##* }
1250 space_used=${tmpvdu%% *}
1253 $_VDLIMIT --xid $ctx \
1254 --set space_used=$space_used \
1255 --set space_total=$space_total \
1256 --set inodes_used=$inodes_used \
1257 --set inodes_total=$inodes_total \
1258 --set reserved=$reserved \
1263 function setDiskLimits
1268 # Disk Limits without a static context are useless
1269 test -e "$vdir"/context || return 0
1271 for dlimit in "$vdir/dlimits/"*; do
1272 test -d "$dlimit" || continue
1273 test ! -e "$dlimit/disabled" || continue
1275 _setSingleDiskLimit "$vdir" "$dlimit"
1280 function _saveSingleDiskLimit
1287 getFileValue ctx "$vdir/context"
1288 getFileValue directory "$dlimit/directory" || return 0
1290 local cachename=$ctx$directory
1291 cachename=${cachename//\//_}
1293 # Things are getting ugly here... LFS says that /var/cache (where
1294 # cachename is usually pointing to) can vanish and applications
1295 # have to deal with it. So, we have to interprete the $vdir/cache
1296 # symlink and have to create the needed directories manually.
1297 if test -d "$vdir/cache"; then
1298 : # ok, exists already
1299 elif test -L "$vdir/cache"; then
1300 # it's a dangling symlink
1302 link=$($_READLINK "$vdir/cache")
1303 ( cd $vdir && $_MKDIR -p "$link" )
1308 test -d "$vdir/cache"
1309 $_MKDIR -p "$vdir"/cache/dlimits
1311 $_VDLIMIT --xid $ctx "$directory" | \
1312 $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1314 $_VDLIMIT --xid $ctx --remove "$directory"
1318 function saveDiskLimits
1323 test -e "$vdir"/context || return 0
1325 for dlimit in "$vdir/dlimits/"*; do
1326 test -d "$dlimit" || continue
1327 test ! -e "$dlimit/disabled" || continue
1329 _saveSingleDiskLimit "$vdir" "$dlimit"
1333 function _namespaceCleanup
1336 local root=$($_VSERVER_INFO "$1" VDIR 1)
1342 getFileArray skip "$vdir"/namespace-cleanup-skip \
1343 "$__CONFDIR"/.defaults/namespace-cleanup-skip || :
1345 # these are things that have to be accessible post-cleanup
1346 for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
1347 "$__PKGSTATEDIR" "$__LOCKDIR" /usr/local /tmp "${skip[@]}"; do
1348 local real=`getPhysicalDir "$i"`
1349 test "$i" != "$real" || real=
1350 for j in "$i" "$real"; do
1351 while test -n "$j"; do
1352 list=( "${list[@]}" "$j" )
1358 local -a list_umount
1359 while read -r dev path opts; do
1360 test -n "$path" || continue
1361 for i in "$root" /dev /proc; do
1362 test "${path#$i}" != "$path" && continue 2
1364 for i in "${list[@]}" /; do
1365 test "$path" = "$i" && continue 2
1367 # unmount them in reverse order so mounts further down the tree get unmounted first
1368 list_umount=( "$path" "${list_umount[@]}" )
1370 # separate loop to avoid races while reading /proc/mounts
1371 for i in "${list_umount[@]}"; do
1372 $_UMOUNT -l -n -i "$i"
1376 function handleDeviceMap
1381 local flags device target
1383 test -d "$dir" || return 0
1384 test -n "$xid" || return 0
1386 for i in "$dir"/*; do
1387 test -d "$i" || continue
1389 local -a vdevmap_opts=()
1390 test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
1391 test -e "$i/open" && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
1392 test -e "$i/remap" && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
1394 getFileValue flags "$i/flags" || :
1395 getFileValue device "$i/device" || :
1396 getFileValue target "$i/target" || :
1397 vdevmap_opts=( "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
1398 ${device:+--device "$device"} ${target:+--target "$target"} )
1400 $_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
1406 $_GREP -q "cgroup" /proc/filesystems
1409 function _generateCgroupOptions
1413 hasCgroup || return 0
1415 findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
1416 if test -n "$file"; then
1417 read CGROUP_MNT < "$file"
1419 findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
1420 if test -n "$file"; then
1421 read CGROUP_SUBSYS < "$file"
1423 findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
1424 if test -n "$file"; then
1425 _readFileToArray CGROUP_INHERIT "$file" ""
1433 hasCgroup || return 1
1434 test -d "$CGROUP_MNT" || return 1
1435 test -d "$1/cgroup" -o \
1436 \( -d "$__CONFDIR/.defaults/cgroup" -a \
1437 ! -e "$1/nocgroup" \)
1440 function _handleCgroup
1449 useCgroup "$vdir" || return 0
1451 findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
1452 test -d "$dir" || return 0
1454 if test -r "$dir"/name; then
1455 read name < "$dir"/name
1457 read name < "$vdir"/name
1460 if test "$action" = "attach"; then
1461 if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
1462 parent="$CGROUP_MNT/$name"
1463 parent="${parent%/*}"
1464 for i in "${CGROUP_INHERIT[@]}"; do
1465 test -f "$parent/$i" || continue
1466 cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
1470 for i in "$dir"/*; do
1471 cat "$i" > "$CGROUP_MNT/$name/${i##*/}"
1474 echo "$$" > "$CGROUP_MNT/$name/tasks"
1475 elif test "$action" = "destroy"; then
1476 rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
1482 function attachToCgroup
1484 _handleCgroup attach "$@"
1487 function destroyCgroup
1489 _handleCgroup destroy "$@"