use CHROOT_SH instead of CHROOT_*
[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_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
46 declare -a STOPCMD_PREPARE=()
47
48 declare -a VSERVER_EXTRA_CMDS=()
49
50 INIT_RESCUE=
51 VSHELPER_SYNC_TIMEOUT=30
52 USE_VNAMESPACE=
53 INTERFACE_CMDS_IDX=0
54 RUNLEVEL_START=
55 RUNLEVEL_STOP=
56 _HAVE_INTERFACE_OPTIONS=
57 _HAVE_CHBIND_OPTIONS=
58 _NEED_VSHELPER_SYNC=
59 _IS_FAKEINIT=
60
61 INITSTYLE=sysv
62
63 S_CONTEXT=
64
65 SILENT_OPT=
66
67 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
68
69 if test -e "$VSERVER_DIR"/noisy -o -n "$OPTION_VERBOSE"; then
70     SILENT_OPT=
71 else
72     SILENT_OPT='--silent'
73 fi
74
75 function _generateChbindOptions
76 {
77     local vdir="$1"
78     local i
79     local bcast=
80
81     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
82
83     local f=$vdir/interfaces/bcast
84     getFileValue bcast "$f"
85     
86     CHBIND_OPTS=( $SILENT_OPT ${bcast:+--bcast "$bcast"} )
87
88     for i in "${INTERFACES[@]}"; do
89         CHBIND_OPTS=( "${CHBIND_OPTS[@]}" --ip "$i" )
90     done
91
92     _HAVE_CHBIND_OPTIONS=1
93 }
94
95 function _generateNiceCommand
96 {
97     local vdir=$1
98     local nice
99
100     test -r "$vdir/nice" || return 0;
101     read nice <"$vdir"/nice
102
103     NICE_CMD=( $_NICE -$nice )
104 }
105
106
107 function _generatePersonalityOptions
108 {
109     local vdir="$1"
110     local f="$vdir"/personality
111     local type flags
112
113     test -s "$f" || return 0
114
115     {
116         local delim tmp
117
118         read type
119         while read tmp; do
120             case x$tmp in
121                 (x\#*|x)        ;;
122                 (*)             flags=$flags$delim$tmp
123                                 delim=,
124                                 ;;
125             esac
126         done
127     } <"$f"
128
129     OPTS_VCONTEXT_ENTER=( "${OPTS_VCONTEXT_ENTER[@]}"
130                           --personality-type "$type"
131                           ${flags:+--personality-flags "$flags"} )
132 }
133
134 function _generateCCapabilityOptions
135 {
136     local vdir=$1
137     local cap
138     local f="$vdir"/ccapabilities
139     
140     test -e "$f" || return 0
141     while read cap; do
142         case x"$cap" in
143             (x|x\#)     ;;
144             (*)         OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --ccap "$cap" );;
145         esac
146     done <"$f"
147 }
148
149 function _generateBCapabilityOptions
150 {
151     local vdir=$1
152     local cap
153     local f="$vdir"/bcapabilities
154     
155     test -e "$f" || return 0
156     while read cap; do
157         case x"$cap" in
158             (x|x\#)     ;;
159             (*)         OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --bcap "$cap" );;
160         esac
161     done <"$f"
162 }
163
164 function _generateCapabilityOptions
165 {
166     local vdir=$1
167     local cap
168
169     _generateBCapabilityOptions "$vdir"
170     _generateCCapabilityOptions "$vdir"
171     
172     test -e "$vdir"/capabilities || return 0
173
174     CAP_OPTS=()
175     CAPCHROOT_OPTS=()
176
177     while read cap; do
178         case x"$cap" in
179             (x|x\#)     ;;
180             (!CAP_SYSCHROOT)
181                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
182                 CAPCHROOT_OPTS=( "${CAPCHROOT_OPTS[@]}" --nochroot )
183                 ;;
184             (*)
185                 CAP_OPTS=( "${CAP_OPTS[@]}" --cap "$cap" )
186                 ;;
187         esac
188     done <"$vdir"/capabilities
189 }
190
191 function getEnterShell
192 {
193     local vdir=$1
194     local shell_file
195
196     ENTER_SHELL=()
197
198     getFileValue ENTER_SHELL "$vdir"/shell "$__CONFDIR"/.defaults/shell
199     
200     test -n "$ENTER_SHELL" || {
201         local i
202         for i in "/bin/bash -login" "/bin/sh -l" /bin/csh; do
203             set -- $i
204             test -x "$vdir/vdir/$1" || continue
205             ENTER_SHELL=( "$@" )
206             break
207         done
208     }
209 }
210
211 ## Usage: sendKillSequence <ctx> <signal> [<wait> <signal>]*
212 function sendKillSequence
213 {
214     local ctx=$1
215     local wait=
216     shift
217
218     while isCtxRunning "$ctx"; do
219         test -z "$wait" || sleep "$wait"
220
221         killContext "$ctx" "$1"
222         test -n "$2" || break
223         wait="$2"
224         shift 2
225     done
226 }
227
228 function _generateInitOptions
229 {
230     local vdir=$1
231     local cfgdir=$vdir/apps/init
232     local i f
233
234     INITCMD_START=()
235     INITCMD_STOP=()
236     INITCMD_START_SYNC=()
237     INITCMD_STOP_SYNC=()
238     INITCMD_PREPARE=()
239     STOPCMD_PREPARE=()
240
241     INITKILL_SEQ=( 15 5 9 )
242     CHCONTEXT_INIT_OPTS=()
243
244
245     getFileValue INITSTYLE      "$cfgdir"/style
246     getFileValue RUNLEVEL_START "$cfgdir"/runlevel
247     getFileValue RUNLEVEL_START "$cfgdir"/runlevel.start
248     getFileValue RUNLEVEL_STOP  "$cfgdir"/runlevel.stop
249     getFileArray INITKILL_SEQ   "$cfgdir"/killseq || :
250
251     case x"$INITSTYLE" in
252         (xrescue)
253             INITCMD_START=( "${INITCMD_RESCUE[@]}" )
254             INITCMD_STOP=( /sbin/killall5 )
255             _IS_FAKEINIT=1
256             _NEED_VSHELPER_SYNC=
257             ;;
258             
259         (xsysv)
260             test -n "$RUNLEVEL_START" || RUNLEVEL_START=3
261             test -n "$RUNLEVEL_STOP"  || RUNLEVEL_STOP=6
262
263             for i in /etc/init.d/rc /etc/rc.d/rc; do
264                 test -x "$vdir/vdir/$i" || continue
265                 INITCMD_START=( "$i" "$RUNLEVEL_START" )
266                 INITCMD_STOP=(  "$i" "$RUNLEVEL_STOP"  )
267             done
268             INITCMD_PREPARE=( $_FAKE_RUNLEVEL "$RUNLEVEL_START" /var/run/utmp )
269             ;;
270             
271         (xplain)
272             INITCMD_START=( /sbin/init )
273             INITCMD_STOP=(  /sbin/init )
274             _IS_FAKEINIT=1
275             _NEED_VSHELPER_SYNC=1
276             test -z "$RUNLEVEL_START" || INITCMD_START=( "${INITCMD_START[@]}" "$RUNLEVEL_START" )
277             test -z "$RUNLEVEL_STOP"  || INITCMD_STOP=(  "${INITCMD_STOP[@]}"  "$RUNLEVEL_STOP"  )
278             ;;
279             
280         (xminit)
281             INITCMD_START=( /sbin/minit-start )
282             INITCMD_STOP=(  /sbin/minit-stop  )
283             _IS_FAKEINIT=1
284             INITCMD_START_SYNC=( "$_INITSYNC_MINIT_START" "$vdir" )
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             ! isNumber "${RUNLEVEL_START:-3}" || INITCMD_PREPARE=( $_FAKE_RUNLEVEL "${RUNLEVEL_START:-3}" /var/run/utmp )
289             ;;
290
291         (xgentoo)
292             INITCMD_START=( /sbin/rc default  )
293             INITCMD_STOP=(  /sbin/rc shutdown )
294             ;;
295
296         (x) ;;
297         (*) echo "Unknown init-style '$INITSTYLE'; aborting" >&2;
298             exit 1;;
299     esac
300
301     if test x"$INITSTYLE" != xrescue; then
302         getFileArray INITCMD_START      "$cfgdir"/cmd.start      || :
303         getFileArray INITCMD_STOP       "$cfgdir"/cmd.stop       || :
304         getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
305         getFileArray INITCMD_STOP_SYNC  "$cfgdir"/cmd.stop-sync  || :
306         getFileArray INITCMD_PREPARE    "$cfgdir"/cmd.prepare    || :
307     fi
308     
309     test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
310         INITCMD_START_SYNC=()
311         INITCMD_STOP_SYNC=()
312         _NEED_VSHELPER_SYNC=
313     }
314
315     if vshelper.isEnabled; then
316         vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
317     else
318         _NEED_VSHELPER_SYNC=
319     fi
320 }
321
322 function _generateFlagOptions
323 {
324     local vdir=$1
325
326     CHCONTEXT_FLAG_OPTS=()
327
328     test ! -e "$vdir"/flags || \
329     while read flag; do
330         case x"$flag" in
331             (x|x\#)             ;;
332             (xnamespace)        ;;
333             (xfakeinit)
334                 _IS_FAKEINIT=1
335                 ;;
336             (*)
337                 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
338                 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
339                                       --flag "$flag" )
340                 ;;
341         esac
342     done <"$vdir"/flags
343
344     isAvoidNamespace "$vdir" || {
345         USE_VNAMESPACE=1
346         CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
347     }
348 }
349
350 function _generateChcontextOptions
351 {
352     local vdir=$1
353     local ctx hostname domainname
354     local cap_opts
355     local flag
356
357     {
358         read ctx        <"$vdir"/context        || :
359         ## LEGACY ALERT
360         read hostname   <"$vdir"/uts/nodename   || read hostname   <"$vdir"/hostname   || :
361         read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
362     } 2>/dev/null
363
364     test -z "$S_CONTEXT" || ctx=$S_CONTEXT
365
366     _generateCapabilityOptions "$vdir"
367     _generateFlagOptions       "$vdir"
368
369     CHCONTEXT_OPTS=( $SILENT_OPT \
370                      "${CHCONTEXT_FLAG_OPTS[@]}" \
371                      "${CAP_OPTS[@]}" \
372                      --secure
373                      ${ctx:+--ctx "$ctx"} \
374                      ${hostname:+--hostname "$hostname"} \
375                      ${domainname:+--domainname "$domainname"} )
376
377     OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
378                            ${ctx:+--xid "$ctx"} )
379     ## put '--secure' at front so that it can be overridden
380     OPTS_VATTRIBUTE=( --secure "${OPTS_VATTRIBUTE[@]}" )
381 }
382
383 function _generateScheduleOptions
384 {
385     local vdir=$1
386     local f="$vdir"/schedule
387     test -e "$f" || return 0
388
389     local fill_rate interval tokens tokens_min tokens_max prio_bias
390     {
391         {
392             read fill_rate   && \
393             read interval    && \
394             read tokens      && \
395             read tokens_min  && \
396             read tokens_max  && \
397             read prio_bias   || prio_bias=
398         } <"$f"
399     } 2>/dev/null
400
401     test -n "$prio_bias" || {
402         echo $"Bad content in '$f'; aborting..." >&2
403         false
404     }
405
406     OPTS_VSCHED=( --fill-rate  "$fill_rate"  --interval "$interval" \
407                   --tokens     "$tokens"     --tokens_min "$tokens_min" \
408                   --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
409 }
410
411 function _getInterfaceValue
412 {
413     local _giv_val=$1
414     local _giv_dflt=$2
415     shift 2
416     
417     local _giv_i
418     local _giv_tmp
419
420     for _giv_i; do
421         read _giv_tmp  <"$_giv_i/$_giv_val" && break || :
422     done 2>/dev/null
423
424     : ${_giv_tmp:=$_giv_dflt}
425     eval $_giv_val=\$_giv_tmp
426 }
427
428 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
429 function _transformMask2Prefix
430 {
431     local _tm2p_tmp=$2
432     
433     test -n "$_tm2p_tmp" || {
434         $_MASK2PREFIX "$3" || _tm2p_tmp=$?
435     }
436
437     eval $1=\$_tm2p_tmp
438     return 0
439 }
440
441 function _addInterfaceCmd
442 {
443     eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
444     let ++INTERFACE_CMDS_IDX
445 }
446
447 ## Usage: _generateMac <var> <iface> <ctx>
448 function _generateMac
449 {
450     isNumber "$2" || {
451         echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
452         return 1
453     }
454
455     eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
456 }
457
458 ## Usage: _processSingleInterface <interface-directory>
459 function _processSingleInterface
460 {
461     local iface=$1
462
463     local ip
464     local dev
465     local prefix
466     local mask
467     local bcast
468     local name
469     local scope
470     local mac
471     local extip
472     local up="up"
473
474     _getInterfaceValue ip     '' "$iface"
475     _getInterfaceValue extip  '' "$iface" "$iface/.."
476     _getInterfaceValue dev    '' "$iface" "$iface/.."
477     _getInterfaceValue prefix '' "$iface" "$iface/.."
478     _getInterfaceValue mask   '' "$iface" "$iface/.."
479     _getInterfaceValue bcast  '' "$iface" "$iface/.."
480     _getInterfaceValue name   '' "$iface"
481     _getInterfaceValue scope  '' "$iface" "$iface/.."
482     _getInterfaceValue mac    '' "$iface"
483
484     test -n "$ip" || { echo $"Can not read ip for '$iface'"  >&2; return 1; }
485     test -n "$dev" -o -e "$iface"/nodev || {
486         echo $"No device specified for '$iface'" >&2
487         return 1;
488     }
489
490     test ! -e "$iface"/down || up=
491
492     while true; do
493         _transformMask2Prefix prefix "$prefix" "$mask"
494         INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
495
496         test ! -e "$iface"/nodev   || break
497         ## LEGACY ALERT
498         test ! -e "$iface"/only_ip || break
499
500         case "$dev" in
501             (*.*)
502                 test -d /proc/net/vlan || {
503                     echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers"  >&2
504                     return 1
505                 }
506                 test -f /proc/net/vlan || {
507                     _addInterfaceCmd VCONFIG ${dev/./ }
508                     _addInterfaceCmd IP_ADDR 127.0.0.1/8 broadcast 127.255.255.255 dev "$dev"
509                     _addInterfaceCmd IP_LINK "$dev" $up
510                 }
511                 ;;
512         esac
513
514         if ! test -e "$iface"/indirect; then
515             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} ${name:+label "$dev:$name"} dev "$dev"
516             #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
517             _addInterfaceCmd IP_LINK  "$dev" $up
518         elif ! test -n "$ctx"; then
519             echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
520             return 1
521         else
522             test -z "$mac" || _generateMac mac "$(basename $iface)" "$ctx" || return 1
523             _addInterfaceCmd MODPROBE dummy "$dev"
524             _addInterfaceCmd IP_LINK  dev dummy0 address "$mac"
525             _addInterfaceCmd NAMEIF   "$dev" "$mac"
526             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" dev "$dev"
527             test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$ctx" "$extip"
528         fi
529
530         break
531     done
532 }
533
534 ## Usage: _generateInterfaceOptions <vserver-directory>
535 function _generateInterfaceOptions
536 {
537     local iface
538     local ctx
539
540     test ! -e "$1"/context || read ctx <"$1"/context
541
542     for iface in "$1/interfaces/"*; do
543         test   -d "$iface"          || continue
544         test ! -e "$iface"/disabled || continue
545     
546         _processSingleInterface "$iface"
547     done
548     _HAVE_INTERFACE_OPTIONS=1
549 }
550
551 function enableInterfaces
552 {
553     local i=0
554     declare -a var
555
556     lock "$__LOCKDIR"/vserver.interfaces
557
558     while test $i -lt $INTERFACE_CMDS_IDX; do
559         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
560         local type=${var[0]}
561         unset var[0]
562
563         set -- "${var[@]}"
564         case "$type" in
565             IPTABLES)   ;; ## TODO
566             MODPROBE)
567                 local mod=$1
568                 local name=$2
569                 shift 2
570                 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
571                 ;;
572             NAMEIF)             $_NAMEIF "$@";;
573             VCONFIG)            $_VCONFIG  add   "$@";;
574             IP_ADDR)            $_IP addr  add   "$@";;
575             IP_ADDR_FLUSH)      $_IP addr  flush "$@";;
576             IP_LINK)            $_IP link  set   "$@";;
577             IP_ROUTE)           $_IP route add   "$@";;
578             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
579         esac
580
581         let ++i
582     done
583
584     unlock 1
585 }
586
587 function disableInterfaces
588 {
589     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
590
591     local i=$INTERFACE_CMDS_IDX
592     declare -a var
593
594     lock "$__LOCKDIR"/vserver.interfaces
595     
596     while test $i -gt 0; do
597         let --i || :
598
599         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
600         local type=${var[0]}
601         unset var[0]
602         
603         set -- "${var[@]}"
604         case "$type" in
605             IPTABLES)           ;; ## TODO
606             MODPROBE)           $_RMMOD "${2:-$1}";;
607             NAMEIF)             ;;
608             VCONFIG)            $_VCONFIG  rem "$@";;
609             IP_ADDR)            $_IP addr  del "$@";;
610             IP_ADDR_FLUSH)      ;;
611             IP_LINK)            ;; ## Ignore the link-down command for now
612             IP_ROUTE)           $_IP route del "$@";;
613             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
614         esac
615     done
616
617     unlock 1
618 }
619
620 ## Usage: prepareInit <vserver-directory>
621 function prepareInit
622 {
623     pushd "$1/vdir" >/dev/null
624     case "$INITSTYLE" in
625         sysv)
626             { find var/run  ! -type d -print0; \
627               find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
628             ;;
629         plain)
630             $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
631             : | $_CHROOT_SH truncate fastboot  2>/dev/null || :
632             ;;
633         minit)
634             ;;
635     esac
636     "${INITCMD_PREPARE[@]}"
637     popd >/dev/null
638 }
639
640 ## Usage: prepareInit <vserver-directory>
641 function prepareStop
642 {
643     pushd "$1/vdir" >/dev/null
644     case "$INITSTYLE" in
645         (sysv)
646             export PREVLEVEL=$RUNLEVEL_START # required by Debian's initscripts
647             ;;
648     esac
649     "${STOPCMD_PREPARE[@]}"
650     popd >/dev/null
651 }
652
653
654 function generateOptions
655 {
656     _generateInterfaceOptions   "$1"
657     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1" 
658     _generateNiceCommand        "$1"
659     _generateInitOptions        "$1"
660     _generateChcontextOptions   "$1"
661     _generateScheduleOptions    "$1"
662     _generatePersonalityOptions "$1"
663
664     if test -n "$_IS_FAKEINIT"; then
665         CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
666         OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
667     fi
668 }
669
670 function _mountVserverInternal
671 {
672     local fstab="$1"
673     test -e "$fstab" || return 0
674     shift
675
676     pushd "$vdir" >/dev/null
677     "$@" $_SECURE_MOUNT -a --chroot --fstab "$fstab" --rootfs no
678     popd >/dev/null
679 }
680
681 function mountRootFS
682 {
683     local cfgdir=$1
684     local vdir=$1/vdir
685     local fstab="$cfgdir"/fstab
686
687     test -e "$fstab" || return 0
688     pushd "$vdir" >/dev/null
689     $_SECURE_MOUNT -a --chroot --fstab "$fstab" --rootfs only -n
690     popd >/dev/null
691 }
692
693 function mountVserver
694 {
695     local cfgdir=$1
696     local ns_opt=$2
697     local vdir=$1/vdir
698     local mtab_src
699
700     test -e "$cfgdir"/fstab -o \
701          -e "$cfgdir"/fstab.local -o \
702          -e "$cfgdir"/fstab.remote || return 0
703
704     findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
705     
706     pushd "$vdir" >/dev/null
707     $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
708     popd >/dev/null
709
710     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
711
712     test -z "$NAMESPACE_CLEANUP" || isAvoidNamespace "$cfgdir" || \
713         $_VNAMESPACE --cleanup
714
715     _mountVserverInternal "$cfgdir"/fstab
716     _mountVserverInternal "$cfgdir"/fstab.local
717     _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}"
718
719     isAvoidNamespace "$cfgdir" || \
720         $_SECURE_MOUNT --rbind -n "$vdir" "/"
721 }
722
723 function _umountVserverInternal
724 {
725     local fstab="$1"
726     test -e "$fstab" || return 0
727     shift
728
729     $_TAC "$fstab" | {
730         is_ok=1
731         while read src dst tmp; do
732             test -n "$tmp" || continue
733             case x"$src" in
734                 (x\#*)  continue;;
735             esac
736
737         
738             "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
739         done
740         test -n "$is_ok"
741     }
742 }
743
744 function umountVserver
745 {
746     local cfgdir=$1
747     local vdir=$1/vdir
748     local is_ok=1
749
750     isAvoidNamespace "$cfgdir"    || return 0
751     test -e "$cfgdir"/fstab -o \
752          -e "$cfgdir"/fstab.local || return 0
753     test -n "$_HAVE_CHBIND_OPTIONS"  || _generateChbindOptions "$cfgdir"
754     
755     pushd "$vdir/" >/dev/null || return 1
756         _umountVserverInternal  "$cfgdir"/fstab.local                              || is_ok=
757         _umountVserverInternal  "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
758     popd >/dev/null           || return 1
759
760     test -n "$is_ok"
761 }
762
763 ## Usage: waitForSync <vserver> <vshelper-fifo-varname>
764 function initSync
765 {
766     local _is_meth=sync
767     test -n "$_NEED_VSHELPER_SYNC" || _is_meth=async
768
769     vshelper.initSync "$1" "$2" "$_is_meth"
770 }
771
772 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
773 function initWait
774 {
775     if $_VSERVER_INFO - FEATURE vwait; then
776         local _is_tmpdir
777         _is_tmpdir=$($_MKTEMPDIR /tmp/vwaitstat.XXXXXX)
778             
779         $_NOHUP $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
780             --terminate --status-fd 3 "$2"  \
781             >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo &
782
783         echo "$!" >$_is_tmpdir/pid
784         eval "$4"=$_is_tmpdir
785     fi
786 }
787
788
789 ## Usage: _waitForVWait <fifo> <pid>
790 function _waitForVWait
791 {
792     declare -a status
793     getFileArray status "$1"
794     wait "$2" || :
795     set -- ${status[0]}
796
797     case "$1" in
798         (ERROR)         warning $"\
799 'vwait' exited with error '$2' which indicates that vserver could not
800 be stopped properly"
801                         ;;
802         (FINISHED)      ;;
803         (KILLED)        warning $"\
804 A timeout occured while waiting for the vserver to finish and it was
805 killed by sending a SIGKILL signal. Please investigate the reasons
806 and/or increase the timeout in apps/vshelper/sync-timeout."
807                         ;;
808         (TIMEOUT|\?\?\?|*)      warning $"\
809 internal error: 'vwait' exited with an unexpected status; I will try
810 to continue but be prepared for unexpected events."
811                         ;;
812     esac
813
814     return 0
815 }
816
817 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
818 function waitForSync
819 {
820     local cfgdir=$1
821     local fifo=$2
822     local vwait_statdir=$3
823     local vwait_pid=$4
824
825     if test -d "$vwait_statdir"; then
826         _waitForVWait "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )"
827     elif test -n "$_NEED_VSHELPER_SYNC"; then
828         $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
829             warning $"\
830 A timeout or other error occured while waiting for the synchronization
831 signal from vserver '$VSERVER_NAME'.
832 The vserver will be killed nevertheless..."
833     elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
834         "${INITCMD_STOP_SYNC[@]}" || \
835             warning $"\
836 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
837 will be killed nevertheless..."
838     fi
839
840     test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
841         sleep 1
842 }
843
844 function _sourceWrap
845 {
846     local vdir name flavor start i already_handled base
847     . "$@"
848 }
849
850 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
851 function execScriptlets
852 {
853     declare -r vdir=$1
854     declare -r name=$2
855     declare -r flavor=$3
856     local base i
857
858     for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
859         local   DONT_SKIP_DEFAULTS=
860         local   already_handled=
861         
862         for i in "$base/$flavor" "$base/$flavor.d"/*; do
863             isRegularFile "$i" || continue
864             test  -r "$i"      || continue
865
866             already_handled=1
867             local start=
868             test -x "$i" || start=_sourceWrap
869             $start "$i" "$flavor" "$name"
870         done
871
872         test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
873     done
874 }
875
876
877 function sanityCheck
878 {
879     declare -r cfgdir=$1
880
881     ! test -e "$cfgdir"/fstab.local ||
882         warning $"\
883 WARNING: 'fstab' will *not* be executed in the network context of the
884   vserver anymore. Therefore, 'fstab.local' has the same functionality
885   and is obsoleted. When you need the old behaviour, put the mounts
886   into 'fstab.remote'"
887
888     ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
889         warning $"\
890 WARNING: The hostname is now configured in 'uts/nodename' but not in
891   'hostname'."
892
893     ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
894         warning $"\
895 WARNING: The domainname is now configured in 'uts/domainname' but not
896   in 'domainname'." >&2
897
898   
899     local i
900     for i in "$cfgdir"/interfaces/*/only_ip; do
901         if test -e "$i"; then
902             local iface
903             iface=${i##$cfgdir/interfaces/}
904             iface=${iface%%/only_ip}
905             warning $"\
906 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
907   'nodev' instead of"
908         fi
909     done
910
911     find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
912
913     vshelper.doSanityCheck
914
915     $_VSERVER_INFO - VERIFYCAP ||
916         panic $"capabilities are not enabled in kernel-setup"
917
918     $_VSERVER_INFO - VERIFYPROC ||
919         panic $"\
920 /proc/uptime can not be accessed. Usually, this is caused by
921 procfs-security. Please read the FAQ for more details
922 http://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ"
923 }