afb1fd711e83eddf6bd9ccde55167c16bc5724fc
[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             rc=$?
816
817             if test "$rc" -ne 0 -a "$rc" -ne 1; then
818                 $_VPS axf | $_EGREP -e "^[^ \t]+[ \t]+$S_CONTEXT[ \t]+" >&4
819                 killContext "$S_CONTEXT" 9
820             fi
821
822             exit $rc
823         ) 4>$_is_tmpdir/procs &
824             
825         echo "$!" >$_is_tmpdir/pid
826         eval "$3"=$_is_tmpdir
827     fi </dev/null
828 }
829
830
831 ## Usage: _waitForVWait <vserver> <fifo> <pid> <procs>
832 function _waitForVWait
833 {
834     wait "$3" || :
835
836     declare -a status
837     declare -r procs=$(cat $4)
838
839     getFileArray status "$2"
840     set -- ${status[0]}
841
842     case "$1" in
843         (ERROR)         warning $"\
844 'vwait' exited with error '$2' which indicates that vserver could not
845 be stopped properly"
846                         ;;
847         (FINISHED)      ;;
848         (KILLED)        warning $"\
849 A timeout occured while waiting for the vserver to finish and it was
850 killed by sending a SIGKILL signal. Please investigate the reasons
851 and/or increase the timeout in apps/vshelper/sync-timeout."
852                         ;;
853
854         (TIMEOUT)       warning $"\
855 A timeout occured while waiting for the vserver to finish and it will
856 be killed by sending a SIGKILL signal. The following process list
857 might be useful for finding out the reason of this behavior:
858
859 ----------------------------------------------------------------------
860 ${procs:+$procs
861 }----------------------------------------------------------------------"
862                         ;;
863
864         (\?\?\?|*)      warning $"\
865 internal error: 'vwait' exited with an unexpected status '$1'; I will
866 try to continue but be prepared for unexpected events."
867                     ;;
868     esac
869
870     return 0
871 }
872
873 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
874 function waitForSync
875 {
876     local cfgdir=$1
877     local fifo=$2
878     local vwait_statdir=$3
879     local vwait_pid=$4
880
881     if test -d "$vwait_statdir"; then
882         _waitForVWait "$cfgdir" "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )" "$vwait_statdir/procs"
883     elif test -n "$_NEED_VSHELPER_SYNC"; then
884         $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
885             warning $"\
886 A timeout or other error occured while waiting for the synchronization
887 signal from vserver '$VSERVER_NAME'.
888 The vserver will be killed nevertheless..."
889     elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
890         "${INITCMD_STOP_SYNC[@]}" || \
891             warning $"\
892 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
893 will be killed nevertheless..."
894     fi
895
896     test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
897         sleep 1
898 }
899
900 function _sourceWrap
901 {
902     local vdir name flavor start i already_handled base
903     . "$@"
904 }
905
906 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
907 function execScriptlets
908 {
909     declare -r vdir=$1
910     declare -r name=$2
911     declare -r flavor=$3
912     local base i
913
914     for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
915         local   DONT_SKIP_DEFAULTS=
916         local   already_handled=
917         
918         for i in "$base/$flavor" "$base/$flavor.d"/*; do
919             isRegularFile "$i" || continue
920             test  -r "$i"      || continue
921
922             already_handled=1
923             local start=
924             test -x "$i" || start=_sourceWrap
925             $start "$i" "$flavor" "$name"
926         done
927
928         test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
929     done
930 }
931
932
933 function sanityCheck
934 {
935     declare -r cfgdir=$1
936
937     ! test -e "$cfgdir"/fstab.local ||
938         warning $"\
939 WARNING: 'fstab' will *not* be executed in the network context of the
940   vserver anymore. Therefore, 'fstab.local' has the same functionality
941   and is obsoleted. When you need the old behaviour, put the mounts
942   into 'fstab.remote'"
943
944     ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
945         warning $"\
946 WARNING: The hostname is now configured in 'uts/nodename' but not in
947   'hostname'."
948
949     ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
950         warning $"\
951 WARNING: The domainname is now configured in 'uts/domainname' but not
952   in 'domainname'." >&2
953
954   
955     local i
956     for i in "$cfgdir"/interfaces/*/only_ip; do
957         if test -e "$i"; then
958             local iface
959             iface=${i##$cfgdir/interfaces/}
960             iface=${iface%%/only_ip}
961             warning $"\
962 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
963   'nodev' instead of"
964         fi
965     done
966     
967     find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
968
969     vshelper.doSanityCheck
970
971     $_VSERVER_INFO - VERIFYCAP ||
972         panic $"capabilities are not enabled in kernel-setup"
973
974     $_VSERVER_INFO - VERIFYPROC ||
975         panic $"\
976 /proc/uptime can not be accessed. Usually, this is caused by
977 procfs-security. Please read the FAQ for more details
978 http://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ"
979 }