minor optimizations
[util-vserver.git] / util-vserver / 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_START=()
32 declare -a INITCMD_START_SYNC=()
33 declare -a INITCMD_STOP=()
34 declare -a INITCMD_STOP_SYNC=()
35 declare -a INITCMD_PREPARE=()
36 declare -a INITKILL_SEQ=()
37 declare -a ENTER_SHELL=()
38
39 declare -a OPTS_VCONTEXT_CREATE=()
40 declare -a OPTS_VCONTEXT_MIGRATE=()
41 declare -a OPTS_VATTRIBUTE=( --flag fakeinit )
42 declare -a OPTS_VSCHED=()
43
44 declare -a VSERVER_EXTRA_CMDS=()
45
46 VSHELPER_SYNC_TIMEOUT=30
47 USE_VNAMESPACE=
48 INTERFACE_CMDS_IDX=0
49 _HAVE_INTERFACE_OPTIONS=
50 _HAVE_CHBIND_OPTIONS=
51 _NEED_VSHELPER_SYNC=
52 _IS_FAKEINIT=
53
54 INITSTYLE=sysv
55
56 S_CONTEXT=
57
58 SILENT_OPT=
59
60 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
61
62 if test -e "$VSERVER_DIR"/noisy -o "$OPTION_VERBOSE"; then
63     SILENT_OPT=
64 else
65     SILENT_OPT='--silent'
66 fi
67
68 function _generateChbindOptions
69 {
70     local vdir="$1"
71     local i
72     local bcast=
73
74     test "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
75
76     local f=$vdir/interfaces/bcast
77     getFileValue bcast "$f"
78     
79     CHBIND_OPTS=( $SILENT_OPT ${bcast:+--bcast "$bcast"} )
80
81     for i in "${INTERFACES[@]}"; do
82         CHBIND_OPTS=( "${CHBIND_OPTS[@]}" --ip "$i" )
83     done
84
85     _HAVE_CHBIND_OPTIONS=1
86 }
87
88 function _generateNiceCommand
89 {
90     local vdir=$1
91     local nice
92
93     test -r "$vdir/nice" || return 0;
94     read nice <"$vdir"/nice
95
96     NICE_CMD=( $_NICE -$nice )
97 }
98
99 function _generateCCapabilityOptions
100 {
101     local vdir=$1
102     local cap
103     local f="$vdir"/ccapabilities
104     
105     test -e "$f" || return 0
106     while read cap; do
107         case x"$cap" in
108             (x|x\#)     ;;
109             (*)         OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --ccap "$cap" );;
110         esac
111     done <"$f"
112 }
113
114 function _generateBCapabilityOptions
115 {
116     local vdir=$1
117     local cap
118     local f="$vdir"/bcapabilities
119     
120     test -e "$f" || return 0
121     while read cap; do
122         case x"$cap" in
123             (x|x\#)     ;;
124             (*)         OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --bcap "$cap" );;
125         esac
126     done <"$f"
127 }
128
129 function _generateCapabilityOptions
130 {
131     local vdir=$1
132     local cap
133
134     _generateBCapabilityOptions "$vdir"
135     _generateCCapabilityOptions "$vdir"
136     
137     test -e "$vdir"/capabilities || return 0
138
139     CAP_OPTS=()
140     CAPCHROOT_OPTS=()
141
142     while read cap; do
143         case x"$cap" in
144             (x|x\#)     ;;
145             (!CAP_SYSCHROOT)
146                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
147                 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
148                 ;;
149             (*)
150                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
151                 ;;
152         esac
153     done <"$vdir"/capabilities
154 }
155
156 function getEnterShell
157 {
158     local vdir=$1
159
160     ENTER_SHELL=()
161     
162     getFileValue ENTER_SHELL     "$vdir"/shell
163     
164     test "$ENTER_SHELL" || {
165         local i
166         for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
167             set -- $i
168             test -x "$vdir/vdir/$1" || continue
169             ENTER_SHELL=( "$@" )
170             break
171         done
172     }
173 }
174
175 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
176 function sendKillSequence
177 {
178     local ctx=$1
179     local wait=
180     shift
181
182     while isCtxRunning "$ctx"; do
183         test -z "$wait" || sleep "$wait"
184         
185         $_VKILL -c "$ctx" ${1:+-s "$1"} 2>/dev/null || :
186         test "$2" || break
187         wait="$2"
188         shift 2
189     done
190 }
191
192 function _generateInitOptions
193 {
194     local vdir=$1
195     local cfgdir=$vdir/apps/init
196     local runlevel_start
197     local runlevel_stop
198     local i f
199
200     INITCMD_START=()
201     INITCMD_STOP=()
202     INITCMD_START_SYNC=()
203     INITCMD_STOP_SYNC=()
204     INITCMD_PREPARE=()
205
206     INITKILL_SEQ=( 15 5 9 )
207     CHCONTEXT_INIT_OPTS=()
208
209
210     getFileValue INITSTYLE      "$cfgdir"/style
211     getFileValue runlevel_start "$cfgdir"/runlevel
212     getFileValue runlevel_start "$cfgdir"/runlevel.start
213     getFileValue runlevel_stop  "$cfgdir"/runlevel.stop
214     getFileArray INITKILL_SEQ   "$cfgdir"/killseq || :
215
216     case x"$INITSTYLE" in
217         (xsysv)
218             test "$runlevel_start" || runlevel_start=3
219             test "$runlevel_stop"  || runlevel_stop=6
220
221             for i in /etc/init.d/rc /etc/rc.d/rc; do
222                 test -x "$vdir/vdir/$i" || continue
223                 INITCMD_START=( "$i" "$runlevel_start" )
224                 INITCMD_STOP=(  "$i" "$runlevel_stop"  )
225             done
226             INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$runlevel_start" /var/run/utmp )
227             ;;
228             
229         (xplain)
230             INITCMD_START=( /sbin/init )
231             INITCMD_STOP=(  /sbin/init )
232             _IS_FAKEINIT=1
233             _NEED_VSHELPER_SYNC=1
234             test -z "$runlevel_start" || INITCMD_START=( "${INITCMD_START[@]}" "$runlevel_start" )
235             test -z "$runlevel_stop"  || INITCMD_STOP=(  "${INITCMD_STOP[@]}"  "$runlevel_stop"  )
236             ;;
237             
238         (xminit)
239             INITCMD_START=( /sbin/minit-start )
240             INITCMD_STOP=(  /sbin/minit-stop  )
241             _IS_FAKEINIT=1
242             INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
243             _NEED_VSHELPER_SYNC=1
244             test -z "$runlevel_start" || INITCMD_START=( "${INITCMD_START[@]}" "$runlevel_start" )
245             test -z "$runlevel_stop"  || INITCMD_STOP=(  "${INITCMD_STOP[@]}"  "$runlevel_stop"  )
246             ;;
247
248         (xgentoo)
249             INITCMD_START=( /sbin/rc default  )
250             INITCMD_STOP=(  /sbin/rc shutdown )
251             ;;
252
253         (x) ;;
254         (*) echo "Unknown init-style '$INITSTYLE'; aborting" >&2;
255             exit 1;;
256     esac
257
258     getFileArray INITCMD_START      "$cfgdir"/cmd.start      || :
259     getFileArray INITCMD_STOP       "$cfgdir"/cmd.stop       || :
260     getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
261     getFileArray INITCMD_STOP_SYNC  "$cfgdir"/cmd.stop-sync  || :
262     getFileArray INITCMD_PREPARE    "$cfgdir"/cmd.prepare    || :
263
264     
265     test "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
266         INITCMD_START_SYNC=()
267         INITCMD_STOP_SYNC=()
268         _NEED_VSHELPER_SYNC=
269     }
270
271     if vshelper.isEnabled; then
272         vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
273     else
274         _NEED_VSHELPER_SYNC=
275     fi
276 }
277
278 function _generateFlagOptions
279 {
280     local vdir=$1
281
282     CHCONTEXT_FLAG_OPTS=()
283
284     test ! -e "$vdir"/flags || \
285     while read flag; do
286         case x"$flag" in
287             (x|x\#)             ;;
288             (xnamespace)        ;;
289             (xfakeinit)
290                 _IS_FAKEINIT=1
291                 ;;
292             (*)
293                 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
294                 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
295                                       --flag "$flag" )
296                 ;;
297         esac
298     done <"$vdir"/flags
299
300     isAvoidNamespace "$vdir" || {
301         USE_VNAMESPACE=1
302         CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
303     }
304 }
305
306 function _generateChcontextOptions
307 {
308     local vdir=$1
309     local ctx hostname domainname
310     local cap_opts
311     local flag
312
313     {
314         read ctx        <"$vdir"/context        || :
315         ## LEGACY ALERT
316         read hostname   <"$vdir"/uts/nodename   || read hostname   <"$vdir"/hostname   || :
317         read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
318     } 2>/dev/null
319
320     ## LEGACY ALERT
321     test \( ! -e "$vdir"/hostname   -o -e "$vdir"/uts/nodename   \) -a \
322          \( ! -e "$vdir"/domainname -o -e "$vdir"/uts/domainname \) || {
323         echo $"\
324 The hostname is now configured in 'uts/nodename' but not in 'hostname' anymore;
325 the old way is not supported when using 2.6 kernel patches so it is strongly
326 recommended to move these files.
327
328 The same applies to 'domainname' vs. 'uts/domainname'." >&2
329     }
330
331     test -z "$S_CONTEXT" || ctx=$S_CONTEXT
332
333     _generateCapabilityOptions "$vdir"
334     _generateFlagOptions       "$vdir"
335
336     CHCONTEXT_OPTS=( $SILENT_OPT \
337                      "${CHCONTEXT_FLAG_OPTS[@]}" \
338                      "${CAP_OPTS[@]}" \
339                      --secure
340                      ${ctx:+--ctx "$ctx"} \
341                      ${hostname:+--hostname "$hostname"} \
342                      ${domainname:+--domainname "$domainname"} )
343
344     OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
345                            ${ctx:+--xid "$ctx"} )
346     ## put '--secure' at front so that it can be overridden
347     OPTS_VATTRIBUTE=( --secure "${OPTS_VATTRIBUTE[@]}" )
348 }
349
350 function _generateScheduleOptions
351 {
352     local vdir=$1
353     local f="$vdir"/schedule
354     test -e "$f" || return 0
355
356     local fill_rate interval tokens tokens_min tokens_max cpu_mask
357     {
358         {
359             read fill_rate   && \
360             read interval    && \
361             read tokens      && \
362             read tokens_min  && \
363             read tokens_max  && \
364             read cpu_mask    || cpu_mask=
365         } <"$f"
366     } 2>/dev/null
367
368     test "$cpu_mask" || {
369         echo $"Bad content in '$f'; aborting..." >&2
370         false
371     }
372
373     OPTS_VSCHED=( --fill-rate  "$fill_rate"  --interval "$interval" \
374                   --tokens     "$tokens"     --tokens_min "$tokens_min" \
375                   --tokens_max "$tokens_max" --cpu_mask "$cpu_mask" )
376 }
377
378 function _getInterfaceValue
379 {
380     local val=$1
381     local dflt=$2
382     shift 2
383     
384     local i
385     local tmp
386
387     for i; do
388         read tmp  <"$i/$val" && break || :
389     done 2>/dev/null
390
391     : ${tmp:=$dflt}
392     eval $val=\$tmp
393 }
394
395 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
396 function _transformMask2Prefix
397 {
398     local tmp=$2
399     
400     test "$tmp" || {
401         $_MASK2PREFIX "$3" || tmp=$?
402     }
403
404     eval $1=\$tmp
405     return 0
406 }
407
408 function _addInterfaceCmd
409 {
410     eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
411     let ++INTERFACE_CMDS_IDX
412 }
413
414 ## Usage: _generateMac <var> <iface> <ctx>
415 function _generateMac
416 {
417     isNumber "$2" || {
418         echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
419         return 1
420     }
421
422     eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
423 }
424
425 ## Usage: _processSingleInterface <interface-directory>
426 function _processSingleInterface
427 {
428     local iface=$1
429
430     local ip
431     local dev
432     local prefix
433     local mask
434     local bcast
435     local name
436     local scope
437     local mac
438     local extip
439     local up="up"
440
441     _getInterfaceValue ip     '' "$iface"
442     _getInterfaceValue extip  '' "$iface" "$iface/.."
443     _getInterfaceValue dev    '' "$iface" "$iface/.."
444     _getInterfaceValue prefix '' "$iface" "$iface/.."
445     _getInterfaceValue mask   '' "$iface" "$iface/.."
446     _getInterfaceValue bcast  '' "$iface" "$iface/.."
447     _getInterfaceValue name   '' "$iface"
448     _getInterfaceValue scope  '' "$iface" "$iface/.."
449     _getInterfaceValue mac    '' "$iface"
450
451     test "$ip" || { echo $"Can not read ip for '$iface'"  >&2; return 1; }
452
453     test ! -e "$iface"/down    || up=
454     
455     while test "$dev"; do
456         _transformMask2Prefix prefix "$prefix" "$mask"
457         INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
458
459         test ! -e "$iface"/nodev || break
460         test ! -e "$iface"/only_ip || {
461             ## LEGACY ALERT
462             echo $"The 'only_ip' flag for interface '$iface' is deprecated; use 'nodev' instead of" >&2
463             break
464         }
465
466         case "$dev" in
467             (*.*)
468                 test -d /proc/net/vlan || {
469                     echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers"  >&2
470                     return 1
471                 }
472                 test -f /proc/net/vlan || {
473                     _addInterfaceCmd VCONFIG "${dev/./ }"
474                     _addInterfaceCmd IP_ADDR 127.0.0.1/8 broadcast 127.255.255.255 dev "$dev"
475                     _addInterfaceCmd IP_LINK "$dev" $up
476                 }
477                 ;;
478         esac
479
480         if ! test -e "$iface"/indirect; then
481             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} ${name:+label "$dev:$name"} dev "$dev"
482             #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
483             _addInterfaceCmd IP_LINK  "$dev" $up
484         elif ! test "$ctx"; then
485             echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
486             return 1
487         else
488             test "$mac" || _generateMac mac "$(basename $iface)" "$ctx" || return 1
489             _addInterfaceCmd MODPROBE dummy "$dev"
490             _addInterfaceCmd IP_LINK  dev dummy0 address "$mac"
491             _addInterfaceCmd NAMEIF   "$dev" "$mac"
492             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" dev "$dev"
493             test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$ctx" "$extip"
494         fi
495
496         break
497     done
498 }
499
500 ## Usage: _generateInterfaceOptions <vserver-directory>
501 function _generateInterfaceOptions
502 {
503     local iface
504     local ctx
505
506     test ! -e "$1"/context || read ctx <"$1"/context
507
508     for iface in "$1/interfaces/"*; do
509         test   -d "$iface"          || continue
510         test ! -e "$iface"/disabled || continue
511     
512         _processSingleInterface "$iface"
513     done
514     _HAVE_INTERFACE_OPTIONS=1
515 }
516
517 function enableInterfaces
518 {
519     local i=0
520     declare -a var
521
522     lock "$LOCKDIR"/vserver.interfaces
523
524     while test $i -lt $INTERFACE_CMDS_IDX; do
525         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
526         local type=${var[0]}
527         unset var[0]
528
529         set -- "${var[@]}"
530         case "$type" in
531             IPTABLES)   ;; ## TODO
532             MODPROBE)
533                 local mod=$1
534                 local name=$2
535                 shift 2
536                 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
537                 ;;
538             NAMEIF)             $_NAMEIF "$@";;
539             VCONFIG)            $_VCONFIG  add   "$@";;
540             IP_ADDR)            $_IP addr  add   "$@";;
541             IP_ADDR_FLUSH)      $_IP addr  flush "$@";;
542             IP_LINK)            $_IP link  set   "$@";;
543             IP_ROUTE)           $_IP route add   "$@";;
544             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
545         esac
546
547         let ++i
548     done
549
550     unlock 1
551 }
552
553 function disableInterfaces
554 {
555     test "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
556
557     local i=$INTERFACE_CMDS_IDX
558     declare -a var
559
560     lock "$LOCKDIR"/vserver.interfaces
561     
562     while test $i -gt 0; do
563         let --i || :
564
565         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
566         local type=${var[0]}
567         unset var[0]
568         
569         set -- "${var[@]}"
570         case "$type" in
571             IPTABLES)           ;; ## TODO
572             MODPROBE)           $_RMMOD "${2:-$1}";;
573             NAMEIF)             ;;
574             VCONFIG)            $_VCONFIG  rem "$@";;
575             IP_ADDR)            $_IP addr  del "$@";;
576             IP_ADDR_FLUSH)      ;;
577             IP_LINK)            ;; ## Ignore the link-down command for now
578             IP_ROUTE)           $_IP route del "$@";;
579             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
580         esac
581     done
582
583     unlock 1
584 }
585
586 ## Usage: prepareInit <vserver-directory>
587 function prepareInit
588 {
589     pushd "$1/vdir" >/dev/null
590     case "$INITSTYLE" in
591         sysv)
592             { find var/run  ! -type d -print0; \
593               find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_RM
594             ;;
595         plain)
596             $_CHROOT_RM .autofsck forcefsck 2>/dev/null || :
597             : | $_CHROOT_CAT fastboot       2>/dev/null || :
598             ;;
599         minit)
600             ;;
601     esac
602     "${INITCMD_PREPARE[@]}"
603     popd >/dev/null
604 }
605
606 function generateOptions
607 {
608     _generateInterfaceOptions  "$1"
609     test "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1" 
610     _generateNiceCommand       "$1"
611     _generateInitOptions       "$1"
612     _generateChcontextOptions  "$1"
613     _generateScheduleOptions   "$1"
614
615     if test "$_IS_FAKEINIT"; then
616         CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
617         OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
618     fi
619 }
620
621 function _mountVserverInternal
622 {
623     local fstab="$1"
624     test -e "$fstab" || return 0
625     shift
626     
627     "$@" $_SECURE_MOUNT -a --chroot "$vdir" --fstab "$fstab"
628 }
629
630 function mountVserver
631 {
632     local cfgdir=$1
633     local ns_opt=$2
634     local vdir=$1/vdir
635     local mtab_src
636
637     test -e "$cfgdir"/fstab -o \
638          -e "$cfgdir"/fstab.local || return 0
639
640     findObject -r mtab_src "$vdir"/apps/init/mtab "$CONFDIR"/.defaults/init/mtab "$PKGLIBDEFAULTDIR"/mtab /dev/null
641     
642     pushd "$vdir" >/dev/null
643     $_CHROOT_CAT /etc/mtab <"$mtab_src"
644     popd >/dev/null
645
646     test "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
647
648     test -z "$NAMESPACE_CLEANUP" || isAvoidNamespace "$cfgdir" || \
649         $_VNAMESPACE --cleanup
650
651     _mountVserverInternal "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}"
652     _mountVserverInternal "$cfgdir"/fstab.local
653
654     isAvoidNamespace "$cfgdir" || \
655         $_SECURE_MOUNT --rbind -n "$vdir" "/"
656 }
657
658 function _umountVserverInternal
659 {
660     local fstab="$1"
661     test -e "$fstab" || return 0
662     shift
663
664     tac "$fstab" | {
665         is_ok=1
666         while read src dst tmp; do
667             test "$tmp" || continue
668             case x"$src" in
669                 (x\#*)  continue;;
670             esac
671
672         
673             "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
674         done
675         test "$is_ok"
676     }
677 }
678
679 function umountVserver
680 {
681     local cfgdir=$1
682     local vdir=$1/vdir
683     local is_ok=1
684
685     isAvoidNamespace "$cfgdir"    || return 0
686     test -e "$cfgdir"/fstab -o \
687          -e "$cfgdir"/fstab.local || return 0
688     test "$_HAVE_CHBIND_OPTIONS"  || _generateChbindOptions "$cfgdir"
689     
690     pushd "$vdir/" >/dev/null || return 1
691         _umountVserverInternal  "$cfgdir"/fstab.local                              || is_ok=
692         _umountVserverInternal  "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
693     popd >/dev/null           || return 1
694
695     test "$is_ok"
696 }
697
698 ## Usage: waitForSync <vserver> <vshelper-fifo-varname>
699 function initSync
700 {
701     test -z "$_NEED_VSHELPER_SYNC" || vshelper.initSync "$1" "$2"
702 }
703
704 ## Usage: waitForSync <vserver> [<vshelper-fifo>]
705 function waitForSync
706 {
707     local cfgdir=$1
708     local fifo=$2
709     
710     if test "$_NEED_VSHELPER_SYNC"; then
711         $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
712             warning $"\
713 A timeout or other error occured while waiting for the synchronization
714 signal from vserver '$VSERVER_NAME'.
715 The vserver will be killed nevertheless..."
716     elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
717         "${INITCMD_STOP_SYNC[@]}" || \
718             warning $"\
719 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
720 will be killed nevertheless..."
721     fi
722
723     test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
724         sleep 1
725 }
726
727 function _sourceWrap
728 {
729     local vdir name flavor start i already_handled base
730     . "$@"
731 }
732
733 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
734 function execScriptlets
735 {
736     declare -r vdir=$1
737     declare -r name=$2
738     declare -r flavor=$3
739     local base i
740
741     for base in "$vdir"/scripts "$CONFDIR"/.defaults/scripts; do
742         local   DONT_SKIP_DEFAULTS=
743         local   already_handled=
744         
745         for i in "$base/$flavor" "$base/$flavor.d"/*; do
746             test -f "$i" -a -r "$i" || continue
747             already_handled=1
748             local start=
749             test -x "$i" || start=_sourceWrap
750             $start "$i" "$flavor" "$name"
751         done
752
753         test -z "$already_handled" -o "$DONT_SKIP_DEFAULTS" || break
754     done
755 }