6b7bf4553c9e66c688495f49c4a88f0d218c5709
[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         (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
298     esac
299
300     if test x"$INITSTYLE" != xrescue; then
301         getFileArray INITCMD_START      "$cfgdir"/cmd.start      || :
302         getFileArray INITCMD_STOP       "$cfgdir"/cmd.stop       || :
303         getFileArray INITCMD_START_SYNC "$cfgdir"/cmd.start-sync || :
304         getFileArray INITCMD_STOP_SYNC  "$cfgdir"/cmd.stop-sync  || :
305         getFileArray INITCMD_PREPARE    "$cfgdir"/cmd.prepare    || :
306     fi
307     
308     test -n "$OPTION_FORCE_SYNC" -o -e "$cfgdir"/sync || {
309         INITCMD_START_SYNC=()
310         INITCMD_STOP_SYNC=()
311         _NEED_VSHELPER_SYNC=
312     }
313
314     if vshelper.isEnabled; then
315         vshelper.getSyncTimeout "$vdir" VSHELPER_SYNC_TIMEOUT || :
316     else
317         _NEED_VSHELPER_SYNC=
318     fi
319 }
320
321 function _generateFlagOptions
322 {
323     local vdir=$1
324
325     CHCONTEXT_FLAG_OPTS=()
326
327     test ! -e "$vdir"/flags || \
328     while read flag; do
329         case x"$flag" in
330             (x|x\#*)            ;;
331             (xnamespace)        ;;
332             (xfakeinit)
333                 _IS_FAKEINIT=1
334                 ;;
335             (*)
336                 OPTS_VATTRIBUTE=( "${OPTS_VATTRIBUTE[@]}" --flag "$flag" )
337                 CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}"
338                                       --flag "$flag" )
339                 ;;
340         esac
341     done <"$vdir"/flags
342
343     isAvoidNamespace "$vdir" || {
344         USE_VNAMESPACE=1
345         CHCONTEXT_FLAG_OPTS=( "${CHCONTEXT_FLAG_OPTS[@]}" --flag namespace )
346     }
347 }
348
349 function _generateChcontextOptions
350 {
351     local vdir=$1
352     local ctx hostname domainname
353     local cap_opts
354     local flag
355
356     {
357         read ctx        <"$vdir"/context        || :
358         ## LEGACY ALERT
359         read hostname   <"$vdir"/uts/nodename   || read hostname   <"$vdir"/hostname   || :
360         read domainname <"$vdir"/uts/domainname || read domainname <"$vdir"/domainname || :
361     } 2>/dev/null
362
363     test -z "$S_CONTEXT" || ctx=$S_CONTEXT
364
365     _generateCapabilityOptions "$vdir"
366     _generateFlagOptions       "$vdir"
367
368     CHCONTEXT_OPTS=( $SILENT_OPT \
369                      "${CHCONTEXT_FLAG_OPTS[@]}" \
370                      "${CAP_OPTS[@]}" \
371                      --secure
372                      ${ctx:+--ctx "$ctx"} \
373                      ${hostname:+--hostname "$hostname"} \
374                      ${domainname:+--domainname "$domainname"} )
375
376     OPTS_VCONTEXT_CREATE=( $SILENT_OPT \
377                            ${ctx:+--xid "$ctx"} )
378     ## put '--secure' at front so that it can be overridden
379     OPTS_VATTRIBUTE=( --secure "${OPTS_VATTRIBUTE[@]}" )
380 }
381
382 function _generateScheduleOptions
383 {
384     local vdir=$1
385     local f="$vdir"/schedule
386     test -e "$f" || return 0
387
388     local fill_rate interval tokens tokens_min tokens_max prio_bias
389     {
390         {
391             read fill_rate   && \
392             read interval    && \
393             read tokens      && \
394             read tokens_min  && \
395             read tokens_max  && \
396             read prio_bias   || prio_bias=
397         } <"$f"
398     } 2>/dev/null
399
400     test -n "$prio_bias" || {
401         echo $"Bad content in '$f'; aborting..." >&2
402         false
403     }
404
405     OPTS_VSCHED=( --fill-rate  "$fill_rate"  --interval "$interval" \
406                   --tokens     "$tokens"     --tokens_min "$tokens_min" \
407                   --tokens_max "$tokens_max" --priority-bias "$prio_bias" )
408 }
409
410 function _getInterfaceValue
411 {
412     local _giv_val=$1
413     local _giv_dflt=$2
414     shift 2
415     
416     local _giv_i
417     local _giv_tmp
418
419     for _giv_i; do
420         read _giv_tmp  <"$_giv_i/$_giv_val" && break || :
421     done 2>/dev/null
422
423     : ${_giv_tmp:=$_giv_dflt}
424     eval $_giv_val=\$_giv_tmp
425 }
426
427 ## Usage: _transformMask2Prefix <result-varname> <prefix> <mask>
428 function _transformMask2Prefix
429 {
430     local _tm2p_tmp=$2
431     
432     test -n "$_tm2p_tmp" || {
433         $_MASK2PREFIX "$3" || _tm2p_tmp=$?
434     }
435
436     eval $1=\$_tm2p_tmp
437     return 0
438 }
439
440 function _addInterfaceCmd
441 {
442     eval INTERFACE_CMDS_${INTERFACE_CMDS_IDX}='( "$@" )'
443     let ++INTERFACE_CMDS_IDX
444 }
445
446 ## Usage: _generateMac <var> <iface> <ctx>
447 function _generateMac
448 {
449     isNumber "$2" || {
450         echo $"Interface basename '$iface' must be either a number, or the mac must be configured explicitly" >&2
451         return 1
452     }
453
454     eval $1=$(printf "f0:ff:%02x:%02x:%02x:%02x" $[ (~($2>>8)) & 0xff ] $[ ($2 & 0xff) ] $[ ($3>>8) & 0xff ] $[ $3 & 0xff ])
455 }
456
457 function _getVLANInfo
458 {
459     case "$1" in
460         (vlan????)
461             panic "\
462 creation of VLAN_PLUS_VID devices is not supported; please create them
463 before starting the vserver and use the 'nodev' flag then"
464             echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
465             ;;
466         (vlan*)
467             panic "\
468 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
469 create them before starting the vserver and use the 'nodev' flag then"
470             echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
471             ;;
472         (*.????)        echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
473         (*.*)           echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
474         (*)             return 1
475     esac
476
477     return 0
478 }
479
480 ## Usage: _processSingleInterface <interface-directory>
481 function _processSingleInterface
482 {
483     local iface=$1
484
485     local ip
486     local dev
487     local prefix
488     local mask
489     local bcast
490     local name
491     local scope
492     local mac
493     local extip
494     local up="up"
495
496     _getInterfaceValue ip     '' "$iface"
497     _getInterfaceValue extip  '' "$iface" "$iface/.."
498     _getInterfaceValue dev    '' "$iface" "$iface/.."
499     _getInterfaceValue prefix '' "$iface" "$iface/.."
500     _getInterfaceValue mask   '' "$iface" "$iface/.."
501     _getInterfaceValue bcast  '' "$iface" "$iface/.."
502     _getInterfaceValue name   '' "$iface"
503     _getInterfaceValue scope  '' "$iface" "$iface/.."
504     _getInterfaceValue mac    '' "$iface"
505
506     test -n "$ip" || { echo $"Can not read ip for '$iface'"  >&2; return 1; }
507     test -n "$dev" -o -e "$iface"/nodev || {
508         echo $"No device specified for '$iface'" >&2
509         return 1;
510     }
511
512     test ! -e "$iface"/down || up=
513
514     while true; do
515         _transformMask2Prefix prefix "$prefix" "$mask"
516         INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
517
518         test ! -e "$iface"/nodev   || break
519         ## LEGACY ALERT
520         test ! -e "$iface"/only_ip || break
521
522         local vlan_info
523         if vlan_info=$(_getVLANInfo "$dev"); then
524             test -d /proc/net/vlan || {
525                 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers"  >&2
526                 return 1
527             }
528             test -f /proc/net/vlan || {
529                 _addInterfaceCmd VCONFIG $vlan_info
530             }
531         fi
532
533         if ! test -e "$iface"/indirect; then
534             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} ${name:+label "$dev:$name"} dev "$dev"
535             #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
536             _addInterfaceCmd IP_LINK  "$dev" $up
537         elif ! test -n "$ctx"; then
538             echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
539             return 1
540         else
541             test -z "$mac" || _generateMac mac "$(basename $iface)" "$ctx" || return 1
542             _addInterfaceCmd MODPROBE dummy "$dev"
543             _addInterfaceCmd IP_LINK  dev dummy0 address "$mac"
544             _addInterfaceCmd NAMEIF   "$dev" "$mac"
545             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" dev "$dev"
546             test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$ctx" "$extip"
547         fi
548
549         break
550     done
551 }
552
553 ## Usage: _generateInterfaceOptions <vserver-directory>
554 function _generateInterfaceOptions
555 {
556     local iface
557     local ctx
558
559     test ! -e "$1"/context || read ctx <"$1"/context
560
561     for iface in "$1/interfaces/"*; do
562         test   -d "$iface"          || continue
563         test ! -e "$iface"/disabled || continue
564     
565         _processSingleInterface "$iface"
566     done
567     _HAVE_INTERFACE_OPTIONS=1
568 }
569
570 function enableInterfaces
571 {
572     local i=0
573     declare -a var
574
575     lock "$__LOCKDIR"/vserver.interfaces
576
577     while test $i -lt $INTERFACE_CMDS_IDX; do
578         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
579         local type=${var[0]}
580         unset var[0]
581
582         set -- "${var[@]}"
583         case "$type" in
584             IPTABLES)   ;; ## TODO
585             MODPROBE)
586                 local mod=$1
587                 local name=$2
588                 shift 2
589                 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
590                 ;;
591             NAMEIF)             $_NAMEIF   "$@";;
592             VCONFIG)            $_VCONFIG  set_name_type "$4"      >/dev/null
593                                 $_VCONFIG  add           "$2" "$3" >/dev/null;;
594             IP_ADDR)            $_IP addr  add   "$@";;
595             IP_ADDR_FLUSH)      $_IP addr  flush "$@";;
596             IP_LINK)            $_IP link  set   "$@";;
597             IP_ROUTE)           $_IP route add   "$@";;
598             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
599         esac
600
601         let ++i
602     done
603
604     unlock 1
605 }
606
607 function disableInterfaces
608 {
609     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
610
611     local i=$INTERFACE_CMDS_IDX
612     declare -a var
613
614     lock "$__LOCKDIR"/vserver.interfaces
615     
616     while test $i -gt 0; do
617         let --i || :
618
619         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
620         local type=${var[0]}
621         unset var[0]
622         
623         set -- "${var[@]}"
624         case "$type" in
625             IPTABLES)           ;; ## TODO
626             MODPROBE)           $_RMMOD "${2:-$1}";;
627             NAMEIF)             ;;
628             VCONFIG)            $_VCONFIG  rem "$2.$3" >/dev/null;;
629             IP_ADDR)            $_IP addr  del "$@";;
630             IP_ADDR_FLUSH)      ;;
631             IP_LINK)            ;; ## Ignore the link-down command for now
632             IP_ROUTE)           $_IP route del "$@";;
633             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
634         esac
635     done
636
637     unlock 1
638 }
639
640 ## Usage: prepareInit <vserver-directory>
641 function prepareInit
642 {
643     pushd "$1/vdir" >/dev/null
644     case "$INITSTYLE" in
645         sysv)
646             { find var/run  ! -type d -print0; \
647               find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
648             ;;
649         plain)
650             $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
651             : | $_CHROOT_SH truncate fastboot  2>/dev/null || :
652             ;;
653         minit)
654             ;;
655     esac
656     "${INITCMD_PREPARE[@]}"
657     popd >/dev/null
658 }
659
660 ## Usage: prepareInit <vserver-directory>
661 function prepareStop
662 {
663     pushd "$1/vdir" >/dev/null
664     case "$INITSTYLE" in
665         (sysv)
666             export PREVLEVEL=$RUNLEVEL_START # required by Debian's initscripts
667             ;;
668     esac
669     "${STOPCMD_PREPARE[@]}"
670     popd >/dev/null
671 }
672
673
674 function generateOptions
675 {
676     _generateInterfaceOptions   "$1"
677     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1" 
678     _generateNiceCommand        "$1"
679     _generateInitOptions        "$1"
680     _generateChcontextOptions   "$1"
681     _generateScheduleOptions    "$1"
682     _generatePersonalityOptions "$1"
683
684     if test -n "$_IS_FAKEINIT"; then
685         CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
686         OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
687     fi
688 }
689
690 function _mountVserverInternal
691 {
692     local fstab="$1"
693     local xflag=
694     
695     test -e "$fstab" || return 0
696     shift
697
698     pushd "$vdir" >/dev/null
699     # check whether / is mounted readonly or whether there is special
700     # magic regarding the mtab file; when etc/mtab can not be touched,
701     # add the '-n' flag to mount
702     test -w etc -o -w etc/mtab || xflag=-n
703     "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
704     popd >/dev/null
705 }
706
707 function mountRootFS
708 {
709     local cfgdir=$1
710     local vdir=$1/vdir
711     local fstab="$cfgdir"/fstab
712     local xflag=
713
714     test -e "$fstab" || return 0
715     pushd "$vdir" >/dev/null
716     # check whether / is mounted readonly or whether there is special
717     # magic regarding the mtab file; when etc/mtab can not be touched,
718     # add the '-n' flag to mount
719     test -w etc -o -w etc/mtab || xflag=-n
720     $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
721     popd >/dev/null
722 }
723
724 function mountVserver
725 {
726     local cfgdir=$1
727     local ns_opt=$2
728     local vdir=$1/vdir
729     local mtab_src
730
731     test -e "$cfgdir"/fstab -o \
732          -e "$cfgdir"/fstab.local -o \
733          -e "$cfgdir"/fstab.remote || return 0
734
735     findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
736     
737     pushd "$vdir" >/dev/null
738     $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
739     popd >/dev/null
740
741     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
742
743     test -z "$NAMESPACE_CLEANUP" || isAvoidNamespace "$cfgdir" || \
744         $_VNAMESPACE --cleanup
745
746     _mountVserverInternal "$cfgdir"/fstab
747     _mountVserverInternal "$cfgdir"/fstab.local
748     _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}"
749
750     isAvoidNamespace "$cfgdir" || \
751         $_SECURE_MOUNT --rbind -n "$vdir" "/"
752 }
753
754 function _umountVserverInternal
755 {
756     local fstab="$1"
757     test -e "$fstab" || return 0
758     shift
759
760     $_TAC "$fstab" | {
761         is_ok=1
762         while read src dst tmp; do
763             test -n "$tmp" || continue
764             case x"$src" in
765                 (x\#*)  continue;;
766             esac
767
768         
769             "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
770         done
771         test -n "$is_ok"
772     }
773 }
774
775 function umountVserver
776 {
777     local cfgdir=$1
778     local vdir=$1/vdir
779     local is_ok=1
780
781     isAvoidNamespace "$cfgdir"    || return 0
782     test -e "$cfgdir"/fstab -o \
783          -e "$cfgdir"/fstab.local || return 0
784     test -n "$_HAVE_CHBIND_OPTIONS"  || _generateChbindOptions "$cfgdir"
785     
786     pushd "$vdir/" >/dev/null || return 1
787         _umountVserverInternal  "$cfgdir"/fstab.local                              || is_ok=
788         _umountVserverInternal  "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
789     popd >/dev/null           || return 1
790
791     test -n "$is_ok"
792 }
793
794 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
795 function initSync
796 {
797     local _is_meth=sync
798     test -n "$_NEED_VSHELPER_SYNC" && \
799         ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
800
801     vshelper.initSync "$1" "$3" "$_is_meth"
802 }
803
804 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
805 function initWait
806 {
807     if $_VSERVER_INFO - FEATURE vwait; then
808         local _is_tmpdir
809         _is_tmpdir=$($_MKTEMPDIR /tmp/vwaitstat.XXXXXX)
810
811         (
812             $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
813                 --status-fd 3 "$2" \
814                 >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo
815
816             $_VPS axf | $_EGREP -e "^[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
817
818             killContext "$S_CONTEXT" 9
819         ) 4>$_is_tmpdir/procs &
820             
821         echo "$!" >$_is_tmpdir/pid
822         eval "$3"=$_is_tmpdir
823     fi </dev/null
824 }
825
826
827 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
828 function _waitForVWait
829 {
830     declare -a status
831     declare -r procs=$4
832
833     wait "$3" || :
834     getFileArray status "$2"
835     set -- ${status[0]}
836
837     case "$1" in
838         (ERROR)         warning $"\
839 'vwait' exited with error '$2' which indicates that vserver could not
840 be stopped properly"
841                         ;;
842         (FINISHED)      ;;
843         (KILLED)        warning $"\
844 A timeout occured while waiting for the vserver to finish and it was
845 killed by sending a SIGKILL signal. Please investigate the reasons
846 and/or increase the timeout in apps/vshelper/sync-timeout."
847                         ;;
848
849         (TIMEOUT)       warning $"\
850 A timeout occured while waiting for the vserver to finish and it will
851 be killed by sending a SIGKILL signal. The following process list
852 might be useful for finding out the reason of this behavior:
853
854 $procs
855 "
856                         ;;
857
858         (\?\?\?|*)      warning $"\
859 internal error: 'vwait' exited with an unexpected status '$1'; I will
860 try to continue but be prepared for unexpected events."
861                     ;;
862     esac
863
864     return 0
865 }
866
867 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
868 function waitForSync
869 {
870     local cfgdir=$1
871     local fifo=$2
872     local vwait_statdir=$3
873     local vwait_pid=$4
874
875     if test -d "$vwait_statdir"; then
876         _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$( < $vwait_statdir/procs )"
877     elif test -n "$_NEED_VSHELPER_SYNC"; then
878         $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
879             warning $"\
880 A timeout or other error occured while waiting for the synchronization
881 signal from vserver '$VSERVER_NAME'.
882 The vserver will be killed nevertheless..."
883     elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
884         "${INITCMD_STOP_SYNC[@]}" || \
885             warning $"\
886 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
887 will be killed nevertheless..."
888     fi
889
890     test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
891         sleep 1
892 }
893
894 function _sourceWrap
895 {
896     local vdir name flavor start i already_handled base
897     . "$@"
898 }
899
900 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
901 function execScriptlets
902 {
903     declare -r vdir=$1
904     declare -r name=$2
905     declare -r flavor=$3
906     local base i
907
908     for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
909         local   DONT_SKIP_DEFAULTS=
910         local   already_handled=
911         
912         for i in "$base/$flavor" "$base/$flavor.d"/*; do
913             isRegularFile "$i" || continue
914             test  -r "$i"      || continue
915
916             already_handled=1
917             local start=
918             test -x "$i" || start=_sourceWrap
919             $start "$i" "$flavor" "$name"
920         done
921
922         test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
923     done
924 }
925
926
927 function sanityCheck
928 {
929     declare -r cfgdir=$1
930
931     ! test -e "$cfgdir"/fstab.local ||
932         warning $"\
933 WARNING: 'fstab' will *not* be executed in the network context of the
934   vserver anymore. Therefore, 'fstab.local' has the same functionality
935   and is obsoleted. When you need the old behaviour, put the mounts
936   into 'fstab.remote'"
937
938     ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
939         warning $"\
940 WARNING: The hostname is now configured in 'uts/nodename' but not in
941   'hostname'."
942
943     ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
944         warning $"\
945 WARNING: The domainname is now configured in 'uts/domainname' but not
946   in 'domainname'." >&2
947
948   
949     local i
950     for i in "$cfgdir"/interfaces/*/only_ip; do
951         if test -e "$i"; then
952             local iface
953             iface=${i##$cfgdir/interfaces/}
954             iface=${iface%%/only_ip}
955             warning $"\
956 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
957   'nodev' instead of"
958         fi
959     done
960     
961     find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
962
963     vshelper.doSanityCheck
964
965     $_VSERVER_INFO - VERIFYCAP ||
966         panic $"capabilities are not enabled in kernel-setup"
967
968     $_VSERVER_INFO - VERIFYPROC ||
969         panic $"\
970 /proc/uptime can not be accessed. Usually, this is caused by
971 procfs-security. Please read the FAQ for more details
972 http://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ"
973 }