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