Apply Christian Heim's patch to deprecate the Gentoo initstyle
[util-vserver.git] / 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             panic "init-style '$INITSTYLE' is no longer supported; please use plain instead; aborting";;
296
297         (x) ;;
298         (*) panic "Unknown init-style '$INITSTYLE'; aborting";;
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 --flag default "${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 function _getVLANInfo
459 {
460     case "$1" in
461         (vlan????)
462             panic "\
463 creation of VLAN_PLUS_VID devices is not supported; please create them
464 before starting the vserver and use the 'nodev' flag then"
465             echo "$1 vlan ${1##vlan} VLAN_PLUS_VID"
466             ;;
467         (vlan*)
468             panic "\
469 creation of VLAN_PLUS_VID_NO_PAD devices is not supported; please
470 create them before starting the vserver and use the 'nodev' flag then"
471             echo "$1 vlan ${1##vlan} VLAN_PLUS_VID_N0_PAD"
472             ;;
473         (*.????)        echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID";;
474         (*.*)           echo "$1 ${1%%.*} ${1##*.} DEV_PLUS_VID_NO_PAD";;
475         (*)             return 1
476     esac
477
478     return 0
479 }
480
481 ## Usage: _processSingleInterface <interface-directory>
482 function _processSingleInterface
483 {
484     local iface=$1
485
486     local ip
487     local dev
488     local prefix
489     local mask
490     local bcast
491     local name
492     local scope
493     local mac
494     local extip
495     local up="up"
496
497     _getInterfaceValue ip     '' "$iface"
498     _getInterfaceValue extip  '' "$iface" "$iface/.."
499     _getInterfaceValue dev    '' "$iface" "$iface/.."
500     _getInterfaceValue prefix '' "$iface" "$iface/.."
501     _getInterfaceValue mask   '' "$iface" "$iface/.."
502     _getInterfaceValue bcast  '' "$iface" "$iface/.."
503     _getInterfaceValue name   '' "$iface"
504     _getInterfaceValue scope  '' "$iface" "$iface/.."
505     _getInterfaceValue mac    '' "$iface"
506
507     test -n "$ip" || { echo $"Can not read ip for '$iface'"  >&2; return 1; }
508     test -n "$dev" -o -e "$iface"/nodev || {
509         echo $"No device specified for '$iface'" >&2
510         return 1;
511     }
512
513     test ! -e "$iface"/down || up=
514
515     while true; do
516         _transformMask2Prefix prefix "$prefix" "$mask"
517         INTERFACES=( "${INTERFACES[@]}" "$ip${prefix:+/$prefix}" )
518
519         test ! -e "$iface"/nodev   || break
520         ## LEGACY ALERT
521         test ! -e "$iface"/only_ip || break
522
523         local vlan_info
524         if vlan_info=$(_getVLANInfo "$dev"); then
525             test -d /proc/net/vlan || {
526                 echo -e $"VLAN device-name used, but vlan subsystem not enabled.\nTry to execute 'modprobe 8021q' before starting the vservers"  >&2
527                 return 1
528             }
529             test -f /proc/net/vlan -o -e "$iface"/novlandev || {
530                 _addInterfaceCmd VCONFIG $vlan_info
531             }
532         fi
533
534         if ! test -e "$iface"/indirect; then
535             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" broadcast ${bcast:-+} ${name:+label "$dev:$name"} dev "$dev"
536             #_addInterfaceCmd IP_ROUTE "$ip${prefix:+/$prefix}" dev "$dev"
537             _addInterfaceCmd IP_LINK  "$dev" $up
538         elif ! test -n "$ctx"; then
539             echo $"Using 'dummy' (indirect) for interface '$dev' requires a fixed context number; dynamic ctx are not supported" >&2
540             return 1
541         else
542             test -z "$mac" || _generateMac mac "$(basename $iface)" "$ctx" || return 1
543             _addInterfaceCmd MODPROBE dummy "$dev"
544             _addInterfaceCmd IP_LINK  dev dummy0 address "$mac"
545             _addInterfaceCmd NAMEIF   "$dev" "$mac"
546             _addInterfaceCmd IP_ADDR  "$ip${prefix:+/$prefix}" dev "$dev"
547             test -z "$extip" || _addInterfaceCmd IPTABLES "$ip${prefix:+/$prefix}" ${name:+label "$dev:$name"} "$ctx" "$extip"
548         fi
549
550         break
551     done
552 }
553
554 ## Usage: _generateInterfaceOptions <vserver-directory>
555 function _generateInterfaceOptions
556 {
557     local iface
558     local ctx
559
560     test ! -e "$1"/context || read ctx <"$1"/context
561
562     for iface in "$1/interfaces/"*; do
563         test   -d "$iface"          || continue
564         test ! -e "$iface"/disabled || continue
565     
566         _processSingleInterface "$iface"
567     done
568     _HAVE_INTERFACE_OPTIONS=1
569 }
570
571 function enableInterfaces
572 {
573     local i=0
574     declare -a var
575
576     lock "$__LOCKDIR"/vserver.interfaces
577
578     while test $i -lt $INTERFACE_CMDS_IDX; do
579         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
580         local type=${var[0]}
581         unset var[0]
582
583         set -- "${var[@]}"
584         case "$type" in
585             IPTABLES)   ;; ## TODO
586             MODPROBE)
587                 local mod=$1
588                 local name=$2
589                 shift 2
590                 $_MODPROBE ${name:+-o "$name"} "$mod" "$@"
591                 ;;
592             NAMEIF)             $_NAMEIF   "$@";;
593             VCONFIG)            $_VCONFIG  set_name_type "$4"      >/dev/null
594                                 $_VCONFIG  add           "$2" "$3" >/dev/null;;
595             IP_ADDR)            $_IP addr  add   "$@";;
596             IP_ADDR_FLUSH)      $_IP addr  flush "$@";;
597             IP_LINK)            $_IP link  set   "$@";;
598             IP_ROUTE)           $_IP route add   "$@";;
599             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
600         esac
601
602         let ++i
603     done
604
605     unlock 1
606 }
607
608 function disableInterfaces
609 {
610     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$1"
611
612     local i=$INTERFACE_CMDS_IDX
613     declare -a var
614
615     lock "$__LOCKDIR"/vserver.interfaces
616     
617     while test $i -gt 0; do
618         let --i || :
619
620         eval var='( "${INTERFACE_CMDS_'$i'[@]}" )'
621         local type=${var[0]}
622         unset var[0]
623         
624         set -- "${var[@]}"
625         case "$type" in
626             IPTABLES)           ;; ## TODO
627             MODPROBE)           $_RMMOD "${2:-$1}";;
628             NAMEIF)             ;;
629             VCONFIG)            $_VCONFIG  rem "$2.$3" >/dev/null;;
630             IP_ADDR)            $_IP addr  del "$@";;
631             IP_ADDR_FLUSH)      ;;
632             IP_LINK)            ;; ## Ignore the link-down command for now
633             IP_ROUTE)           $_IP route del "$@";;
634             *)                  echo "Unknown interface-command type '$type'" >&2; false;;
635         esac
636     done
637
638     unlock 1
639 }
640
641 ## Usage: prepareInit <vserver-directory>
642 function prepareInit
643 {
644     pushd "$1/vdir" >/dev/null
645     case "$INITSTYLE" in
646         sysv)
647             { find var/run  ! -type d -print0; \
648               find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
649             ;;
650         plain)
651             $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
652             : | $_CHROOT_SH truncate fastboot  2>/dev/null || :
653             ;;
654         minit)
655             ;;
656     esac
657     "${INITCMD_PREPARE[@]}"
658     popd >/dev/null
659 }
660
661 ## Usage: prepareInit <vserver-directory>
662 function prepareStop
663 {
664     pushd "$1/vdir" >/dev/null
665     case "$INITSTYLE" in
666         (sysv)
667             export PREVLEVEL=$RUNLEVEL_START # required by Debian's initscripts
668             ;;
669     esac
670     "${STOPCMD_PREPARE[@]}"
671     popd >/dev/null
672 }
673
674
675 function generateOptions
676 {
677     _generateInterfaceOptions   "$1"
678     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1" 
679     _generateNiceCommand        "$1"
680     _generateInitOptions        "$1"
681     _generateChcontextOptions   "$1"
682     _generateScheduleOptions    "$1"
683     _generatePersonalityOptions "$1"
684
685     if test -n "$_IS_FAKEINIT"; then
686         CHCONTEXT_INIT_OPTS=( --disconnect --flag fakeinit )
687         OPTS_VCONTEXT_MIGRATE=( "${OPTS_VCONTEXT_MIGRATE[@]}" --initpid --disconnect )
688     fi
689 }
690
691 function _mountVserverInternal
692 {
693     local fstab="$1"
694     local xflag=
695     
696     test -e "$fstab" || return 0
697     shift
698
699     pushd "$vdir" >/dev/null
700     # check whether / is mounted readonly or whether there is special
701     # magic regarding the mtab file; when etc/mtab can not be touched,
702     # add the '-n' flag to mount
703     test -w etc -o -w etc/mtab || xflag=-n
704     "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
705     popd >/dev/null
706 }
707
708 function mountRootFS
709 {
710     local cfgdir=$1
711     local vdir=$1/vdir
712     local fstab="$cfgdir"/fstab
713     local xflag=
714
715     test -e "$fstab" || return 0
716     pushd "$vdir" >/dev/null
717     # check whether / is mounted readonly or whether there is special
718     # magic regarding the mtab file; when etc/mtab can not be touched,
719     # add the '-n' flag to mount
720     test -w etc -o -w etc/mtab || xflag=-n
721     $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs only -n
722     popd >/dev/null
723 }
724
725 function mountVserver
726 {
727     local cfgdir=$1
728     local ns_opt=$2
729     local vdir=$1/vdir
730     local mtab_src
731
732     test -e "$cfgdir"/fstab -o \
733          -e "$cfgdir"/fstab.local -o \
734          -e "$cfgdir"/fstab.remote || return 0
735
736     findObject -r mtab_src "$cfgdir"/apps/init/mtab "$__CONFDIR"/.defaults/init/mtab "$__PKGLIBDEFAULTDIR"/mtab /dev/null
737     
738     pushd "$vdir" >/dev/null
739     $_CHROOT_SH truncate /etc/mtab <"$mtab_src"
740     popd >/dev/null
741
742     test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$cfgdir"
743
744     test -z "$NAMESPACE_CLEANUP" || isAvoidNamespace "$cfgdir" || \
745         $_VNAMESPACE --cleanup
746
747     _mountVserverInternal "$cfgdir"/fstab
748     _mountVserverInternal "$cfgdir"/fstab.local
749     _mountVserverInternal "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}"
750
751     isAvoidNamespace "$cfgdir" || \
752         $_SECURE_MOUNT --rbind -n "$vdir" "/"
753 }
754
755 function _umountVserverInternal
756 {
757     local fstab="$1"
758     test -e "$fstab" || return 0
759     shift
760
761     $_TAC "$fstab" | {
762         is_ok=1
763         while read src dst tmp; do
764             test -n "$tmp" || continue
765             case x"$src" in
766                 (x\#*)  continue;;
767             esac
768
769         
770             "$@" $_EXEC_CD "$dst" $_UMOUNT -lfn . || is_ok=
771         done
772         test -n "$is_ok"
773     }
774 }
775
776 function umountVserver
777 {
778     local cfgdir=$1
779     local vdir=$1/vdir
780     local is_ok=1
781
782     isAvoidNamespace "$cfgdir"    || return 0
783     test -e "$cfgdir"/fstab -o \
784          -e "$cfgdir"/fstab.local -o \
785          -e "$cfgdir"/fstab.remote || return 0
786     test -n "$_HAVE_CHBIND_OPTIONS"  || _generateChbindOptions "$cfgdir"
787     
788     pushd "$vdir/" >/dev/null || return 1
789         _umountVserverInternal  "$cfgdir"/fstab.remote $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
790         _umountVserverInternal  "$cfgdir"/fstab.local                               || is_ok=
791         _umountVserverInternal  "$cfgdir"/fstab                                     || 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 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     test ! -d "$cfgdir"/dlimits -o -L "$cfgdir/cache" || \
971         warning $"\
972 WARNING: There is no cachedirectory configured for this vserver;
973   please create '$cfgdir/cache' e.g. by executing
974
975   ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
976 "
977
978     find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
979
980     vshelper.doSanityCheck
981
982     $_VSERVER_INFO - VERIFYCAP ||
983         panic $"capabilities are not enabled in kernel-setup"
984
985     $_VSERVER_INFO - VERIFYPROC ||
986         panic $"\
987 /proc/uptime can not be accessed. Usually, this is caused by
988 procfs-security. Please read the FAQ for more details
989 http://www.linux-vserver.org/index.php?page=Linux-Vserver+FAQ"
990 }
991
992
993 function _setSingleDiskLimit
994 {
995     local vdir=$1
996     local dlimit=$2
997     local space_used=
998     local space_total=
999     local inodes_used=
1000     local inodes_total=
1001     local reserved=
1002     local directory=
1003     local ctx=
1004
1005     getFileValue ctx          "$vdir/context"
1006     getFileValue directory    "$dlimit/directory"    || return 0
1007     getFileValue space_total  "$dlimit/space_total"  || return 0
1008     getFileValue inodes_total "$dlimit/inodes_total" || return 0
1009     getFileValue reserved     "$dlimit/reserved"     || return 0
1010
1011     local cachename=$ctx$directory
1012     cachename=dlimits/${cachename//\//_}
1013
1014     test -e "$vdir/cache/$cachename" && . "$vdir/cache/$cachename"
1015     # Remove the cache so if the machine goes down unexpectedly, we won't have a stale cache
1016     $_RM -f "$vdir/cache/$cachename"
1017
1018     if test -z "$inodes_used" -o -z "$space_used"; then
1019         local tmpvdu
1020         tmpvdu=`$_VDU --xid $ctx --space --inodes --script "$directory"`
1021         inodes_used=${tmpvdu##* }
1022         space_used=${tmpvdu%% *}
1023     fi
1024
1025     $_VDLIMIT --xid $ctx \
1026         --set space_used=$space_used \
1027         --set space_total=$space_total \
1028         --set inodes_used=$inodes_used \
1029         --set inodes_total=$inodes_total \
1030         --set reserved=$reserved \
1031         "$directory"
1032 }
1033
1034
1035 function setDiskLimits
1036 {
1037     local vdir=$1
1038     local dlimit
1039
1040     # Disk Limits without a static context are useless
1041     test -e "$vdir"/context || return 0
1042
1043     for dlimit in "$vdir/dlimits/"*; do
1044         test   -d "$dlimit"          || continue
1045         test ! -e "$dlimit/disabled" || continue
1046
1047         _setSingleDiskLimit "$vdir" "$dlimit"
1048     done
1049 }
1050
1051
1052 function _saveSingleDiskLimit
1053 {
1054     local vdir=$1
1055     local dlimit=$2
1056     local ctx=
1057     local directory=
1058
1059     getFileValue ctx       "$vdir/context"
1060     getFileValue directory "$dlimit/directory" || return 0
1061
1062     local cachename=$ctx$directory
1063     cachename=${cachename//\//_}
1064
1065     # Things are getting ugly here... LFS says that /var/cache (where
1066     # cachename is usually pointing to) can vanish and applications
1067     # have to deal with it. So, we have to interprete the $vdir/cache
1068     # symlink and have to create the needed directories manually.
1069     if   test -d "$vdir/cache"; then
1070         :       # ok, exists already
1071     elif test -L "$vdir/cache"; then
1072         # it's a dangling symlink
1073         local link
1074         link=$($_READLINK "$vdir/cache")
1075         ( cd $vdir && $_MKDIR -p "$link" )
1076     else
1077         return 0
1078     fi
1079
1080     test -d "$vdir/cache"
1081     $_MKDIR -p "$vdir"/cache/dlimits
1082
1083     $_VDLIMIT --xid $ctx "$directory" | \
1084         $_GREP '_used=' > "$vdir/cache/dlimits/$cachename"
1085 }
1086
1087
1088 function saveDiskLimits
1089 {
1090     local vdir=$1
1091     local dlimit
1092
1093     test -e "$vdir"/context || return 0
1094
1095     for dlimit in "$vdir/dlimits/"*; do
1096         test   -d "$dlimit"          || continue
1097         test ! -e "$dlimit/disabled" || continue
1098
1099         _saveSingleDiskLimit "$vdir" "$dlimit"
1100     done
1101 }