root/trunk/scripts/vserver.functions

Revision 2819, 37.3 kB (checked in by dhozac, 1 month ago)

Use pivot_root on kernels supporting two namespaces per context.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 # $Id$  --*- sh -*--
2
3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License.
8
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 ## Expected env:
19 #  $VSERVER_DIR   ... path to vserver-cfg dir
20 #  $VSERVER_NAME  ... name of vserver
21
22 declare -a NICE_CMD=()
23 declare -a IONICE_CMD=()
24 declare -a CHBIND_CMD=()
25 declare -a CAP_OPTS=()
26 declare -a CHCONTEXT_INIT_OPTS=()
27 declare -a CHCONTEXT_FLAG_OPTS=()
28 declare -a CHCONTEXT_OPTS=()
29 declare -a CAPCHROOT_OPTS=()
30 declare -a INTERFACES=()
31
32 declare -a INITCMD_RESCUE=( /bin/sleep 900 )
33 declare -a INITCMD_START=()
34 declare -a INITCMD_START_SYNC=()
35 declare -a INITCMD_STOP=()
36 declare -a INITCMD_STOP_SYNC=()
37 declare -a INITCMD_PREPARE=()
38 declare -a INITKILL_SEQ=()
39 declare -a ENTER_SHELL=()
40
41 declare -a OPTS_VCONTEXT_CREATE=()
42 declare -a OPTS_VCONTEXT_MIGRATE=()
43 declare -a OPTS_VCONTEXT_ENTER=()
44 OPT_VCONTEXT_CHROOT=--chroot
45 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
46 declare -a OPTS_VSCHED=()
47 declare -a OPTS_ENV=()
48 declare -a OPTS_VTAG_CREATE=()
49 declare -a OPTS_VTAG_ENTER=()
50 declare -a OPTS_VMEMCTRL=()
51 declare -a OPTS_VSPACE=( --default )
52
53 declare -a STOPCMD_PREPARE=()
54
55 declare -a VSERVER_EXTRA_CMDS=()
56
57 INIT_RESCUE=
58 VSHELPER_SYNC_TIMEOUT=30
59 USE_VNAMESPACE=
60 INTERFACE_CMDS_IDX=0
61 RUNLEVEL_START=
62 RUNLEVEL_STOP=
63 _HAVE_INTERFACE_OPTIONS=
64 _HAVE_CHBIND_OPTIONS=
65 _NEED_VSHELPER_SYNC=
66 _IS_FAKEINIT=
67
68 INITSTYLE=sysv
69
70 S_CONTEXT=
71 N_CONTEXT=
72
73 SILENT_OPT=
74
75 CGROUP_MNT=/dev/cgroup
76 CGROUP_SUBSYS=all
77 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
78
79 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
80
81 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
82     SILENT_OPT=
83 else
84     SILENT_OPT='--silent'
85 fi
86
87 function _readFileToArray
88 {
89     local _rfta_f="$1"
90     local _rfta_a="$2"
91     local _rfta_p="$3"
92     local _rfta_v
93
94     test -e "$_rfta_f" || return 0
95     while read _rfta_v; do
96         case x"$_rfta_v" in
97             (x|x\#*)    ;;
98             (*)         eval "$_rfta_a=( \"\${$_rfta_a[@]}\" $_rfta_p \"$_rfta_v\" )";;
99         esac
100     done <"$_rfta_f"
101 }
102
103 function _generateChbindOptions
104 {
105     local vdir="$1"
106     local i
107     local bcast=
108     local lback=
109     local nid=
110
111     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
112
113     local f="$vdir"/interfaces/bcast
114     getFileValue bcast "$f"
115     f="$vdir"/interfaces/lback
116     getFileValue lback "$f"
117
118     CHBIND_CMD=( $_CHBIND $SILENT_OPT --secure ${N_CONTEXT:+--nid "$N_CONTEXT"}
119                  ${bcast:+--bcast "$bcast"} ${lback:+--lback "$lback"}
120                 )
121
122     for i in "${INTERFACES[@]}"; do
123         CHBIND_CMD=( "${CHBIND_CMD[@]}" --ip "$i" )
124     done
125
126     _readFileToArray "$vdir"/nflags        CHBIND_CMD --flag
127     _readFileToArray "$vdir"/ncapabilities CHBIND_CMD --ncap
128
129     _HAVE_CHBIND_OPTIONS=1
130 }
131
132 function _generateNiceCommand
133 {
134     local vdir=$1
135     local nice=0
136     local current_nice=`$_NICE`
137
138     test -r "$vdir/nice" && read nice <"$vdir"/nice
139
140     let nice=$nice-$current_nice || :
141     NICE_CMD=( $_NICE -n $nice )
142 }
143
144 function _generateIONiceCommand
145 {
146     local vdir=$1
147     local ionice_class=2
148     local ionice_priority=0
149
150     test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
151     test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
152
153     IONICE_CMD=( $_IONICE -c$ionice_class -n$ionice_priority )
154 }
155
156 function _generatePersonalityOptions
157 {
158     local vdir="$1"
159     local f="$vdir"/personality
160     local type flags
161
162     test -s "$f" || return 0
163
164     {
165         local delim tmp
166
167         read type
168         while read tmp; do
169             case x$tmp in
170                 (x\#*|x)        ;;
171                 (*)             flags=$flags$delim$tmp
172                                 delim=,
173                                 ;;
174             esac
175         done
176     } <"$f"
177
178     OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
179                           --personality-type "$type"
180                           ${flags:+--personality-flags "$flags"} )
181 }
182
183 function _generateCCapabilityOptions
184 {
185     local vdir=$1
186
187     _readFileToArray "$vdir"/ccapabilities OPTS_VATTRIBUTE --ccap
188 }
189
190 function _generateBCapabilityOptions
191 {
192     local vdir=$1
193
194     _readFileToArray "$vdir"/bcapabilities OPTS_VATTRIBUTE --bcap
195 }
196
197 function _generateCapabilityOptions
198 {
199     local vdir=$1
200     local cap
201
202     _generateBCapabilityOptions "$vdir"
203     _generateCCapabilityOptions "$vdir"
204    
205     test -e "$vdir"/capabilities || return 0
206
207     CAP_OPTS=()
208     CAPCHROOT_OPTS=()
209
210     while read cap; do
211         case x"$cap" in
212             (x|x\#*)    ;;
213             (!CAP_SYSCHROOT)
214                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
215                 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
216                 ;;
217             (*)
218                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
219                 ;;
220         esac
221     done <"$vdir"/capabilities
222 }
223
224 function getEnterShell
225 {
226     local vdir=$1
227     local shell_file
228
229     ENTER_SHELL=()
230
231     getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
232    
233     test -n "$ENTER_SHELL" || {
234         local i
235         for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
236             set -- $i
237             test -x "$vdir/vdir/$1" || continue
238             ENTER_SHELL=( "$@" )
239             break
240         done
241     }
242 }
243
244 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
245 function sendKillSequence
246 {
247     local ctx=$1
248     local wait=
249     shift
250
251     while isCtxRunning "$ctx"; do
252         test -z "$wait" || sleep "$wait"
253
254         killContext "$ctx" "$1"
255         test -n "$2" || break
256         wait="$2"
257         shift 2
258     done
259 }
260
261 function _generateInitOptions
262 {
263     local vdir=$1
264     local cfgdir=$vdir/apps/init
265     local i f
266
267     INITCMD_START=()
268     INITCMD_STOP=()
269     INITCMD_START_SYNC=()
270     INITCMD_STOP_SYNC=()
271     INITCMD_PREPARE=()
272     STOPCMD_PREPARE=()
273
274     INITKILL_SEQ=( 15 5 9 )
275     CHCONTEXT_INIT_OPTS=()
276
277
278     test x"$INITSTYLE" = xrescue || \
279       getFileValue INITSTYLE    "$cfgdir"/style
280     getFileValue RUNLEVEL_START "$cfgdir"/runlevel
281     getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
282     getFileValue RUNLEVEL_STOP  "$cfgdir"/runlevel.stop
283     getFileArray INITKILL_SEQ   "$cfgdir"/killseq || :
284
285     findFile _gio_env           "$cfgdir"/environment \
286         "$__CONFDIR"/.defaults/apps/init/environment \
287         "$__PKGLIBDEFAULTDIR"/environment
288     getFileArray OPTS_ENV       "$_gio_env" || :
289
290     case x"$INITSTYLE" in
291         (xrescue)
292             INITCMD_START=( "${INITCMD_RESCUE[@]}" )
293             INITCMD_STOP=( /sbin/killall5 )
294             ;;
295            
296         (xsysv)
297             test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
298             test -n "$RUNLEVEL_STOP"  || RUNLEVEL_STOP=6
299
300             for i in /etc/init.d/rc /etc/rc.d/rc; do
301                 test -x "$vdir/vdir/$i" || continue
302                 INITCMD_START=( "$i" "$RUNLEVEL_START" )
303                 INITCMD_STOP=(  "$i" "$RUNLEVEL_STOP"  )
304             done
305             INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
306             OPTS_ENV=( "${OPTS_ENV[@]}" PREVLEVEL=N RUNLEVEL="$RUNLEVEL_START" )
307             if test -n "$OPTION_DEBUG_SYSV"; then
308                 INITCMD_START=( /bin/bash -x "${INITCMD_START[@]}" )
309                 INITCMD_STOP=( /bin/bash -x "${INITCMD_STOP[@]}" )
310             fi
311             ;;
312            
313         (xplain)
314             INITCMD_START=( /sbin/init )
315             INITCMD_STOP=(  /sbin/init )
316             _IS_FAKEINIT=1
317             _NEED_VSHELPER_SYNC=1
318             test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
319             test -z "$RUNLEVEL_STOP"  || INITCMD_STOP=(  "${INITCMD_STOP[@]}"  "$RUNLEVEL_STOP"  )
320             ;;
321            
322         (xminit)
323             INITCMD_START=( /sbin/minit-start )
324             INITCMD_STOP=(  /sbin/minit-stop  )
325             _IS_FAKEINIT=1
326             INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
327             _NEED_VSHELPER_SYNC=1
328             test -z "$RUNLEVEL_START"         || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
329             test -z "$RUNLEVEL_STOP"          || INITCMD_STOP=(  "${INITCMD_STOP[@]}"  "$RUNLEVEL_STOP"  )
330             ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
331             ;;
332
333         (xgentoo)
334             test -n "$RUNLEVEL_START" || RUNLEVEL_START="default"
335             RC_PATH=/usr/sbin:/usr/bin:/sbin:/bin
336
337             if test -x "$vdir/vdir/lib/rcscripts/sh/init-vserver.sh"; then
338                 RC_WRAP=/lib/rcscripts/sh/init-vserver.sh
339             elif test -x "$vdir/vdir/lib/rc/sh/init-vserver.sh"; then
340                 RC_WRAP=/lib/rc/sh/init-vserver.sh
341             else
342                 panic "init-vserver.sh not found; aborting"
343             fi
344
345             INITCMD_START=( env TERM=$TERM $RC_WRAP "$RUNLEVEL_START" )
346             INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
347             INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
348             ;;
349
350         (xarch)
351             test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
352             INITCMD_START=( /etc/rc.multi )
353             INITCMD_STOP=( /etc/rc.shutdown )
354             INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
355             ;;
356
357         (x) ;;
358         (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
359     esac
360
361     if test x"$INITSTYLE" != xrescue; then
362         getFileArray INITCMD_START      "$cfgdir"/cmd.start      || :
363         getFileArray INITCMD_STOP       "$cfgdir"/cmd.stop       || :
364         getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
365         getFileArray INITCMD_STOP_SYNC  "$cfgdir"/cmd.stop-sync  || :
366         getFileArray INITCMD_PREPARE    "$cfgdir"/cmd.prepare    || :
367     fi
368    
369     test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
370         INITCMD_START_SYNC=()
371         INITCMD_STOP_SYNC=()
372         _NEED_VSHELPER_SYNC=
373     }
374
375     if vshelper.isEnabled; then
376         vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
377     else
378         _NEED_VSHELPER_SYNC=
379     fi
380 }
381
382 function _generateFlagOptions
383 {
384     local vdir=$1
385     local file
386
387     CHCONTEXT_FLAG_OPTS=()
388
389     findFile file "$vdir"/cflags "$vdir"/flags ""
390     test -z "$file" || \
391     while read flag; do
392         case x"$flag" in
393             (x|x\#*)            ;;
394             (xnamespace)        ;;
395             (xfakeinit)
396                 _IS_FAKEINIT=1
397                 ;;
398             (*)
399                 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
400                 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
401                                       --flag "$flag" )
402                 ;;
403         esac
404     done <"$file"
405
406     isAvoidNamespace "$vdir" || {
407         USE_VNAMESPACE=1
408         CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
409         ! $_VSERVER_INFO - FEATURE PIVOT_ROOT || \
410             OPT_VCONTEXT_CHROOT=--pivot-root
411     }
412 }
413
414 function _generateChcontextOptions
415 {
416     local vdir=$1
417     local ctx hostname domainname
418     local cap_opts
419     local flag
420
421     {
422         read ctx        <"$vdir"/context        || :
423         ## LEGACY ALERT
424         read hostname   <"$vdir"/uts/nodename   || read hostname   <"$vdir"/hostname   || :
425         read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
426     } 2>/dev/null
427
428     test -z "$S_CONTEXT" || ctx=$S_CONTEXT
429
430     _generateCapabilityOptions "$vdir"
431     _generateFlagOptions       "$vdir"
432
433     CHCONTEXT_OPTS=( $SILENT_OPT \
434                      "${CHCONTEXT_FLAG_OPTS[@]}" \
435                      "${CAP_OPTS[@]}" \
436                      --secure
437                      ${ctx:+--ctx "$ctx"} \
438                      ${hostname:+--hostname "$hostname"} \
439                      ${domainname:+--domainname "$domainname"} )
440
441     OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
442                            ${ctx:+--xid "$ctx"} )
443     ## put '--secure' at front so that it can be overridden
444     OPTS_VATTRIBUTE=( --secure --flag default "${OPTS_VATTRIBUTE[@]}" )
445 }
446
447 function _generateScheduleOptions
448 {
449     local vdir=$1
450     if test -d "$vdir"/sched; then
451       OPTS_VSCHED=( --dir "$vdir"/sched --missingok )
452       return 0
453     fi
454
455     local f="$vdir"/schedule
456     test -e "$f" || return 0
457
458     local fill_rate interval tokens tokens_min tokens_max prio_bias
459     {
460         {
461             read fill_rate   && \
462             read interval    && \
463             read tokens      && \
464             read tokens_min  && \
465             read tokens_max  && \
466             read prio_bias   || prio_bias=
467         } <"$f"
468     } 2>/dev/null
469
470     test -n "$prio_bias" || {
471         echo $"Bad content in '$f'; aborting..." >&2
472         false
473     }
474
475     OPTS_VSCHED=( --fill-rate  "$fill_rate"  --interval "$interval" \
476                   --tokens     "$tokens"     --tokens_min "$tokens_min" \
477                   --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
478 }
479
480 function _getInterfaceValue
481 {
482     local _giv_val=$1
483     local _giv_dflt=$2
484     shift 2
485    
486     local _giv_i
487     local _giv_tmp
488
489     for _giv_i; do
490         read _giv_tmp  <"$_giv_i/$_giv_val" && break || :
491     done 2>/dev/null
492
493     : ${_giv_tmp:=$_giv_dflt}
494     eval $_giv_val=\$_giv_tmp
495 }
496
497 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
498 function _transformMask2Prefix
499 {
500     local _tm2p_tmp=$2
501    
502     test -n "$_tm2p_tmp" || {
503         $_MASK2PREFIX "$3" || _tm2p_tmp=$?
504     }
505
506     eval $1=\$_tm2p_tmp
507     return 0
508 }
509
510 function _addInterfaceCmd
511 {
512     eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
513     let ++INTERFACE_CMDS_IDX
514 }
515
516 ## Usage: _generateMac <var> <iface> <ctx>
517 function _generateMac
518 {
519     isNumber "$2" || {
520         echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
521         return 1
522     }
523
524     eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
525 }
526
527 function _getVLANInfo
528 {
529     case "$1" in
530         (vlan????)
531             panic "\
532 creation of VLAN_PLUS_VID devices is not supported; please create them
533 before starting the vserver and use the 'nodev' flag then"
534             echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
535             ;;
536         (vlan*)
537             panic "\
538 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
539 create them before starting the vserver and use the 'nodev' flag then"
540             echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
541             ;;
542         (*.????)        echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
543         (*.*)           echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
544         (*)             return 1
545     esac
546
547     return 0
548 }
549
550 function _getTunInfo
551 {
552     local iface="$1"
553
554     test -e "$iface/tun" -o -e "$iface/tap" || return 1
555     test ! -e "$iface/tun"     || echo --tun
556     test ! -e "$iface/tap"     || echo --tap
557     test ! -e "$iface/nocsum"  || echo --~checksum
558     test   -e "$iface/shared"  || echo --nid-failure-ok "$N_CONTEXT"
559     if test -e "$iface/uid"; then
560         local uid
561         getFileValue uid "$iface/uid"
562         echo --uid "$uid"
563     fi
564     if test -e "$iface/gid"; then
565         local gid
566         getFileValue gid "$iface/gid"
567         echo --gid "$gid"
568     fi
569     if test -e "$iface/linktype"; then
570         local linktype
571         getFileValue linktype "$iface/linktype"
572         echo --linktype "$linktype"
573     fi
574     return 0
575 }
576
577 ## Usage: _processSingleInterface <interface-directory>
578 function _processSingleInterface
579 {
580     local iface=$1
581
582     local ip
583     local dev
584     local prefix
585     local mask
586     local bcast
587     local name
588     local scope
589     local mac
590     local extip
591     local up="up"
592     local peer
593
594     _getInterfaceValue ip     '' "$iface"
595     _getInterfaceValue extip  '' "$iface" "$iface/.."
596     _getInterfaceValue dev    '' "$iface" "$iface/.."
597     _getInterfaceValue prefix '' "$iface" "$iface/.."
598     _getInterfaceValue mask   '' "$iface" "$iface/.."
599     _getInterfaceValue bcast  '' "$iface" "$iface/.."
600     _getInterfaceValue name   '' "$iface"
601     _getInterfaceValue scope  '' "$iface" "$iface/.."
602     _getInterfaceValue mac    '' "$iface"
603     _getInterfaceValue peer   '' "$iface"
604
605     test -n "$ip" || { echo $"Can not read ip for '$iface'"  >&2; return 1; }
606     test -n "$dev" -o -e "$iface"/nodev || {
607         echo $"No device specified for '$iface'" >&2
608         return 1;
609     }
610
611     test ! -e "$iface"/down || up=
612
613     while true; do
614         _transformMask2Prefix prefix "$prefix" "$mask"
615         INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
616
617         test ! -e "$iface"/nodev   || break
618         ## LEGACY ALERT
619         test ! -e "$iface"/only_ip || break
620
621         test -e "$iface/vlandev" \
622              -o \( -e "$iface/../vlandev" -a ! -e "$iface/novlandev" \) \
623              -o \( -e "$__CONFDIR/.defaults/interfaces/vlandev" \
624                    -a ! -e "$iface/novlandev" \
625                    -a ! -e "$iface/../novlandev" \) && {
626             local vlan_info
627             if vlan_info=$(_getVLANInfo "$dev"); then
628                 test -d /proc/net/vlan || {
629                     echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers"  >&2
630                     return 1
631                 }
632                 _addInterfaceCmd VCONFIG $vlan_info
633             fi
634         }
635
636         if ! test -e "$iface"/indirect; then
637             # XXX: IPv6 hack
638             local use_bcast="broadcast ${bcast:-+}"
639             echo "$ip" | $_GREP -q : && use_bcast=
640
641             local tun_info
642             if tun_info=$(_getTunInfo "$iface"); then
643                 _addInterfaceCmd TUNCTL "$dev" $tun_info
644             fi
645
646             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" $use_bcast ${name:+label "$dev:$name"} dev "$dev" ${peer:+peer "$peer"}
647             #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
648             _addInterfaceCmd IP_LINK  "$dev" $up
649         elif ! test -n "$N_CONTEXT"; then
650             echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
651             return 1
652         else
653             test -z "$mac" || _generateMac mac "$(basename $iface)" "$N_CONTEXT" || return 1
654             _addInterfaceCmd MODPROBE dummy "$dev"
655             _addInterfaceCmd IP_LINK  dev dummy0 address "$mac"
656             _addInterfaceCmd NAMEIF   "$dev" "$mac"
657             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" dev "$dev"
658             test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$N_CONTEXT" "$extip"
659         fi
660
661         break
662     done
663 }
664
665 ## Usage: _generateInterfaceOptions <vserver-directory>
666 function _generateInterfaceOptions
667 {
668     local iface
669
670     # XXX: This is here instead of in _generateChbindOptions
671     #      to avoid a circular dependency
672     getFileValue N_CONTEXT "$1/ncontext" "$1/context"
673     test -n "$N_CONTEXT" -o -z "$S_CONTEXT" || N_CONTEXT="$S_CONTEXT"
674
675     for iface in "$1/interfaces/"*; do
676         test   -d "$iface"          || continue
677         test ! -e "$iface"/disabled || continue
678    
679         _processSingleInterface "$iface"
680     done
681     _HAVE_INTERFACE_OPTIONS=1
682 }
683
684 function enableInterfaces
685 {
686     local i=0
687     declare -a var
688
689     lock "$__LOCKDIR"/vserver.interfaces
690
691     while test $i -lt $INTERFACE_CMDS_IDX; do
692         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
693         local type=${var[0]}
694         unset var[0]
695
696         set -- "${var[@]}"
697         case "$type" in
698             IPTABLES)   ;; ## TODO
699             MODPROBE)
700                 local mod=$1
701                 local name=$2
702                 shift 2
703                 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
704                 ;;
705             NAMEIF)             $_NAMEIF   "$@";;
706             VCONFIG)            $_VCONFIG  set_name_type "$4"      >/dev/null
707                                 $_VCONFIG  add           "$2" "$3" >/dev/null;;
708             IP_ADDR)            $_IP addr  add   "$@";;
709             IP_ADDR_FLUSH)      $_IP addr  flush "$@";;
710             IP_LINK)            $_IP link  set   "$@";;
711             IP_ROUTE)           $_IP route add   "$@";;
712             TUNCTL)
713                 local dev="$1"
714                 shift
715                 $_TUNCTL --persist "$@" "$dev"
716                 ;;
717             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
718         esac
719
720         let ++i
721     done
722
723     unlock 1
724 }
725
726 function disableInterfaces
727 {
728     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
729
730     local i=$INTERFACE_CMDS_IDX
731     declare -a var
732
733     lock "$__LOCKDIR"/vserver.interfaces
734    
735     while test $i -gt 0; do
736         let --i || :
737
738         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
739         local type=${var[0]}
740         unset var[0]
741        
742         set -- "${var[@]}"
743         case "$type" in
744             IPTABLES)           ;; ## TODO
745             MODPROBE)           $_RMMOD "${2:-$1}";;
746             NAMEIF)             ;;
747             VCONFIG)            $_VCONFIG  rem "$2.$3" >/dev/null;;
748             IP_ADDR)            $_IP addr  del "$@";;
749             IP_ADDR_FLUSH)      ;;
750             IP_LINK)            ;; ## Ignore the link-down command for now
751             IP_ROUTE)           $_IP route del "$@";;
752             TUNCTL)             $_TUNCTL --~persist "$1";;
753             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
754         esac
755     done
756
757     unlock 1
758 }
759
760 function _generateTagOptions
761 {
762     local vdir="$1"
763     local tag
764
765     getFileValue tag "$vdir/tag" "$vdir/context"
766     test -n "$tag" || return 0
767
768     OPTS_VTAG_CREATE=( --tag "$tag" )
769     OPTS_VTAG_ENTER=( --tag "$tag" )
770 }
771
772 function _generateMemctrlOptions
773 {
774     local vdir="$1"
775     local badness
776
777     getFileValue badness "$vdir/badness"
778     test -n "$badness" || return 0
779
780     OPTS_VMEMCTRL=( --badness "$badness" )
781 }
782
783 function _generateSpaceOptions
784 {
785     local vdir="$1"
786     local d="$vdir"/spaces
787
788     ( test ! -e "$d"/pid ) || \
789         OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
790
791     test ! -e "$d"/net || {
792         OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
793         # network context and namespace don't make much sense
794         _HAVE_CHBIND_OPTIONS=1
795         CHBIND_CMD=()
796     }
797
798     local mask
799     getFileValue mask "$d"/mask || \
800       OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --mask "$mask" )
801 }
802
803 ## Usage: prepareInit <vserver-directory>
804 function prepareInit
805 {
806     pushd "$1/vdir" >/dev/null
807     case "$INITSTYLE" in
808         sysv)
809             { find var/run  ! -type d -print0; \
810               find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
811             ;;
812         plain)
813             $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
814             : | $_CHROOT_SH truncate fastboot  2>/dev/null || :
815             ;;
816         minit)
817             ;;
818     esac
819     "${INITCMD_PREPARE[@]}"
820     popd >/dev/null
821 }
822
823 ## Usage: prepareInit <vserver-directory>
824 function prepareStop
825 {
826     pushd "$1/vdir" >/dev/null
827     case "$INITSTYLE" in
828         (sysv)
829             export PREVLEVEL=$RUNLEVEL_START RUNLEVEL=$RUNLEVEL_STOP # required by Debian's initscripts
830             ;;
831     esac
832     "${STOPCMD_PREPARE[@]}"
833     popd >/dev/null
834 }
835
836
837 function generateOptions
838 {
839     _generateInterfaceOptions   "$1"
840     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
841     _generateNiceCommand        "$1"
842     _generateIONiceCommand      "$1"
843     _generateInitOptions        "$1"
844     _generateChcontextOptions   "$1"
845     _generateScheduleOptions    "$1"
846     _generatePersonalityOptions "$1"
847     _generateTagOptions         "$1"
848     _generateMemctrlOptions     "$1"
849     _generateSpaceOptions       "$1"
850     _generateCgroupOptions
851
852     if test -n "$_IS_FAKEINIT"; then
853         CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
854         OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
855     fi
856 }
857
858 function addtoCPUSET
859 {
860     local vdir=$1
861     local cpuset
862     local f="$vdir"/cpuset
863     local i
864     local configured=0
865
866     test -d "$f" || return 0
867     test -e "$f"/name || return 0
868
869     read cpuset < "$f"/name
870     test -e "$f"/nocreate || {
871        test -d /dev/cpuset/"$cpuset" || mkdir /dev/cpuset/"$cpuset" || configured=1
872        for i in cpus mems cpu_exclusive mem_exclusive virtualized; do
873            if test -e "$f"/"$i"; then
874                cat "$f"/"$i" >/dev/cpuset/"$cpuset"/"$i" || {
875                    configured=1
876                    break
877                }
878            fi
879        done
880     }
881
882     echo $$ >/dev/cpuset/"$cpuset"/tasks || configured=1
883     if [ "$configured" -ne 0 ]; then
884        warning $"\
885 WARNING: Failed to create or CPUSET \"$cpuset\" does not exist! Not using it!" >&2
886        rmdir /dev/cpuset/"$cpuset" 2>/dev/null || :
887        return 0
888     fi
889 }
890
891 function removeCPUSET
<