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