0139d581f351b69883bdcb577f32b616a959efa2
[util-vserver.git] / scripts / vserver.functions
1 # $Id: vserver.functions,v 1.57 2005/07/03 17:47:06 ensc Exp $  --*- 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     local xflag=
674     
675     test -e "$fstab" || return 0
676     shift
677
678     pushd "$vdir" >/dev/null
679     # check whether / is mounted readonly or whether there is special
680     # magic regarding the mtab file; when etc/mtab can not be touched,
681     # add the '-n' flag to mount
682     test -w etc -o -w etc/mtab || xflag=-n
683     "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
684     popd >/dev/null
685 }
686
687 function mountRootFS
688 {
689     local cfgdir=$1
690     local vdir=$1/vdir
691     local fstab="$cfgdir"/fstab
692     local xflag=
693
694     test -e "$fstab" || return 0
695     pushd "$vdir" >/dev/null
696     # check whether / is mounted readonly or whether there is special
697     # magic regarding the mtab file; when etc/mtab can not be touched,
698     # add the '-n' flag to mount
699     test -w etc -o -w etc/mtab || xflag=-n
700     $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
701     popd >/dev/null
702 }
703
704 function mountVserver
705 {
706     local cfgdir=$1
707     local ns_opt=$2
708     local vdir=$1/vdir
709     local mtab_src
710
711     test -e "$cfgdir"/fstab -o \
712          -e "$cfgdir"/fstab.local -o \
713          -e "$cfgdir"/fstab.remote || return 0
714
715     findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
716     
717     pushd "$vdir" >/dev/null
718     $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
719     popd >/dev/null
720
721     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
722
723     test -z "$NAMESPACE_CLEANUP" || isAvoidNamespace "$cfgdir" || \
724         $_VNAMESPACE --cleanup
725
726     _mountVserverInternal "$cfgdir"/fstab
727     _mountVserverInternal "$cfgdir"/fstab.local
728     _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}"
729
730     isAvoidNamespace "$cfgdir" || \
731         $_SECURE_MOUNT --rbind -n "$vdir" "/"
732 }
733
734 function _umountVserverInternal
735 {
736     local fstab="$1"
737     test -e "$fstab" || return 0
738     shift
739
740     $_TAC "$fstab" | {
741         is_ok=1
742         while read src dst tmp; do
743             test -n "$tmp" || continue
744             case x"$src" in
745                 (x\#*)  continue;;
746             esac
747
748         
749             "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
750         done
751         test -n "$is_ok"
752     }
753 }
754
755 function umountVserver
756 {
757     local cfgdir=$1
758     local vdir=$1/vdir
759     local is_ok=1
760
761     isAvoidNamespace "$cfgdir"    || return 0
762     test -e "$cfgdir"/fstab -o \
763          -e "$cfgdir"/fstab.local || return 0
764     test -n "$_HAVE_CHBIND_OPTIONS"  || _generateChbindOptions "$cfgdir"
765     
766     pushd "$vdir/" >/dev/null || return 1
767         _umountVserverInternal  "$cfgdir"/fstab.local                              || is_ok=
768         _umountVserverInternal  "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
769     popd >/dev/null           || return 1
770
771     test -n "$is_ok"
772 }
773
774 ## Usage: waitForSync <vserver> <context> <vshelper-fifo-varname>
775 function initSync
776 {
777     local _is_meth=sync
778     test -n "$_NEED_VSHELPER_SYNC" && \
779         ! $_VSERVER_INFO - FEATURE vwait || _is_meth=async
780
781     vshelper.initSync "$1" "$3" "$_is_meth"
782 }
783
784 ## Usage: initWait <vserver> <context> <vwait-tmpdir-varname>
785 function initWait
786 {
787     if $_VSERVER_INFO - FEATURE vwait; then
788         local _is_tmpdir
789         _is_tmpdir=$($_MKTEMPDIR /tmp/vwaitstat.XXXXXX)
790             
791         $_NOHUP $_VWAIT --timeout "$VSHELPER_SYNC_TIMEOUT" \
792             --terminate --status-fd 3 "$2"  \
793             >>$_is_tmpdir/out 2>$_is_tmpdir/err 3>$_is_tmpdir/fifo &
794
795         echo "$!" >$_is_tmpdir/pid
796         eval "$3"=$_is_tmpdir
797     fi
798 }
799
800
801 ## Usage: _waitForVWait <fifo> <pid>
802 function _waitForVWait
803 {
804     declare -a status
805     wait "$2" || :
806     getFileArray status "$1"
807     set -- ${status[0]}
808
809     case "$1" in
810         (ERROR)         warning $"\
811 'vwait' exited with error '$2' which indicates that vserver could not
812 be stopped properly"
813                         ;;
814         (FINISHED)      ;;
815         (KILLED)        warning $"\
816 A timeout occured while waiting for the vserver to finish and it was
817 killed by sending a SIGKILL signal. Please investigate the reasons
818 and/or increase the timeout in apps/vshelper/sync-timeout."
819                         ;;
820         (TIMEOUT|\?\?\?|*)      warning $"\
821 internal error: 'vwait' exited with an unexpected status '$1'; I will
822 try to continue but be prepared for unexpected events."
823                         ;;
824     esac
825
826     return 0
827 }
828
829 ## Usage: waitForSync <vserver> [<vshelper-fifo>] [<vwait-statdir>]
830 function waitForSync
831 {
832     local cfgdir=$1
833     local fifo=$2
834     local vwait_statdir=$3
835     local vwait_pid=$4
836
837     if test -d "$vwait_statdir"; then
838         _waitForVWait "$vwait_statdir/fifo" "$( <$vwait_statdir/pid )"
839     elif test -n "$_NEED_VSHELPER_SYNC"; then
840         $_VSHELPER_SYNC "$fifo" "$VSHELPER_SYNC_TIMEOUT" || \
841             warning $"\
842 A timeout or other error occured while waiting for the synchronization
843 signal from vserver '$VSERVER_NAME'.
844 The vserver will be killed nevertheless..."
845     elif test "${#INITCMD_STOP_SYNC[@]}" -ne 0; then
846         "${INITCMD_STOP_SYNC[@]}" || \
847             warning $"\
848 Stop-synchronization for vserver '$VSERVER_NAME' failed. The vserver
849 will be killed nevertheless..."
850     fi
851
852     test -z "$OPTION_FORCE_SYNC" -a ! -e "$cfgdir"/sync ||
853         sleep 1
854 }
855
856 function _sourceWrap
857 {
858     local vdir name flavor start i already_handled base
859     . "$@"
860 }
861
862 ## Usage: execScriptlets <vserver-cfgdir> <vserver-name> <script-flavor>
863 function execScriptlets
864 {
865     declare -r vdir=$1
866     declare -r name=$2
867     declare -r flavor=$3
868     local base i
869
870     for base in "$vdir"/scripts "$__CONFDIR"/.defaults/scripts; do
871         local   DONT_SKIP_DEFAULTS=
872         local   already_handled=
873         
874         for i in "$base/$flavor" "$base/$flavor.d"/*; do
875             isRegularFile "$i" || continue
876             test  -r "$i"      || continue
877
878             already_handled=1
879             local start=
880             test -x "$i" || start=_sourceWrap
881             $start "$i" "$flavor" "$name"
882         done
883
884         test -z "$already_handled" -o -n "$DONT_SKIP_DEFAULTS" || break
885     done
886 }
887
888
889 function sanityCheck
890 {
891     declare -r cfgdir=$1
892
893     ! test -e "$cfgdir"/fstab.local ||
894         warning $"\
895 WARNING: 'fstab' will *not* be executed in the network context of the
896   vserver anymore. Therefore, 'fstab.local' has the same functionality
897   and is obsoleted. When you need the old behaviour, put the mounts
898   into 'fstab.remote'"
899
900     ! test -e "$cfgdir"/hostname -a ! -L "$cfgdir"/hostname ||
901         warning $"\
902 WARNING: The hostname is now configured in 'uts/nodename' but not in
903   'hostname'."
904
905     ! test -e "$cfgdir"/domainname -a ! -L "$cfgdir"/domainname ||
906         warning $"\
907 WARNING: The domainname is now configured in 'uts/domainname' but not
908   in 'domainname'." >&2
909
910   
911     local i
912     for i in "$cfgdir"/interfaces/*/only_ip; do
913         if test -e "$i"; then
914             local iface
915             iface=${i##$cfgdir/interfaces/}
916             iface=${iface%%/only_ip}
917             warning $"\
918 WARNING: The 'only_ip' flag for interface '$iface' is deprecated; use
919   'nodev' instead of"
920         fi
921     done
922
923     find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
924
925     vshelper.doSanityCheck
926
927     $_VSERVER_INFO - VERIFYCAP ||
928         panic $"capabilities are not enabled in kernel-setup"
929
930     $_VSERVER_INFO - VERIFYPROC ||
931         panic $"\
932 /proc/uptime can not be accessed. Usually, this is caused by
933 procfs-security. Please read the FAQ for more details
934 http://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ"
935 }