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