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