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