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