vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

vserver.functions (43278B)


      1 # $Id$  --*- sh -*--
      2 
      3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 #  
      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.
      8 #  
      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.
     13 #  
     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.
     17 
     18 ## Expected env:
     19 #  $VSERVER_DIR   ... path to vserver-cfg dir
     20 #  $VSERVER_NAME  ... name of vserver
     21 
     22 declare -a NICE_CMD=()
     23 declare -a IONICE_CMD=()
     24 declare -a NETNS_CMD=()
     25 declare -a CHBIND_CMD=()
     26 declare -a CAP_OPTS=()
     27 declare -a CHCONTEXT_INIT_OPTS=()
     28 declare -a CHCONTEXT_FLAG_OPTS=()
     29 declare -a CHCONTEXT_OPTS=()
     30 declare -a CAPCHROOT_OPTS=()
     31 declare -a INTERFACES=()
     32 
     33 declare -a INITCMD_RESCUE=( /bin/sleep 900 )
     34 declare -a INITCMD_START=()
     35 declare -a INITCMD_START_SYNC=()
     36 declare -a INITCMD_STOP=()
     37 declare -a INITCMD_STOP_SYNC=()
     38 declare -a INITCMD_PREPARE=()
     39 declare -a INITKILL_SEQ=()
     40 declare -a ENTER_SHELL=()
     41 
     42 declare -a OPTS_VCONTEXT_CREATE=()
     43 declare -a OPTS_VCONTEXT_MIGRATE=()
     44 declare -a OPTS_VCONTEXT_ENTER=()
     45 OPT_VCONTEXT_CHROOT=--chroot
     46 OPT_VCONTEXT_CLOSE_FD=""
     47 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
     48 declare -a OPTS_VSCHED=()
     49 declare -a OPTS_ENV=()
     50 declare -a OPTS_VTAG_CREATE=()
     51 declare -a OPTS_VTAG_ENTER=()
     52 declare -a OPTS_VMEMCTRL=()
     53 declare -a OPTS_VSPACE=( --default )
     54 declare -a OPTS_VSPACE_SHARED=()
     55 declare -a VSPACE_SHARED_CMD=()
     56 
     57 declare -a STOPCMD_PREPARE=()
     58 
     59 declare -a VSERVER_EXTRA_CMDS=()
     60 
     61 INIT_RESCUE=
     62 VSHELPER_SYNC_TIMEOUT=30
     63 USE_VNAMESPACE=
     64 INTERFACE_CMDS_IDX=0
     65 RUNLEVEL_START=
     66 RUNLEVEL_STOP=
     67 _HAVE_INTERFACE_OPTIONS=
     68 _HAVE_CHBIND_OPTIONS=
     69 _NEED_VSHELPER_SYNC=
     70 _IS_FAKEINIT=
     71 
     72 INITSTYLE=sysv
     73 
     74 S_CONTEXT=
     75 N_CONTEXT=
     76 
     77 SILENT_OPT=
     78 
     79 CGROUP_MNT=/dev/cgroup
     80 declare -a CGROUP_SUBSYS=()
     81 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
     82 CGROUP_BASE=""
     83 CGROUP_MNT_PER_SS=""
     84 
     85 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
     86 
     87 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
     88     SILENT_OPT=
     89 else
     90     SILENT_OPT='--silent'
     91 fi
     92 
     93 function _readFileToArray
     94 {
     95     local _rfta_f="$1"
     96     local _rfta_a="$2"
     97     local _rfta_p="$3"
     98     local _rfta_v
     99 
    100     test -e "$_rfta_f" || return 0
    101     while read _rfta_v; do
    102 	case x"$_rfta_v" in
    103 	    (x|x\#*)	;;
    104 	    (*)		eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
    105 	esac
    106     done <"$_rfta_f"
    107 }
    108 
    109 function _generateChbindOptions
    110 {
    111     local vdir="$1"
    112     local i
    113     local bcast=
    114     local lback=
    115     local nid=
    116 
    117     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
    118 
    119     if test -e "$vdir"/noncontext -o \
    120 	    \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
    121 	_HAVE_CHBIND_OPTIONS=1
    122 	return 0
    123     fi
    124 
    125     local f="$vdir"/interfaces/bcast
    126     getFileValue bcast "$f"
    127     f="$vdir"/interfaces/lback
    128     getFileValue lback "$f"
    129 
    130     CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
    131 		 ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
    132 		)
    133 
    134     for i in "${INTERFACES[@]}"; do
    135 	CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
    136     done
    137 
    138     _readFileToArray "$vdir"/nflags        CHBIND_CMD --flag
    139     _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
    140 
    141     _HAVE_CHBIND_OPTIONS=1
    142 }
    143 
    144 function _generateNiceCommand
    145 {
    146     local vdir=$1
    147     local nice=0
    148     local current_nice=`$_NICE`
    149 
    150     test -r "$vdir/nice" && read nice <"$vdir"/nice
    151 
    152     let nice=$nice-$current_nice || :
    153     NICE_CMD=( $_NICE -n $nice )
    154 }
    155 
    156 function _generateIONiceCommand
    157 {
    158     local vdir=$1
    159     local ionice_class=
    160     local ionice_priority=
    161 
    162     test -n "$_IONICE" || return 0
    163 
    164     test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
    165     test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
    166 
    167     test -n "$ionice_class$ionice_priority" || return 0
    168 
    169     if test -z "$ionice_class" -a -n "$ionice_priority"; then
    170 	IONICE_CMD=( $_IONICE -c2 -n"$ionice_priority" )
    171     else
    172 	IONICE_CMD=( $_IONICE ${ionice_class:+-c$ionice_class} ${ionice_priority:+-n$ionice_priority} )
    173     fi
    174 }
    175 
    176 function _generatePersonalityOptions
    177 {
    178     local vdir="$1"
    179     local f="$vdir"/personality
    180     local type flags
    181 
    182     test -s "$f" || return 0
    183 
    184     {
    185 	local delim tmp
    186 
    187 	read type
    188 	while read tmp; do
    189 	    case x$tmp in
    190 		(x\#*|x)	;;
    191 		(*)		flags=$flags$delim$tmp
    192 				delim=,
    193 				;;
    194 	    esac
    195 	done
    196     } <"$f"
    197 
    198     OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
    199                           --personality-type "$type"
    200 			  ${flags:+--personality-flags "$flags"} )
    201 }
    202 
    203 function _generateCCapabilityOptions
    204 {
    205     local vdir=$1
    206 
    207     _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
    208 }
    209 
    210 function _generateBCapabilityOptions
    211 {
    212     local vdir=$1
    213 
    214     _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
    215 }
    216 
    217 function _generateUMaskOptions
    218 {
    219     local vdir=$1
    220 
    221     _readFileToArray "$vdir"/umask OPTS_VATTRIBUTE --umask
    222 }
    223 
    224 function _generateCapabilityOptions
    225 {
    226     local vdir=$1
    227     local cap
    228 
    229     _generateBCapabilityOptions "$vdir"
    230     _generateCCapabilityOptions "$vdir"
    231     
    232     test -e "$vdir"/capabilities || return 0
    233 
    234     CAP_OPTS=()
    235     CAPCHROOT_OPTS=()
    236 
    237     while read cap; do
    238 	case x"$cap" in
    239 	    (x|x\#*)	;;
    240 	    (!CAP_SYSCHROOT)
    241 		CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
    242 		CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
    243 		;;
    244 	    (*)
    245 		CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
    246 		;;
    247 	esac
    248     done <"$vdir"/capabilities
    249 }
    250 
    251 function getEnterShell
    252 {
    253     local vdir=$1
    254     local shell_file
    255 
    256     ENTER_SHELL=()
    257 
    258     getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
    259     
    260     test -n "$ENTER_SHELL" || {
    261 	local i
    262 	for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
    263 	    set -- $i
    264 	    test -x "$vdir/vdir/$1" || continue
    265 	    ENTER_SHELL=( "$@" )
    266 	    break
    267 	done
    268     }
    269 }
    270 
    271 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
    272 function sendKillSequence
    273 {
    274     local ctx=$1
    275     local wait=
    276     shift
    277 
    278     while isCtxRunning "$ctx"; do
    279 	test -z "$wait" || sleep "$wait"
    280 
    281 	killContext "$ctx" "$1"
    282 	test -n "$2" || break
    283 	wait="$2"
    284 	shift 2
    285     done
    286 }
    287 
    288 function _generateInitOptions
    289 {
    290     local vdir=$1
    291     local cfgdir=$vdir/apps/init
    292     local i f
    293 
    294     INITCMD_START=()
    295     INITCMD_STOP=()
    296     INITCMD_START_SYNC=()
    297     INITCMD_STOP_SYNC=()
    298     INITCMD_PREPARE=()
    299     STOPCMD_PREPARE=()
    300 
    301     INITKILL_SEQ=( 15 5 9 )
    302     CHCONTEXT_INIT_OPTS=()
    303 
    304 
    305     test x"$INITSTYLE" = xrescue || \
    306       getFileValue INITSTYLE    "$cfgdir"/style
    307     getFileValue RUNLEVEL_START "$cfgdir"/runlevel
    308     getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
    309     getFileValue RUNLEVEL_STOP  "$cfgdir"/runlevel.stop
    310     getFileArray INITKILL_SEQ	"$cfgdir"/killseq || :
    311 
    312     findFile _gio_env		"$cfgdir"/environment \
    313 	"$__CONFDIR"/.defaults/apps/init/environment \
    314 	"$__PKGLIBDEFAULTDIR"/environment
    315     getFileArray OPTS_ENV	"$_gio_env" || :
    316 
    317     case x"$INITSTYLE" in
    318 	(xrescue)
    319 	    INITCMD_START=( "${INITCMD_RESCUE[@]}" )
    320 	    INITCMD_STOP=( /sbin/killall5 )
    321 	    ;;
    322 	    
    323 	(xsysv)
    324 	    test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
    325 	    test -n "$RUNLEVEL_STOP"  || RUNLEVEL_STOP=6
    326 
    327 	    for i in /etc/init.d/rc /etc/rc.d/rc; do
    328 		test -x "$vdir/vdir/$i" || continue
    329 		INITCMD_START=( "$i" "$RUNLEVEL_START" )
    330 		INITCMD_STOP=(  "$i" "$RUNLEVEL_STOP"  )
    331 	    done
    332 	    INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
    333 	    OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
    334 	    if test -n "$OPTION_DEBUG_SYSV"; then
    335 		INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
    336 		INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
    337 	    fi
    338 	    ;;
    339 	    
    340 	(xplain)
    341 	    INITCMD_START=( /sbin/init )
    342 	    INITCMD_STOP=(  /sbin/init )
    343 	    _IS_FAKEINIT=1
    344 	    _NEED_VSHELPER_SYNC=1
    345 	    test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
    346 	    test -z "$RUNLEVEL_STOP"  || INITCMD_STOP=(  "${INITCMD_STOP[@]}"  "$RUNLEVEL_STOP"  )
    347 	    ;;
    348 	    
    349 	(xminit)
    350 	    INITCMD_START=( /sbin/minit-start )
    351 	    INITCMD_STOP=(  /sbin/minit-stop  )
    352 	    _IS_FAKEINIT=1
    353 	    INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
    354 	    _NEED_VSHELPER_SYNC=1
    355 	    test -z "$RUNLEVEL_START"         || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
    356 	    test -z "$RUNLEVEL_STOP"          || INITCMD_STOP=(  "${INITCMD_STOP[@]}"  "$RUNLEVEL_STOP"  )
    357 	    ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
    358 	    ;;
    359 
    360 	(xgentoo|xopenrc)
    361 	    test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
    362 	    RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
    363 
    364 	    if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
    365 	    	RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
    366 	    elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
    367 	    	RC_WRAP=/lib/rc/sh/init-vserver.sh
    368 	    else
    369 	    	panic "init-vserver.sh not found; aborting"
    370 	    fi
    371 
    372 	    OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
    373 	    INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
    374 	    INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
    375 	    INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
    376 	    ;;
    377 
    378 	(xarch)
    379 	    test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
    380 	    INITCMD_START=( /etc/rc.multi )
    381 	    INITCMD_STOP=( /etc/rc.shutdown )
    382 	    INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
    383 	    ;;
    384 
    385 	(x) ;;
    386 	(*) panic "Unknown init-style '$INITSTYLE'; aborting";;
    387     esac
    388 
    389     if test x"$INITSTYLE" != xrescue; then
    390 	getFileArray INITCMD_START      "$cfgdir"/cmd.start      || :
    391 	getFileArray INITCMD_STOP       "$cfgdir"/cmd.stop       || :
    392 	getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
    393 	getFileArray INITCMD_STOP_SYNC  "$cfgdir"/cmd.stop-sync  || :
    394 	getFileArray INITCMD_PREPARE    "$cfgdir"/cmd.prepare    || :
    395     fi
    396     
    397     test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
    398 	INITCMD_START_SYNC=()
    399 	INITCMD_STOP_SYNC=()
    400 	_NEED_VSHELPER_SYNC=
    401     }
    402 
    403     if vshelper.isEnabled; then
    404 	vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
    405     else
    406 	_NEED_VSHELPER_SYNC=
    407     fi
    408 }
    409 
    410 function _generateFlagOptions
    411 {
    412     local vdir=$1
    413     local file
    414 
    415     CHCONTEXT_FLAG_OPTS=()
    416 
    417     findFile file "$vdir"/cflags "$vdir"/flags ""
    418     test -z "$file" || \
    419     while read flag; do
    420 	case x"$flag" in
    421 	    (x|x\#*)		;;
    422 	    (xnamespace)	;;
    423 	    (xfakeinit)
    424 		_IS_FAKEINIT=1
    425 		;;
    426 	    (*)
    427 		OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
    428 	    	CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
    429 				      --flag "$flag" )
    430 		;;
    431 	esac
    432     done <"$file"
    433 
    434     isAvoidNamespace "$vdir" || {
    435 	USE_VNAMESPACE=1
    436 	CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
    437 	! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
    438 	    OPT_VCONTEXT_CHROOT=--pivot-root
    439     }
    440 }
    441 
    442 function _generateChcontextOptions
    443 {
    444     local vdir=$1
    445     local ctx hostname domainname
    446     local cap_opts
    447     local flag
    448 
    449     {
    450 	read ctx        <"$vdir"/context        || :
    451 	## LEGACY ALERT
    452 	read hostname   <"$vdir"/uts/nodename   || read hostname   <"$vdir"/hostname   || :
    453 	read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
    454     } 2>/dev/null
    455 
    456     test -z "$S_CONTEXT" || ctx=$S_CONTEXT
    457 
    458     _generateCapabilityOptions "$vdir"
    459     _generateFlagOptions       "$vdir"
    460     _generateUMaskOptions      "$vdir"
    461 
    462     CHCONTEXT_OPTS=( $SILENT_OPT \
    463                      "${CHCONTEXT_FLAG_OPTS[@]}" \
    464 		     "${CAP_OPTS[@]}" \
    465 		     --secure
    466 		     ${ctx:+--ctx "$ctx"} \
    467                      ${hostname:+--hostname "$hostname"} \
    468 		     ${domainname:+--domainname "$domainname"} )
    469 
    470     OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
    471 			   ${ctx:+--xid "$ctx"} )
    472     findFile file "$vdir"/keepfds "$__CONFDIR/.defaults/keepfds" ""
    473     test -n "$file" || OPT_VCONTEXT_CLOSE_FD="--closefd"
    474     ## put '--secure' at front so that it can be overridden
    475     OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
    476 }
    477 
    478 function _generateScheduleOptions
    479 {
    480     local vdir=$1
    481     if test -d "$vdir"/sched; then
    482       OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
    483       return 0
    484     fi
    485 
    486     local f="$vdir"/schedule
    487     test -e "$f" || return 0
    488 
    489     local fill_rate interval tokens tokens_min tokens_max prio_bias
    490     {
    491 	{
    492 	    read fill_rate   && \
    493 	    read interval    && \
    494 	    read tokens      && \
    495 	    read tokens_min  && \
    496 	    read tokens_max  && \
    497 	    read prio_bias   || prio_bias=
    498 	} <"$f"
    499     } 2>/dev/null
    500 
    501     test -n "$prio_bias" || {
    502 	echo $"Bad content in '$f'; aborting..." >&2
    503 	false
    504     }
    505 
    506     OPTS_VSCHED=( --fill-rate  "$fill_rate"  --interval "$interval" \
    507 		  --tokens     "$tokens"     --tokens_min "$tokens_min" \
    508 		  --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
    509 }
    510 
    511 function _getInterfaceValue
    512 {
    513     local _giv_val=$1
    514     local _giv_dflt=$2
    515     shift 2
    516     
    517     local _giv_i
    518     local _giv_tmp
    519 
    520     for _giv_i; do
    521 	read _giv_tmp  <"$_giv_i/$_giv_val" && break || :
    522     done 2>/dev/null
    523 
    524     : ${_giv_tmp:=$_giv_dflt}
    525     eval $_giv_val=\$_giv_tmp
    526 }
    527 
    528 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
    529 function _transformMask2Prefix
    530 {
    531     local _tm2p_tmp=$2
    532     
    533     test -n "$_tm2p_tmp" || {
    534 	$_MASK2PREFIX "$3" || _tm2p_tmp=$?
    535     }
    536 
    537     eval $1=\$_tm2p_tmp
    538     return 0
    539 }
    540 
    541 function _addInterfaceCmd
    542 {
    543     eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
    544     let ++INTERFACE_CMDS_IDX
    545 }
    546 
    547 ## Usage: _generateMac <var> <iface> <ctx>
    548 function _generateMac
    549 {
    550     isNumber "$2" || {
    551 	echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
    552 	return 1
    553     }
    554 
    555     eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
    556 }
    557 
    558 function _getVLANInfo
    559 {
    560     case "$1" in
    561 	(vlan????)
    562 	    panic "\
    563 creation of VLAN_PLUS_VID devices is not supported; please create them
    564 before starting the vserver and use the 'nodev' flag then"
    565 	    echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
    566 	    ;;
    567 	(vlan*)
    568 	    panic "\
    569 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
    570 create them before starting the vserver and use the 'nodev' flag then"
    571 	    echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
    572 	    ;;
    573 	(*.????)	echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
    574 	(*.*)		echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
    575 	(*)		return 1
    576     esac
    577 
    578     return 0
    579 }
    580 
    581 function _getTunInfo
    582 {
    583     local iface="$1"
    584 
    585     test -e "$iface/tun" -o -e "$iface/tap" || return 1
    586     test ! -e "$iface/tun"     || echo --tun
    587     test ! -e "$iface/tap"     || echo --tap
    588     test ! -e "$iface/nocsum"  || echo --~checksum
    589     test   -e "$iface/shared"  || echo --nid-failure-ok "$N_CONTEXT"
    590     if test -e "$iface/uid"; then
    591 	local uid
    592 	getFileValue uid "$iface/uid"
    593 	echo --uid "$uid"
    594     fi
    595     if test -e "$iface/gid"; then
    596 	local gid
    597 	getFileValue gid "$iface/gid"
    598 	echo --gid "$gid"
    599     fi
    600     if test -e "$iface/linktype"; then
    601 	local linktype
    602 	getFileValue linktype "$iface/linktype"
    603 	echo --linktype "$linktype"
    604     fi
    605     return 0
    606 }
    607 
    608 ## Usage: _processSingleInterface <interface-directory>
    609 function _processSingleInterface
    610 {
    611     local iface=$1
    612 
    613     local ip
    614     local dev
    615     local prefix
    616     local mask
    617     local bcast
    618     local name
    619     local scope
    620     local mac
    621     local extip
    622     local up="up"
    623     local peer
    624 
    625     _getInterfaceValue ip     '' "$iface"
    626     _getInterfaceValue extip  '' "$iface" "$iface/.."
    627     _getInterfaceValue dev    '' "$iface" "$iface/.."
    628     _getInterfaceValue prefix '' "$iface" "$iface/.."
    629     _getInterfaceValue mask   '' "$iface" "$iface/.."
    630     _getInterfaceValue bcast  '' "$iface" "$iface/.."
    631     _getInterfaceValue name   '' "$iface"
    632     _getInterfaceValue scope  '' "$iface" "$iface/.."
    633     _getInterfaceValue mac    '' "$iface"
    634     _getInterfaceValue peer   '' "$iface"
    635 
    636     test -n "$ip" || { echo $"Can not read ip for '$iface'"  >&2; return 1; }
    637     test -n "$dev" -o -e "$iface"/nodev || {
    638 	echo $"No device specified for '$iface'" >&2
    639 	return 1;
    640     }
    641 
    642     test ! -e "$iface"/down || up=
    643 
    644     while true; do
    645 	_transformMask2Prefix prefix "$prefix" "$mask"
    646 	INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
    647 
    648 	test ! -e "$iface"/nodev   || break
    649 	## LEGACY ALERT
    650 	test ! -e "$iface"/only_ip || break
    651 
    652 	test -e "$iface/vlandev" \
    653 	     -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
    654 	     -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
    655 		   -a ! -e "$iface/novlandev" \
    656 		   -a ! -e "$iface/../novlandev" \) && {
    657 	    local vlan_info
    658 	    if vlan_info=$(_getVLANInfo "$dev"); then
    659 		test -d /proc/net/vlan || {
    660 		    echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers"  >&2
    661 		    return 1
    662 		}
    663 		_addInterfaceCmd $VCONFIGOP $vlan_info
    664 	    fi
    665 	}
    666 
    667 	if ! test -e "$iface"/indirect; then
    668 	    # XXX: IPv6 hack
    669 	    local use_bcast="broadcast ${bcast:-+}"
    670 	    echo "$ip" | $_GREP -q : && use_bcast=
    671 
    672 	    local tun_info
    673 	    if tun_info=$(_getTunInfo "$iface"); then
    674 		_addInterfaceCmd TUNCTL "$dev" $tun_info
    675 	    fi
    676 
    677 	    _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
    678 	    #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
    679 	    _addInterfaceCmd IP_LINK  "$dev" $up
    680 	elif ! test -n "$N_CONTEXT"; then
    681 	    echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
    682 	    return 1
    683 	else
    684 	    test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
    685 	    _addInterfaceCmd MODPROBE dummy "$dev"
    686 	    _addInterfaceCmd IP_LINK  dev dummy0 address "$mac"
    687 	    _addInterfaceCmd NAMEIF   "$dev" "$mac"
    688 	    _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" dev "$dev"
    689 	    test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
    690 	fi
    691 
    692 	break
    693     done
    694 }
    695 
    696 ## Usage: _generateInterfaceOptions <vserver-directory>
    697 function _generateInterfaceOptions
    698 {
    699     local iface
    700 
    701     # XXX: This is here instead of in _generateChbindOptions
    702     #      to avoid a circular dependency
    703     getFileValue N_CONTEXT "$1/ncontext" "$1/context"
    704     test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
    705 
    706     for iface in "$1/interfaces/"*; do
    707         test   -d "$iface"          || continue
    708         test ! -e "$iface"/disabled || continue
    709     
    710         _processSingleInterface "$iface"
    711     done
    712     _HAVE_INTERFACE_OPTIONS=1
    713 }
    714 
    715 function enableInterfaces
    716 {
    717     local i=0
    718     declare -a var
    719 
    720     lock "$__LOCKDIR"/vserver.interfaces
    721 
    722     while test $i -lt $INTERFACE_CMDS_IDX; do
    723 	eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
    724 	local type=${var[0]}
    725 	unset var[0]
    726 
    727 	set -- "${var[@]}"
    728 	case "$type" in
    729 	    IPTABLES)	;; ## TODO
    730 	    MODPROBE)
    731 		local mod=$1
    732 		local name=$2
    733 		shift 2
    734 		$_MODPROBE ${name:+-o "$name"} "$mod" "$@"
    735 		;;
    736 	    NAMEIF)		$_NAMEIF   "$@";;
    737 	    VCONFIG)		$_IP link  add link "$2" name "$1" type vlan id "$3";;
    738 	    VCONFIG_LEGACY)	$_VCONFIG  set_name_type "$4"      >/dev/null
    739 				$_VCONFIG  add           "$2" "$3" >/dev/null;;
    740 	    IP_ADDR)		$_IP addr  add   "$@";;
    741 	    IP_ADDR_FLUSH)	$_IP addr  flush "$@";;
    742 	    IP_LINK)		$_IP link  set   "$@";;
    743 	    IP_ROUTE)		$_IP route add   "$@";;
    744 	    TUNCTL)
    745 		local dev="$1"
    746 		shift
    747 		$_TUNCTL --persist "$@" "$dev"
    748 		;;
    749 	    *)			echo "Unknown interface-command type '$type'" >&2; false;;
    750 	esac
    751 
    752 	let ++i
    753     done
    754 
    755     unlock 1
    756 }
    757 
    758 function disableInterfaces
    759 {
    760     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
    761 
    762     local i=$INTERFACE_CMDS_IDX
    763     declare -a var
    764 
    765     lock "$__LOCKDIR"/vserver.interfaces
    766     
    767     while test $i -gt 0; do
    768 	let --i || :
    769 
    770 	eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
    771 	local type=${var[0]}
    772 	unset var[0]
    773 	
    774 	set -- "${var[@]}"
    775 	case "$type" in
    776 	    IPTABLES)		;; ## TODO
    777 	    MODPROBE)		$_RMMOD "${2:-$1}";;
    778 	    NAMEIF)		;;
    779 	    VCONFIG)		$_IP link  delete "$1" type vlan;;
    780 	    VCONFIG_LEGACY)	$_VCONFIG  rem "$2.$3" >/dev/null;;
    781 	    IP_ADDR)		$_IP addr  del "$@";;
    782 	    IP_ADDR_FLUSH)	;;
    783 	    IP_LINK)		;; ## Ignore the link-down command for now
    784 	    IP_ROUTE)		$_IP route del "$@";;
    785 	    TUNCTL)
    786 		local dev="$1"
    787 		shift
    788 		$_TUNCTL --~persist "$@" "$dev"
    789 		;;
    790 	    *)			echo "Unknown interface-command type '$type'" >&2; false;;
    791 	esac
    792     done
    793 
    794     unlock 1
    795 }
    796 
    797 function _generateTagOptions
    798 {
    799     local vdir="$1"
    800     local tag
    801 
    802     getFileValue tag "$vdir/tag" "$vdir/context"
    803     test -n "$tag" || return 0
    804 
    805     OPTS_VTAG_CREATE=( --tag "$tag" )
    806     OPTS_VTAG_ENTER=( --tag "$tag" )
    807 }
    808 
    809 function _generateMemctrlOptions
    810 {
    811     local vdir="$1"
    812     local badness
    813 
    814     getFileValue badness "$vdir/badness"
    815     test -n "$badness" || return 0
    816 
    817     OPTS_VMEMCTRL=( --badness "$badness" )
    818 }
    819 
    820 function _generateSpaceOptions
    821 {
    822     local vdir="$1"
    823     local d="$vdir"/spaces
    824     local shared
    825     local space
    826 
    827     for space in pid net; do
    828 	if test -e "$d"/$space; then
    829 	    getFileValue shared "$d"/$space || shared=""
    830 	    if test -z "$shared"; then
    831 		OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
    832 	    elif test "$shared" = "0"; then
    833 		: # Do nothing
    834 	    else
    835 		OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
    836 		VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
    837 	    fi
    838 	fi
    839     done
    840 
    841     local mask
    842     getFileValue mask "$d"/mask || \
    843       OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
    844 }
    845 
    846 ## Usage: prepareInit <vserver-directory>
    847 function prepareInit
    848 {
    849     pushd "$1/vdir" >/dev/null
    850     case "$INITSTYLE" in
    851 	sysv)
    852 	    local -a dirs=( $($_CHROOT_SH realpath /var/run /var/lock | $_SED 's!^/*!!' || :) )
    853 	    local dir
    854 	    for dir in "${dirs[@]}"; do
    855 		test ! -L "$dir" || continue
    856 		$_FIND "$dir/." ! -type d -print0 2>/dev/null | xargs -0r $_CHROOT_SH rm
    857 	    done
    858 	    ;;
    859 	plain)
    860 	    $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
    861 	    : | $_CHROOT_SH truncate fastboot  2>/dev/null || :
    862 	    ;;
    863 	minit)
    864 	    ;;
    865     esac
    866     "${INITCMD_PREPARE[@]}"
    867     popd >/dev/null
    868 }
    869 
    870 ## Usage: prepareInit <vserver-directory>
    871 function prepareStop
    872 {
    873     pushd "$1/vdir" >/dev/null
    874     case "$INITSTYLE" in
    875 	(sysv)
    876 	    export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
    877 	    ;;
    878     esac
    879     "${STOPCMD_PREPARE[@]}"
    880     popd >/dev/null
    881 }
    882 
    883 
    884 function generateOptions
    885 {
    886     _generateInterfaceOptions   "$1"
    887     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1" 
    888     _generateNiceCommand        "$1"
    889     _generateIONiceCommand	"$1"
    890     _generateInitOptions        "$1"
    891     _generateChcontextOptions   "$1"
    892     _generateScheduleOptions    "$1"
    893     _generatePersonalityOptions "$1"
    894     _generateTagOptions         "$1"
    895     _generateMemctrlOptions     "$1"
    896     _generateSpaceOptions       "$1"
    897     _generateCgroupOptions
    898 
    899     if test -n "$_IS_FAKEINIT"; then
    900 	CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
    901 	OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
    902     fi
    903 }
    904 
    905 function addtoCPUSET
    906 {
    907     local vdir=$1
    908     local cpuset
    909     local f="$vdir"/cpuset
    910     local i
    911     local configured=0
    912 
    913     test -d "$f" || return 0
    914     test -e "$f"/name || return 0
    915 
    916     read cpuset < "$f"/name
    917     test -e "$f"/nocreate || {
    918        test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
    919        for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
    920            if test -e "$f"/"$i"; then
    921                cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
    922                    configured=1
    923                    break
    924                }
    925            fi
    926        done
    927     }
    928 
    929     echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
    930     if [ "$configured" -ne 0 ]; then
    931        warning $"\
    932 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
    933        rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
    934        return 0
    935     fi
    936 }
    937 
    938 function removeCPUSET
    939 {
    940     local vdir=$1
    941     local cpuset
    942     local f="$vdir"/cpuset
    943 
    944     test -d "$f" || return 0
    945     test -e "$f"/name || return 0
    946 
    947     read cpuset < "$f"/name
    948     test -e "$f"/nocreate || {
    949        rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
    950     }
    951 }
    952 
    953 function _mountVserverInternal
    954 {
    955     local fstab="$1"
    956     local xflag=
    957     
    958     test -e "$fstab" || return 0
    959     shift
    960 
    961     pushd "$vdir" >/dev/null
    962     # check whether / is mounted readonly or whether there is special
    963     # magic regarding the mtab file; when etc/mtab can not be touched,
    964     # add the '-n' flag to mount
    965     test -w etc -o -w etc/mtab || xflag=-n
    966     if test -h etc/mtab; then
    967 	local l=$($_READLINK etc/mtab)
    968 	test "${l##/proc/}" = "$l" || xflag=-n
    969     fi
    970     "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
    971     popd >/dev/null
    972 }
    973 
    974 function mountRootFS
    975 {
    976     local cfgdir=$1
    977     local vdir=$1/vdir
    978     local fstab="$cfgdir"/fstab
    979     local xflag=
    980 
    981     test -e "$fstab" || return 0
    982     pushd "$vdir" >/dev/null
    983     # check whether / is mounted readonly or whether there is special
    984     # magic regarding the mtab file; when etc/mtab can not be touched,
    985     # add the '-n' flag to mount
    986     test -w etc -o -w etc/mtab || xflag=-n
    987     $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
    988     popd >/dev/null
    989 }
    990 
    991 function mountVserver
    992 {
    993     local cfgdir=$1
    994     local vdir=$1/vdir
    995     local mtab_src
    996     local extra_opt=
    997     local real_vdir
    998 
    999     test -e "$cfgdir"/fstab -o \
   1000          -e "$cfgdir"/fstab.local -o \
   1001 	 -e "$cfgdir"/fstab.remote || return 0
   1002 
   1003     findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
   1004     
   1005     pushd "$vdir" >/dev/null
   1006     $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
   1007     popd >/dev/null
   1008 
   1009     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
   1010 
   1011     _mountVserverInternal "$cfgdir"/fstab
   1012     _mountVserverInternal "$cfgdir"/fstab.local
   1013     _mountVserverInternal "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}"
   1014 
   1015     isNamespaceCleanup "$cfgdir" && \
   1016         _namespaceCleanup "$cfgdir"
   1017 
   1018     real_vdir=$(getPhysicalDir "$vdir")
   1019     isAvoidNamespace "$cfgdir" || \
   1020 	$_SECURE_MOUNT --rbind -n -o dev "$vdir" "$real_vdir"
   1021     ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
   1022 	$_SECURE_MOUNT -n -o shared,rec "$real_vdir" "$real_vdir"
   1023 }
   1024 
   1025 function _umountVserverInternal
   1026 {
   1027     local fstab="$1"
   1028     test -e "$fstab" || return 0
   1029     shift
   1030 
   1031     $_TAC "$fstab" | {
   1032 	is_ok=1
   1033 	while read src dst tmp; do
   1034 	    test -n "$tmp" || continue
   1035 	    case x"$src" in
   1036 		(x\#*)	continue;;
   1037 	    esac
   1038 
   1039 	
   1040 	    "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
   1041 	done
   1042 	test -n "$is_ok"
   1043     }
   1044 }
   1045 
   1046 function umountVserver
   1047 {
   1048     local cfgdir=$1
   1049     local vdir=$1/vdir
   1050     local is_ok=1
   1051 
   1052     isAvoidNamespace "$cfgdir"    || return 0
   1053     test -e "$cfgdir"/fstab -o \
   1054          -e "$cfgdir"/fstab.local -o \
   1055          -e "$cfgdir"/fstab.remote || return 0
   1056     test -n "$_HAVE_CHBIND_OPTIONS"  || _generateChbindOptions "$cfgdir"
   1057     
   1058     pushd "$vdir/" >/dev/null || return 1
   1059 	_umountVserverInternal  "$cfgdir"/fstab.remote "${CHBIND_CMD[@]}" || is_ok=
   1060 	_umountVserverInternal  "$cfgdir"/fstab.local                     || is_ok=
   1061 	_umountVserverInternal  "$cfgdir"/fstab                           || is_ok=
   1062     popd >/dev/null           || return 1
   1063 
   1064     test -n "$is_ok"
   1065 }
   1066 
   1067 function fsckAllFS
   1068 {
   1069     local cfgdir=$1
   1070     local fstab="$cfgdir"/fstab
   1071     local FSTAB_FILE
   1072     local fsck_exitcode
   1073 
   1074     test -e "$fstab" || return 0
   1075 
   1076     export FSTAB_FILE="$fstab"
   1077     $_FSCK -s -n -A -T
   1078     fsck_exitcode=$?
   1079     test "$fsck_exitcode" -eq 0 -o \
   1080          "$fsck_exitcode" -eq 1 || return $fsck_exitcode
   1081 }
   1082 
   1083 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
   1084 function initSync
   1085 {
   1086     local _is_meth=sync
   1087     test -n "$_NEED_VSHELPER_SYNC" && \
   1088 	! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
   1089 
   1090     vshelper.initSync "$1" "$3" "$_is_meth"
   1091 }
   1092 
   1093 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
   1094 function initWait
   1095 {
   1096     if $_VSERVER_INFO - FEATURE vwait; then
   1097 	local _is_tmpdir
   1098 	_is_tmpdir=$($_MKTEMPDIR vwaitstat.XXXXXX)
   1099 
   1100 	(
   1101 	    $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
   1102 		--status-fd 3 "$2" \
   1103 		>>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
   1104 	    rc=$?
   1105 
   1106 	    if test "$rc" -ne 0 -a "$rc" -ne 1; then
   1107 		$_VPS axf | $_EGREP -e "^[ \t]*[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
   1108 		killContext "$S_CONTEXT" 9
   1109 	    fi
   1110 
   1111 	    exit $rc
   1112 	) 4>$_is_tmpdir/procs &
   1113 	    
   1114 	echo "$!" >$_is_tmpdir/pid
   1115 	eval "$3"=$_is_tmpdir
   1116     fi </dev/null
   1117 }
   1118 
   1119 
   1120 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
   1121 function _waitForVWait
   1122 {
   1123     wait "$3" || :
   1124 
   1125     declare -a status
   1126     declare -r procs=$(cat $4)
   1127 
   1128     getFileArray status "$2"
   1129     set -- ${status[0]}
   1130 
   1131     case "$1" in
   1132 	(ERROR)		warning $"\
   1133 'vwait' exited with error '$2' which indicates that vserver could not
   1134 be stopped properly"
   1135 			;;
   1136 	(FINISHED)	;;
   1137 	(KILLED)	warning $"\
   1138 A timeout occured while waiting for the vserver to finish and it was
   1139 killed by sending a SIGKILL signal. Please investigate the reasons
   1140 and/or increase the timeout in apps/vshelper/sync-timeout."
   1141 			;;
   1142 
   1143 	(TIMEOUT)	warning $"\
   1144 A timeout occured while waiting for the vserver to finish and it will
   1145 be killed by sending a SIGKILL signal. The following process list
   1146 might be useful for finding out the reason of this behavior:
   1147 
   1148 ----------------------------------------------------------------------
   1149 ${procs:+$procs
   1150 }----------------------------------------------------------------------"
   1151 			;;
   1152 
   1153 	(\?\?\?|*)	warning $"\
   1154 internal error: 'vwait' exited with an unexpected status '$1'; I will
   1155 try to continue but be prepared for unexpected events."
   1156 		    ;;
   1157     esac
   1158 
   1159     return 0
   1160 }
   1161 
   1162 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
   1163 function waitForSync
   1164 {
   1165     local cfgdir=$1
   1166     local fifo=$2
   1167     local vwait_statdir=$3
   1168     local vwait_pid=$4
   1169 
   1170     if test -d "$vwait_statdir"; then
   1171 	_waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
   1172     elif test -n "$_NEED_VSHELPER_SYNC"; then
   1173 	$_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
   1174 	    warning $"\
   1175 A timeout or other error occured while waiting for the synchronization
   1176 signal from vserver '$VSERVER_NAME'.
   1177 The vserver will be killed nevertheless..."
   1178     elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
   1179 	"${INITCMD_STOP_SYNC[@]}" || \
   1180 	    warning $"\
   1181 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
   1182 will be killed nevertheless..."
   1183     fi
   1184 
   1185     test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
   1186 	sleep 1
   1187 }
   1188 
   1189 function _sourceWrap
   1190 {
   1191     local vdir name flavor start i already_handled base
   1192     . "$@"
   1193 }
   1194 
   1195 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
   1196 function execScriptlets
   1197 {
   1198     declare -r vdir=$1
   1199     declare -r name=$2
   1200     declare -r flavor=$3
   1201     local base i
   1202 
   1203     for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
   1204 	local	DONT_SKIP_DEFAULTS=
   1205 	local	already_handled=
   1206 	
   1207 	for i in "$base/$flavor" "$base/$flavor.d"/*; do
   1208 	    isRegularFile "$i" || continue
   1209 	    test  -r "$i"      || continue
   1210 
   1211 	    already_handled=1
   1212 	    local start=
   1213 	    test -x "$i" || start=_sourceWrap
   1214 	    $start "$i" "$flavor" "$name"
   1215 	done
   1216 
   1217 	test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
   1218     done
   1219 }
   1220 
   1221 
   1222 function sanityCheck
   1223 {
   1224     declare -r cfgdir=$1
   1225 
   1226     ! test -e "$cfgdir"/fstab.local ||
   1227 	warning $"\
   1228 WARNING: 'fstab' will *not* be executed in the network context of the
   1229   vserver anymore. Therefore, 'fstab.local' has the same functionality
   1230   and is obsoleted. When you need the old behaviour, put the mounts
   1231   into 'fstab.remote'"
   1232 
   1233     ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
   1234 	warning $"\
   1235 WARNING: The hostname is now configured in 'uts/nodename' but not in
   1236   'hostname'."
   1237 
   1238     ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
   1239 	warning $"\
   1240 WARNING: The domainname is now configured in 'uts/domainname' but not
   1241   in 'domainname'." >&2
   1242 
   1243   
   1244     local i
   1245     for i in "$cfgdir"/interfaces/*/only_ip; do
   1246 	if test -e "$i"; then
   1247 	    local iface
   1248 	    iface=${i##$cfgdir/interfaces/}
   1249 	    iface=${iface%%/only_ip}
   1250 	    warning $"\
   1251 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
   1252   'nodev' instead of"
   1253 	fi
   1254     done
   1255 
   1256     test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
   1257 	warning $"\
   1258 WARNING: There is no cachedirectory configured for this vserver;
   1259   please create '$cfgdir/cache' e.g. by executing
   1260 
   1261   ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
   1262 "
   1263 
   1264     $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
   1265 
   1266     vshelper.doSanityCheck
   1267 
   1268     $_VSERVER_INFO - VERIFYCAP ||
   1269 	panic $"capabilities are not enabled in kernel-setup"
   1270 
   1271     $_VSERVER_INFO - VERIFYPROC ||
   1272 	panic $"\
   1273 /proc/uptime can not be accessed. Usually, this is caused by
   1274 procfs-security. Please read the FAQ for more details
   1275 http://linux-vserver.org/Proc-Security"
   1276 
   1277     test -e "$cfgdir"/context || {
   1278 	TYPE=$( $_VSERVER_INFO 49152 XIDTYPE )
   1279 	test "$TYPE" != "static" || panic $"\
   1280 The kernel does not have dynamic contexts enabled. Please configure
   1281 a static one by executing
   1282 
   1283   echo [number between 2 and 49151] > $cfgdir/context"
   1284     }
   1285 }
   1286 
   1287 
   1288 function _setSingleDiskLimit
   1289 {
   1290     local vdir=$1
   1291     local dlimit=$2
   1292     local space_used=
   1293     local space_total=
   1294     local inodes_used=
   1295     local inodes_total=
   1296     local reserved=
   1297     local directory=
   1298     local ctx=
   1299 
   1300     getFileValue ctx          "$vdir/context"
   1301     getFileValue directory    "$dlimit/directory"    || return 0
   1302     getFileValue space_total  "$dlimit/space_total"  || return 0
   1303     getFileValue inodes_total "$dlimit/inodes_total" || return 0
   1304     getFileValue reserved     "$dlimit/reserved"     || return 0
   1305 
   1306     local cachename=$ctx$directory
   1307     cachename=dlimits/${cachename//\//_}
   1308 
   1309     test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
   1310     # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
   1311     $_RM -f "$vdir/cache/$cachename"
   1312 
   1313     if test -z "$inodes_used" -o -z "$space_used"; then
   1314 	local tmpvdu
   1315 	tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
   1316 	inodes_used=${tmpvdu##* }
   1317 	space_used=${tmpvdu%% *}
   1318     fi
   1319 
   1320     $_VDLIMIT --xid $ctx \
   1321 	--set space_used=$space_used \
   1322 	--set space_total=$space_total \
   1323 	--set inodes_used=$inodes_used \
   1324 	--set inodes_total=$inodes_total \
   1325 	--set reserved=$reserved \
   1326 	"$directory"
   1327 }
   1328 
   1329 
   1330 function setDiskLimits
   1331 {
   1332     local vdir=$1
   1333     local dlimit
   1334 
   1335     # Disk Limits without a static context are useless
   1336     test -e "$vdir"/context || return 0
   1337 
   1338     for dlimit in "$vdir/dlimits/"*; do
   1339 	test   -d "$dlimit"          || continue
   1340 	test ! -e "$dlimit/disabled" || continue
   1341 
   1342 	_setSingleDiskLimit "$vdir" "$dlimit"
   1343     done
   1344 }
   1345 
   1346 
   1347 function _saveSingleDiskLimit
   1348 {
   1349     local vdir=$1
   1350     local dlimit=$2
   1351     local ctx=
   1352     local directory=
   1353 
   1354     getFileValue ctx       "$vdir/context"
   1355     getFileValue directory "$dlimit/directory" || return 0
   1356 
   1357     local cachename=$ctx$directory
   1358     cachename=${cachename//\//_}
   1359 
   1360     # Things are getting ugly here... LFS says that /var/cache (where
   1361     # cachename is usually pointing to) can vanish and applications
   1362     # have to deal with it. So, we have to interprete the $vdir/cache
   1363     # symlink and have to create the needed directories manually.
   1364     if   test -d "$vdir/cache"; then
   1365 	:	# ok, exists already
   1366     elif test -L "$vdir/cache"; then
   1367 	# it's a dangling symlink
   1368 	local link
   1369 	link=$($_READLINK "$vdir/cache")
   1370 	( cd $vdir && $_MKDIR -p "$link" )
   1371     else
   1372 	return 0
   1373     fi
   1374 
   1375     test -d "$vdir/cache"
   1376     $_MKDIR -p "$vdir"/cache/dlimits
   1377 
   1378     $_VDLIMIT --xid $ctx "$directory" | \
   1379 	$_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
   1380 
   1381     $_VDLIMIT --xid $ctx --remove "$directory"
   1382 }
   1383 
   1384 
   1385 function saveDiskLimits
   1386 {
   1387     local vdir=$1
   1388     local dlimit
   1389 
   1390     test -e "$vdir"/context || return 0
   1391 
   1392     for dlimit in "$vdir/dlimits/"*; do
   1393 	test   -d "$dlimit"          || continue
   1394 	test ! -e "$dlimit/disabled" || continue
   1395 
   1396 	_saveSingleDiskLimit "$vdir" "$dlimit"
   1397     done
   1398 }
   1399 
   1400 function _namespaceCleanup
   1401 {
   1402     local vdir="$1"
   1403     local root=$($_VSERVER_INFO "$1" VDIR 1)
   1404     local -a list
   1405     local -a skip
   1406     local i
   1407     local j
   1408 
   1409     getFileArray skip "$vdir"/namespace-cleanup-skip \
   1410 	"$__CONFDIR"/.defaults/namespace-cleanup-skip || :
   1411 
   1412     # these are things that have to be accessible post-cleanup
   1413     for i in "$root" "$__SBINDIR" "$__PKGLIBDIR" "$vdir" \
   1414 	"$__PKGSTATEDIR" "$__LOCKDIR" "$__PKGDATADIR" "$__PKGLIBEXECDIR" \
   1415 	/usr/local /tmp "${skip[@]}"; do
   1416 	local real=`getPhysicalDir "$i"`
   1417 	test "$i" != "$real" || real=
   1418 	for j in "$i" "$real"; do
   1419 	    while test -n "$j"; do
   1420 		list=( "${list[@]}" "$j" )
   1421 		j="${j%/*}"
   1422 	    done
   1423 	done
   1424     done
   1425 
   1426     # keep cgroup mount points
   1427     list=( "${list[@]}" "${CGROUP_MNT}" )
   1428     if test -n "$CGROUP_MNT_PER_SS"; then
   1429         for ss in "${CGROUP_SUBSYS[@]}"; do
   1430             list=( "${list[@]}" "${CGROUP_MNT}/${ss}" )
   1431         done
   1432     fi
   1433 
   1434     local -a list_umount
   1435     while read -r dev path opts; do
   1436 	test -n "$path" || continue
   1437 	path_dir="${path}/"
   1438 	for i in "$root" /dev /proc /sys; do
   1439 	    test "${path_dir#${i}/}" != "${path_dir}" && continue 2
   1440 	done
   1441 	for i in "${list[@]}" /; do
   1442 	    test "$path" = "$i" && continue 2
   1443 	done
   1444 	# unmount them in reverse order so mounts further down the tree get unmounted first
   1445 	list_umount=( "$path" "${list_umount[@]}" )
   1446     done < /proc/mounts
   1447     # separate loop to avoid races while reading /proc/mounts
   1448     for i in "${list_umount[@]}"; do
   1449 	$_UMOUNT -l -n -i "$i"
   1450     done
   1451 }
   1452 
   1453 function handleDeviceMap
   1454 {
   1455     local op="$1"
   1456     local xid="$2"
   1457     local dir="$3"
   1458     local flags device target
   1459 
   1460     test -d "$dir" || return 0
   1461     test -n "$xid" || return 0
   1462 
   1463     for i in "$dir"/*; do
   1464 	test -d "$i" || continue
   1465 
   1466 	local -a vdevmap_opts=()
   1467 	test -e "$i/create" && vdevmap_opts=( "${vdevmap_opts[@]}" --create )
   1468 	test -e "$i/open"   && vdevmap_opts=( "${vdevmap_opts[@]}" --open )
   1469 	test -e "$i/remap"  && vdevmap_opts=( "${vdevmap_opts[@]}" --remap )
   1470 
   1471 	getFileValue flags "$i/flags" || :
   1472 	getFileValue device "$i/device" || :
   1473 	getFileValue target "$i/target" || :
   1474 	vdevmap_opts=(  "${vdevmap_opts[@]}" ${flags:+--flags "$flags"} \
   1475 			${device:+--device "$device"} ${target:+--target "$target"} )
   1476 
   1477 	$_VDEVMAP --xid "$xid" "$op" "${vdevmap_opts[@]}" || return $?
   1478     done
   1479 }
   1480 
   1481 function hasCgroup
   1482 {
   1483     $_GREP -q "cgroup" /proc/filesystems
   1484 }
   1485 
   1486 function _generateCgroupOptions
   1487 {
   1488     local file
   1489 
   1490     hasCgroup || return 0
   1491 
   1492     findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
   1493     if test -n "$file"; then
   1494 	_readFileToArray "$file" CGROUP_SUBSYS ""
   1495     else
   1496 	CGROUP_SUBSYS=( $($_AWK '/^#/ { next; } $1 == "ns" { next; } $4 != "0" { print $1; }' /proc/cgroups) )
   1497     fi
   1498     findFile file "$__CONFDIR/.defaults/cgroup/mnt" ""
   1499     if test -n "$file"; then
   1500 	read CGROUP_MNT < "$file"
   1501     elif test -d /sys/fs/cgroup -a -d /sys/fs/cgroup/"${CGROUP_SUBSYS[0]}"; then
   1502 	CGROUP_MNT=/sys/fs/cgroup
   1503 	CGROUP_MNT_PER_SS=1
   1504     fi
   1505     findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
   1506     if test -n "$file"; then
   1507 	_readFileToArray "$file" CGROUP_INHERIT ""
   1508     fi
   1509     findFile file "$__CONFDIR/.defaults/cgroup/base" ""
   1510     if test -n "$file"; then
   1511 	read CGROUP_BASE < "$file"
   1512 	test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
   1513 	    CGROUP_BASE="${CGROUP_BASE}/"
   1514     fi
   1515     findFile file "$__CONFDIR/.defaults/cgroup/per-ss" ""
   1516     if test -n "$file"; then
   1517 	CGROUP_MNT_PER_SS=1
   1518     fi
   1519 
   1520     return 0
   1521 }
   1522 
   1523 function useCgroup
   1524 {
   1525     hasCgroup || return 1
   1526     if test -n "$CGROUP_MNT_PER_SS"; then
   1527 	local existing=0
   1528 	local ss
   1529 	for ss in "${CGROUP_SUBSYS[@]}"; do
   1530 	    if test -e "$CGROUP_MNT/$ss/tasks"; then
   1531 		let existing=${existing}+1
   1532 	    fi
   1533 	done
   1534 	test "$existing" -gt 0 || return 1
   1535     else
   1536 	test -e "$CGROUP_MNT/tasks" || return 1
   1537     fi
   1538     local memcg=""
   1539     if $_VSERVER_INFO - FEATURE memcg; then
   1540 	memcg=1
   1541     fi
   1542     test -d "$1/cgroup" -o \
   1543 	\( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
   1544 	   ! -e "$1/nocgroup" \)
   1545 }
   1546 
   1547 function _handleCgroup
   1548 {
   1549     local action="$1"
   1550     local vdir="$2"
   1551     local dir
   1552     local name
   1553     local i
   1554     local j
   1555     local parent
   1556     local -a mnts
   1557     local ss
   1558 
   1559     useCgroup "$vdir" || return 0
   1560 
   1561     findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
   1562 
   1563     if test -n "$dir" -a -r "$dir"/name; then
   1564 	read name < "$dir"/name
   1565     else
   1566 	name="$VSERVER_NAME"
   1567     fi
   1568 
   1569     if test -n "$CGROUP_MNT_PER_SS"; then
   1570 	mnts=()
   1571 	for ss in "${CGROUP_SUBSYS[@]}"; do
   1572 	    mnts=( "${mnts[@]}" "$CGROUP_MNT/$ss" )
   1573 	done
   1574     else
   1575 	mnts=( "$CGROUP_MNT" )
   1576     fi
   1577     for mnt in "${mnts[@]}"; do
   1578 	test -d "$mnt" || continue
   1579 	if test "$action" = "attach"; then
   1580 	    if test -n "$CGROUP_BASE"; then
   1581 		local -a dirs=()
   1582 		i="$mnt/$CGROUP_BASE"
   1583 		while test "$mnt" != "$i"; do
   1584 		    dirs=( "$i" "${dirs[@]}" )
   1585 		    i="${i%/*}"
   1586 		done
   1587 		for i in "${dirs[@]}"; do
   1588 		    if mkdir "$i" 2>/dev/null; then
   1589 			parent="${i%/*}"
   1590 			for j in "${CGROUP_INHERIT[@]}"; do
   1591 			    test -f "$parent/$j" || continue
   1592 			    cat "$parent/$j" > "$i/$j"
   1593 			done
   1594 		    fi
   1595 		done
   1596 	    fi
   1597 	    if mkdir "$mnt/$CGROUP_BASE$name" 2>/dev/null; then
   1598 		parent="$mnt/$CGROUP_BASE$name"
   1599 		parent="${parent%/*}"
   1600 		for i in "${CGROUP_INHERIT[@]}"; do
   1601 		    test -f "$parent/$i" || continue
   1602 		    cat "$parent/$i" > "$mnt/$CGROUP_BASE$name/$i"
   1603 		done
   1604 
   1605 		if test -n "$dir"; then
   1606 		    shopt -s nullglob
   1607 		    for i in "$dir"/*; do
   1608 			f="${i##*/}"
   1609 			test "$f" != mnt -a "$f" != subsys -a \
   1610 			    "$f" != inherit -a "$f" != name -a "$f" != base -a \
   1611 			    "$f" != per-ss \
   1612 			    || continue
   1613 			if test -n "$CGROUP_MNT_PER_SS"; then
   1614 			    ss="${f%%.*}"
   1615 			    test "$ss" = "${mnt##*/}" || continue
   1616 			fi
   1617 			cat "$i" > "$mnt/$CGROUP_BASE$name/$f"
   1618 		    done
   1619 		fi
   1620 	    fi
   1621 	    echo "$$" > "$mnt/$CGROUP_BASE$name/tasks"
   1622 	elif test "$action" = "destroy"; then
   1623 	    rmdir "$mnt/$CGROUP_BASE$name" 2>/dev/null || :
   1624 	fi
   1625     done
   1626 
   1627     return 0
   1628 }
   1629 
   1630 function attachToCgroup
   1631 {
   1632     _handleCgroup attach "$@"
   1633 }
   1634 
   1635 function destroyCgroup
   1636 {
   1637     _handleCgroup destroy "$@"
   1638 }
   1639 
   1640 function _handleNetNS
   1641 {
   1642     local action="$1"
   1643     local vdir="$2"
   1644     local dir
   1645     local name
   1646 
   1647     findDir dir "$vdir/netns" "$__CONFDIR/.defaults/netns" ""
   1648     test -n "$dir" -a ! -e "$vdir"/nonetns  || return 0
   1649 
   1650     if test -r "$dir"/name; then
   1651 	read name < "$dir"/name
   1652     else
   1653 	name="$VSERVER_NAME"
   1654     fi
   1655 
   1656     NETNS_CMD=( "$_IP" netns exec "$name" )
   1657     if test ! -e "$dir"/shared; then
   1658 	if test "$action" = "add"; then
   1659 	    "$_IP" netns add "$name"
   1660 	    shopt -s nullglob
   1661 	    counter=0
   1662 	    for i in "$dir"/interfaces/*; do
   1663 		local host
   1664 		local guest
   1665 		local type
   1666 		read host < "$i"/host
   1667 		if test -r "$i"/guest; then
   1668 		    read guest < "$i"/guest
   1669 		else
   1670 		    guest="geth$counter"
   1671 		    counter=$(( $counter + 1 ))
   1672 		fi
   1673 		if test -r "$i"/type; then
   1674 		    read type < "$i"/type
   1675 		else
   1676 		    type="veth"
   1677 		fi
   1678 		"$_IP" link add name "$host" type "$type" peer name "$guest"
   1679 		"$_IP" link set "$guest" netns "$name"
   1680 	    done
   1681 	elif test "$action" = "del"; then
   1682 	    shopt -s nullglob
   1683 	    for i in "$dir"/interfaces/*; do
   1684 		local host
   1685 		read host < "$i"/host
   1686 		"$_IP" link del "$host"
   1687 	    done
   1688 	    "$_IP" netns del "$name"
   1689 	fi
   1690     fi
   1691 }
   1692 
   1693 function setupNetNS
   1694 {
   1695     _handleNetNS add "$1"
   1696 }
   1697 
   1698 function enterNetNS
   1699 {
   1700     _handleNetNS exec "$1"
   1701 }
   1702 
   1703 function destroyNetNS
   1704 {
   1705     _handleNetNS del "$1"
   1706 }