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