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