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