4b8e4c891d53cf707924fff2fa4274bc3b79179e
[util-vserver.git] / util-vserver / scripts / 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 _VS_LOGFILE=
19 _VS_ERRFILE=
20
21 _VS_NEWLINE='
22 '
23 declare -r _VS_NEWLINE=${_VS_NEWLINE:0-1}
24 declare -r VS_ALLVSERVERS_ARGS=all,marked,unmarked,stopped,running
25
26 function findObject
27 {
28     local _fo_mod=$1
29     local _fo_var=$2
30     local _fo_file=
31     local _fo_i=X
32     shift 2
33     
34     for _fo_i; do
35         test -n "$_fo_i"         || continue
36         test ! $_fo_mod "$_fo_i" || { _fo_file=$_fo_i; break; }
37     done
38
39     test -z "$_fo_i" -o -n "$_fo_file" || {
40         echo "Can not find file for '$_fo_var'; aborting"
41         exit 1
42     } >&2
43
44     eval "$_fo_var=\"$_fo_file\""
45 }
46
47 function findFile
48 {
49     findObject -f "$@"
50 }
51
52 function findDir
53 {
54     findObject -d "$@"
55 }
56
57 function findAndCopy
58 {
59     local dst=$1
60     test ! -s "$dst"         || return 0
61     
62     local tmp
63     shift
64     findFile tmp "$@"
65
66     test -n "$tmp" -a -s "$tmp" || return 0
67     $_CP -af "$tmp" "$dst"
68 }
69
70 ## Usage: isRegularFile <filename> [<mod>]
71 function isRegularFile
72 {
73     test ${2:--f} "$1" || return 1
74
75     case $1 in
76         (*.rpmsave|*.rpmnew|*.rpmorig|*.cfsaved*|*.~*~) return 1;;
77     esac
78
79     return 0
80 }
81
82 function getPhysicalDir
83 {
84     ( set -P && cd "$1" && pwd )
85 }
86
87 ## Usage:: isDirectoryEmpty <dir> [<ignore-lost+found>]
88 function isDirectoryEmpty
89 {
90     (
91         shopt -s dotglob  || *
92         shopt -s nullglob || *
93
94         ignore_lostfound=1
95         test -z "$2" -o "$2" = 0 || ignore_lostfound=
96         
97         for i in "$1"/*; do
98             case "$i" in
99                 (lost+found)
100                     test "$ignore_lostfound" || exit 1
101                     ;;
102                 (*)     echo "$i"; exit 1
103             esac
104         done
105
106         exit 0
107     )
108 }
109
110 ## Usage: logging <message>
111 function logging
112 {
113     if test -n "$_VS_LOGFILE"; then
114         echo "$@" >>"$_VS_LOGFILE"
115     else
116         echo "$@"
117     fi
118 }
119
120 ## Usage: warning <message>
121 function warning
122 {
123     if test -n "$_VS_ERRFILE"; then
124         echo "$@" >>"$_VS_ERRFILE"
125     else
126         echo "$@" >&2
127     fi
128 }
129
130 ## Usage: panic <message>
131 function panic
132 {
133     if test -n "$_VS_ERRFILE"; then
134         echo "$@" >>"$_VS_ERRFILE"
135     else
136         echo "$@" >&2
137     fi
138
139     exit 1
140 }
141
142 ## Usage: execute <message>
143 function execute
144 {
145     test -z "${DEBUG_EXEC:-}"       || echo "$@"
146     test "${DEBUG_EXEC:-}" = noexec || exec "$@"
147     exit 0
148 }
149
150
151 ## Usage: spawn <message>
152 function spawn
153 {
154     test -z "${DEBUG_EXEC:-}"       || echo  "$@"
155     test "${DEBUG_EXEC:-}" = noexec || "$@"
156 }
157
158 ## Usage: isNumber <arg>
159 function isNumber
160 {
161     local tmp
162     let tmp=$1+0 2>/dev/null || test -z "${1//0/}" -a -n "$1" || return 1
163     return 0
164 }
165
166 ## Usage: hasSubstring <haystack> <needle>+
167 function hasSubstring
168 {
169     local pat=$1
170     local i
171     
172     shift
173
174     for i; do
175         test x"${pat/*$i*/$i}" = x"$i" || continue
176         return 0
177     done
178
179     return 1
180 }
181
182 ## Usage: colorize <style> <command>
183 function colorize
184 {
185     local       style=$1
186     shift
187     
188     if ! $_TTY -s; then
189         "$@"
190     else
191         local   cfile
192         findFile cfile "$__CONFDIR"/.defaults/styles/"$style" ''
193         if test -n "$cfile"; then
194           $_CAT "$cfile"
195         else
196           case "$style" in
197             (bold)      echo -ne "\e[1m";;
198             (emph)      echo -ne "\e[34m";;
199             (info)      echo -ne "\e[0;34m";;
200             (warn*)     echo -ne "\e[1;31m";;
201             (error)     echo -ne "\e[1;33;41m";;
202             (*)         ;;
203           esac
204         fi
205             
206         "$@"
207         echo -ne "\e[m"
208     fi
209 }
210
211 function colpanic
212 {
213     colorize error   panic     "$@"
214 }
215
216 function colwarning
217 {
218     colorize warning warning "$@"
219 }
220
221 function colinfo
222 {
223     colorize info    echo "$@"
224 }
225
226
227 ## Usage: xtermTitle <title>
228 function xtermTitle
229 {
230     $_TTY -s || return 0
231     echo -ne "\e]0;$@\007"
232 }
233
234 _VS_LOCKS=''
235 ## Usage: lock <lockfile> [<timeout>]
236 function lock
237 {
238     local tmp=$($_MKTEMP /tmp/vserver-lock.XXXXXX)
239     $_RM -f $tmp
240     $_MKFIFO -m600 $tmp
241
242     $_LOCKFILE "$1" $tmp $2 &
243     $_GREP -q true $tmp 2>/dev/null || return 1
244     
245     _VS_LOCKS="$! $_VS_LOCKS"
246 }
247
248 ## Usage: unlock [<num>]
249 function unlock
250 {
251     local num=$1
252     local i
253
254     set -- $_VS_LOCKS
255     while test "$#" -gt 0; do
256         kill -HUP "$1" >/dev/null || :
257         shift
258         test "$num" != 1 || break
259         test -z "$num"   || let --num
260     done
261     _VS_LOCKS="$@"
262 }
263
264 function _pkgMountBindDir()
265 {
266     test "$1" != "$2" || return 0
267
268     $_MOUNT -n --bind "$1" "$2"
269 }
270
271 function _pkgSetVarsBase
272 {
273     case "$vserver" in
274         ./*|/*)
275             if test -d "$vserver/vdir"; then
276                 BASEDIR=$vserver
277                 VDIR=$(getPhysicalDir "$vserver/vdir")
278                 
279                 PKGDIR=$BASEDIR/apps/pkgmgmt
280                 test -d "$PKGDIR" || {
281                     echo "Can not find configuration-directory for package-managment tools"
282                     exit 1
283                 } >&2
284                 findDir EXECDIR      $PKGDIR/execdir     /
285             else
286                 VDIR=$(getPhysicalDir "$vserver")
287                 PKGDIR=
288             fi
289             ;;
290         *)
291             BASEDIR=$__CONFDIR/$vserver
292             test -d "$BASEDIR" || {
293                 echo "Can not find configuration-directory"
294                 exit 1
295             } >&2
296             
297             VDIR=$BASEDIR/vdir
298             test -d "$VDIR"   || VDIR=$__DEFAULT_VSERVERDIR/$vserver
299             VDIR=$(getPhysicalDir "$VDIR")
300             
301             PKGDIR=$BASEDIR/apps/pkgmgmt
302             test -d "$PKGDIR" || {
303                 echo "Can not find configuration-directory for package-managment tools"
304                 exit 1
305             } >&2
306
307             findDir EXECDIR      $PKGDIR/execdir     /
308
309             ;;
310     esac
311
312     if test -z "$WORKAROUND_106057"; then
313         _rpmdb_mntpoint=/dev
314     else
315         _rpmdb_mntpoint=/.rpmdb
316     fi
317 }
318
319 function _pkgSetVarsRPM
320 {
321     if test -n "$PKGDIR"; then
322         findDir RPMETCDIR    $PKGDIR/rpmetc      $PKGDIR/base/rpm/etc       /etc/rpm
323         findDir RPMSTATEDIR  $PKGDIR/rpmstate    $PKGDIR/base/rpm/state
324
325         findDir RPMLIBDIR    $PKGDIR/rpmlib      /
326
327     else
328         findDir RPMETCDIR    "$VDIR"/etc/rpm     /etc/rpm
329         findDir RPMSTATEDIR  "$VDIR"/var/lib/rpm
330         RPMLIBDIR=/
331     fi
332     
333     RPMSTATEDIR=$(getPhysicalDir "$RPMSTATEDIR")
334     RPMETCDIR=$(getPhysicalDir "$RPMETCDIR")
335 }
336
337 function _pkgSetVarsApt
338 {
339     if test -n "$PKGDIR"; then
340         findDir APTETCDIR    $PKGDIR/aptetc      $PKGDIR/base/apt/etc       /etc/apt
341         findDir APTSTATEDIR  $PKGDIR/aptstate    $PKGDIR/base/apt/state
342         findDir APTCACHEDIR  $PKGDIR/aptcache    $PKGDIR/base/apt/cache
343         findDir APTARCHIVDIR $PKGDIR/aptarchives $PKGDIR/base/apt/archives  /var/cache/apt/archives
344     else
345         findDir APTETCDIR    "$VDIR"/etc/apt            /etc/apt
346         findDir APTSTATEDIR  "$VDIR"/var/state/apt
347         findDir APTCACHEDIR  "$VDIR"/var/cache/apt
348         findDir APTARCHIVDIR "$VDIR"/var/cache/apt/archives /var/cache/apt/archives
349     fi
350
351     findFile APT_CONFIG "$APTETCDIR"/apt.conf ""
352     test -z "$APT_CONFIG" || export APT_CONFIG
353 }
354
355 function _pkgSetVarsYum
356 {
357     if test -n "$PKGDIR"; then
358         findDir YUMETCDIR    $PKGDIR/yumetc      $PKGDIR/base/yum/etc       /etc
359         findDir YUMCACHEDIR  $PKGDIR/yumcache    $PKGDIR/base/yum/cache
360     else
361         findDir YUMETCDIR    "$VDIR"/etc         /etc
362         findDir YUMCACHEDIR  "$VDIR"/var/cache/yum
363     fi
364 }
365
366
367 function _pkgMountBase
368 {
369     :
370 }
371
372 function _pkgMountApt
373 {
374     :
375 }
376
377 function _pkgMountYum
378 {
379     :
380 }
381
382 function _pkgMountRPM
383 {
384     _pkgMountBindDir "$RPMETCDIR" /etc/rpm
385     test "$RPMLIBDIR" = "/" || _pkgMountBindDir "$RPMLIBDIR" /usr/lib/rpm
386
387     pushd "$VDIR" >/dev/null
388
389     $_SECURE_MOUNT --chroot -n --bind "$RPMSTATEDIR" "$_rpmdb_mntpoint"
390     test -z "$WORKAROUND_106057" || mount -n --bind "$RPMSTATEDIR" "$_rpmdb_mntpoint"
391
392     test -e "$VDIR"/proc/self/status || \
393         $_SECURE_MOUNT --chroot -n -t proc none /proc
394
395     popd >/dev/null
396 }
397
398 function _pkgSetEnvBase
399 {
400     test "$EXECDIR" = "/" || {
401         PATH=$EXECDIR:$PATH
402         LD_LIBRARY_PATH=$EXECDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
403     }
404
405     export PATH LD_LIBRARY_PATH
406 }
407
408 function _pkgSetEnvApt
409 {
410     :
411 }
412
413 function _pkgSetEnvYum
414 {
415     :
416 }
417
418 function _pkgSetEnvRPM
419 {
420     CUR_VSERVER=$vserver
421     RPM_FAKE_NAMESPACE_MOUNTS=$_rpmdb_mntpoint
422     RPM_BINARY=$_VRPM_PRELOAD
423
424     export CUR_VSERVER RPM_FAKE_NAMESPACE_MOUNTS RPM_BINARY
425 }
426
427 function pkgInit
428 {
429     local i
430     local vserver=$1
431     shift
432     
433     _pkgSetVarsBase
434     for i; do
435         case "$i" in
436             rpm)        _pkgSetVarsRPM;;
437             apt)        _pkgSetVarsApt;;
438             yum)        _pkgSetVarsYum;;
439             *)          echo "Unknown packaging flavor" >&2; exit 1;;
440         esac
441     done
442
443     _pkgMountBase
444     for i; do
445         case "$i" in
446             rpm)        _pkgMountRPM;;
447             apt)        _pkgMountApt;;
448             yum)        _pkgMountYum;;
449         esac
450     done
451
452     _pkgSetEnvBase
453     for i; do
454         case "$i" in
455             rpm)        _pkgSetEnvRPM;;
456             apt)        _pkgSetEnvApt;;
457             yum)        _pkgSetEnvYum;;
458         esac
459     done
460
461     _PKG_FLAVORS="$@"
462     _PKG_VSERVER=$vserver
463 }
464
465 function isAvoidNamespace
466 {
467     local cfgdir
468
469     $_VSERVER_INFO - FEATURE namespace   || return 0
470     cfgdir=$($_VSERVER_INFO "$1" CFGDIR) || return 0
471     test ! -e "$cfgdir"/namespace        || return 1
472     test -e "$__CONFDIR"/.defaults/nonamespace -o \
473          -e "$cfgdir"/nonamespace
474 }
475
476 ## Usage: getAllVservers <var> [<KIND>*]
477 function getAllVservers
478 {
479     local _ga_i
480     declare -a _ga_tmp=()
481
482     for _ga_i in $__CONFDIR/*; do
483         isRegularFile "$_ga_i" -d   || continue
484
485         test ! -e "$_ga_i"/disabled || continue
486         test   -d "$_ga_i"/vdir     || continue
487
488         local _ga_doadd=1
489         local _ga_markfile=$_ga_i/apps/init/mark
490         
491         case ${2:-ALL} in
492             (MARKED)    test   -s "$_ga_markfile" || _ga_doadd=;;
493             (UNMARKED)  test ! -s "$_ga_markfile" || _ga_doadd=;;
494             (STOPPED)   ! $_VSERVER "$_ga_i" running &>/dev/null || _ga_doadd=;;
495             (RUNNING)     $_VSERVER "$_ga_i" running &>/dev/null || _ga_doadd=;;
496             (ALL)       ;;
497             (*)         panic $"Unknown vserver tagging '$2'";;
498         esac
499
500         test -z "$_ga_doadd" || _ga_tmp=( "${_ga_tmp[@]}" "${_ga_i##$__CONFDIR/}")
501     done
502
503     eval $1='( "${_ga_tmp[@]}" )'
504 }
505
506 ## Usage: getAllVserversByArg <var> <arg>
507 function getAllVserversByArg
508 {
509     local _gav_mark=
510     
511     case $2 in
512         (--all)         _gav_mark=ALL;;
513         (--marked)      _gav_mark=MARKED;;
514         (--unmarked)    _gav_mark=UNMARKED;;
515         (--stopped)     _gav_mark=STOPPED;;
516         (--running)     _gav_mark=RUNNING;;
517         (*)             return 1;;
518     esac
519
520     getAllVservers "$1" "$_gav_mark"
521 }
522
523 ## Usage: _getProcNumberCount <ctx> <var>
524 function _getProcNumberCount
525 {
526     local _gp_var=$2
527     local _gp_procnr_cnt=0
528
529     # Use /proc/virtual from kernel 2.6 when possible
530     if test -d "/proc/virtual"; then
531         set -- $($_GREP '^PROC:' "/proc/virtual/$1/limit" 2>/dev/null)
532         _gp_procnr_cnt=$2
533     else
534         _gp_procnr_cnt=$($_VPS ax | $_AWK '{print $2}' | $_GREP -x "$1" | $_WC -l )
535     fi
536
537     let _gp_procnr_cnt=_gp_procnr_cnt+0
538     eval $_gp_var=\$_gp_procnr_cnt
539 }
540
541 ## Usage: getVserverCtx <vdir> <result-varname> [<procnumber-varname> [<do-cleanup>]]
542 ## Returns: 0 iff vserver is running
543 function getVserverStatus
544 {
545     test -r "$1"/run || return 1
546
547     local _gvs_ctx
548     read _gvs_ctx <"$1"/run
549     eval "$2"=\$_gvs_ctx
550
551     test -n "$3"     || return 0
552     local _gvs_tmp
553     _getProcNumberCount "$_gvs_ctx" _gvs_tmp
554     eval "$3"=\$_gvs_tmp
555
556     if test "$_gvs_tmp" = 0; then
557         local runfile=$($_READLINK "$1/run")
558         test -z "$4" || $_RM -f "$runfile"
559         return 1
560     fi
561
562     return 0
563 }
564
565 ## Usage: isCtxRunning <ctx>
566 function isCtxRunning
567 {
568     local _tmp
569     _getProcNumberCount "$1" _tmp
570     test $_tmp -gt 0
571 }
572
573 ## Usage: isVserverRunning <vdir> [<ctx-varname>]
574 function isVserverRunning
575 {
576     local _ivr_ctx _ivr_procnum
577
578     getVserverStatus "$1" _ivr_ctx _ivr_procnum 1 || return 1
579     test "$_ivr_procnum" != 0                     || return 1
580     test -z "$2" || eval "$2"=\$_ivr_ctx
581     return 0
582 }
583
584 ## Called as 'getFileValue <varname> <filename>+'
585 function getFileValue
586 {
587     local _gfv_var=$1
588     local _gfv_file
589     shift
590
591     findFile _gfv_file "$@" ''
592     test -n "$_gfv_file" -a -r "$_gfv_file" || return 0
593     eval read "$_gfv_var" <"$_gfv_file"
594 }
595
596 ## Called as 'getFileArray <varname> <filename>'
597 function getFileArray
598 {
599     test -r "$2" || return 1
600     
601     local IFS=$_VS_NEWLINE
602     eval "$1"='( $(< "$2") )'
603 }
604
605 function checkComponents
606 {
607     local       i
608     local       msg=$1
609     local       x_failed=
610
611     shift
612     
613     for i; do
614         local failed=
615         case "$i" in
616             (core)      test -x "$_CHBIND"           || failed=1;;
617             (build)     test -x "$_VSERVER_BUILD"    || failed=1;;
618             (sysv)      test -x "$__INITRDDIR/vserver"    || failed=1;;
619             (devel)     test -d "$__INCLUDEDIR/vserver.h" || failed=1;;
620             (*)         echo "Unknown component '$i'" >&2
621                         return false
622                         ;;
623         esac
624
625         test -z "$failed" || {
626             echo "$msg: $i"
627             x_failed=1
628         } >&2
629     done
630
631     test -z "$x_failed"
632 }
633
634 ## Usage: isKernelAPI <ver> [<cmp-modifier>]
635 function isKernelAPI
636 {
637     local api
638     api=$($_VSERVER_INFO - APIVER) || api=0
639     test $[ $api ] -${2:-ge} $[ $1 ]
640 }
641
642 ## Usage: callInNamespace <vserver> <command> <args>*
643 function callInNamespace
644 {
645     local ctx=
646     
647     isAvoidNamespace "$1" || \
648     ctx=$( $_VSERVER_INFO "$1" CONTEXT f ) || ctx=
649
650     shift
651     if test -n "$ctx"; then
652         $_VNAMESPACE --enter "$ctx" -- "$@"
653     else
654         "$@"
655     fi
656 }
657
658 ## Usage: setDefaultTTY <vdir> [<fallback-tty>]
659 function setDefaultTTY
660 {
661     local cfgdir ttyname
662
663     cfgdir=$($_VSERVER_INFO "$1" APPDIR init) || cfgdir=
664     findObject -e ttyname \
665         ${cfgdir:+"$cfgdir"/tty} \
666         "$__CONFDIR/.defaults/apps/init/tty" \
667         $2 /dev/null
668
669     exec   <$ttyname
670     exec  &>$ttyname
671 }
672
673 ## Usage: killContext <XID> [<SIG>]
674 function killContext
675 {
676     local sig=${2:-9}
677
678     #$_VKILL -s STOP   --xid "$1" 1 &>/dev/null || :
679     $_VKILL -s "$sig" --xid "$1" 1 &>/dev/null || :
680     $_VKILL -s "$sig" --xid "$1"   &>/dev/null || :
681     #$_VKILL -s "$sig" --xid "$1" 1 &>/dev/null || :
682     #$_VKILL -s CONT   --xid "$1" 1 &>/dev/null || :
683 }
684
685 ## Usage: pkgmgmt.guessStyle <vserver> <resultvar>
686 function pkgmgmt.guessStyle()
687 {
688     local _pgs_vdir
689     _pgs_vdir=$($_VSERVER_INFO "$1" VDIR) || {
690         echo $"Can not determine vserver-root" >&2
691         return 1
692     }
693     local _pgs_cfgdir=$($_VSERVER_INFO "$1" APPDIR pkgmgmt) || :
694
695     if test -n "$_pgs_cfgdir" -a -e "$_pgs_cfgdir"/style; then
696         read style <"$_pgs_cfgdir"/style
697     elif test -e "$_pgs_vdir"/etc/redhat-release -o -e "$_pgs_vdir"/etc/fedora-release; then
698         style=redhat
699     elif test -e "$_pgs_vdir"/etc/mandrake-release; then
700         style=mandrake
701     elif test -e "$_pgs_vdir"/etc/debian_version; then
702         style=debian
703     elif test -e "$_pgs_vdir"/etc/SuSE-release; then
704         style=suse
705     else
706         echo $"Can not determine packagemanagement style" >&2
707         return 1
708     fi
709
710     eval $2=\$style
711     return 0
712 }
713
714 ## Usage: pkgmgmt.isInternal <vserver>
715 ## returns true iff <vserver> is configured for internal packagemanagement
716 ## A typical application is
717 ## | is_external=
718 ## | pkgmgmt.isInternal "$vserver" || is_external=1
719 function pkgmgmt.isInternal
720 {
721     local cfgdir=$($_VSERVER_INFO "$1" APPDIR pkgmgmt) || :
722
723     test -z "$cfgdir" -o ! -d "$cfgdir" -o -e "$cfgdir"/internal
724 }
725
726 ## Usage: pkgmgmt.isAptAvailable <cfgdir> <vdir> [<is-internal>]
727 function pkgmgmt.isAptAvailable
728 {
729     local cfgdir="$1"
730     local vdir="$2"
731     local is_internal="$3"
732     
733     local have_apt i
734     if test -n "$is_internal"; then
735         have_apt=1
736         test -d "$cfgdir"/base/apt -o -d "$cfgdir"/aptetc || have_apt=
737     else
738         have_apt=
739         for i in /bin /usr/bin /usr/local/bin; do
740             test ! -x "$vdir$i"/apt-get || { have_apt=1; break; }
741         done
742     fi
743
744     test -n "$have_apt" && return 0 || return 1
745 }
746
747 ## Usage: pkgmgmt.isYumAvailable <cfgdir> <vdir> [<is-internal>]
748 function pkgmgmt.isYumAvailable
749 {
750     local cfgdir="$1"
751     local vdir="$2"
752     local is_internal="$3"
753     
754     local have_yum i
755     if test -n "$is_internal"; then
756         have_yum=1
757         test -d "$cfgdir"/base/yum -o -d "$cfgdir"/yumetc || have_yum=
758     else
759         have_yum=
760         for i in /bin /usr/bin /usr/local/bin; do
761             test ! -x "$vdir$i"/yum || { have_yum=1; break; }
762         done
763     fi
764
765     test -n "$have_yum" && return 0 || return 1
766 }
767
768
769 function vshelper.doSanityCheck
770 {
771     local vshelper this_xid i
772     declare -a warnings=()
773     local solution_disable=
774     local solution_sysctl=
775
776     vshelper.isEnabled && vshelper.isEnabled warning || return 0
777     
778     this_xid=$($_VSERVER_INFO - XID) ||
779         panic $"Failed to determine current context; aborting..."
780
781     ## Do nothing in other xid's; the helper will be executed in xid 0 only
782     test "$this_xid" = 0 || return 0
783
784     local proc_file=/proc/sys/kernel/vshelper
785
786     if ! test -r "$proc_file"; then
787         vshelper=
788         warnings=( "${warnings[@]}"
789                    $"File '$proc_file' does not exist but is required for vshelper setup" )
790         solution_disable=1
791     else
792         vshelper=$(cat "$proc_file")
793
794         $_CMP -s "$vshelper" "$_VSHELPER" || {
795             warnings=( "${warnings[@]}"
796                        $"The configured vshelper '$vshelper' does not match the 'vshelper'
797   script of the util-vserver package"
798                      )
799             solution_disable=1
800             solution_sysctl=1
801         }
802     fi
803
804     test -d "$__VSHELPERSTATEDIR" || {
805         warnings=( "${warnings[@]}"
806                    $"\
807 The vshelper state-directory '$__VSHELPERSTATEDIR' does not exist; since
808 it is created by 'make install', this indicates a serious problem with
809 your util-vserver installation" )
810         solution_disable=1
811     }
812
813     test "${#warnings[@]}" -eq 0 || {
814         warning $"\
815 The following problem(s) were encountered while verifying vshelper
816 functionality:"
817
818         for i in "${warnings[@]}"; do
819             warning "* $i"
820         done
821
822         warning $"\
823         
824 To fix this, you can:"
825
826         test -z "$solution_disable" || warning $"\
827 * disable vshelper entirely by executing
828   | touch \"$__CONFDIR/.defaults/apps/vshelper/disabled\"
829 * disable only this message by executing
830   | touch \"$__CONFDIR/.defaults/apps/vshelper/warning-disabled\""
831
832         test -x "$solution_sysctl" || warning $"\
833 * configure the util-vserver vshelper script, e.g. by adding
834   | kernel.vshelper = $_VSHELPER
835   to /etc/sysctl.conf and rebooting the machine, or by executing
836   | echo \"$_VSHELPER\" >$proc_file"
837
838         warning ""
839
840         return 1
841     }
842
843     return 0
844 }
845
846 ## Usage: vshelper.isEnabled [<style>] [<vserver>]
847 function vshelper.isEnabled
848 {
849     local f=${1:+$1-}disabled
850     test ! -e "$__CONFDIR"/.defaults/apps/vshelper/"$f"     || return 1
851     $_VSERVER_INFO - FEATURE vshelper                       || return 1
852     if test -n "$2"; then
853         local appdir
854         appdir=$($_VSERVER_INFO "$2" APPDIR vshelper)       || return 0
855         test -z "$2" -o ! -e "$appdir/$f"                   || return 1
856     fi
857
858     return 0
859 }
860
861 ## Usage: vshelper.isDebug [<vserver>]
862 function vshelper.isDebug
863 {
864     test ! -e "$__CONFDIR"/.defaults/apps/vshelper/debug    || return 0
865     $_VSERVER_INFO - FEATURE vshelper                       || return 1
866     if test -n "$1"; then
867         local appdir
868         appdir=$($_VSERVER_INFO "$1" APPDIR vshelper)       || return 1
869         test ! -e "$appdir/debug"                           || return 0
870     fi
871
872     return 1
873 }
874
875 function vshelper._getHandlerInternal
876 {
877     local _vghi_var=$1
878     local _vghi_tmp
879     shift
880     shift       ## HACK: see below the note about the 'set -u' mode
881     
882     while test "$#" -ge 2; do
883         local _vghi_mod=$1
884         local _vghi_obj=$2
885         shift 2
886
887         test "$_vghi_mod" "$_vghi_obj" || continue
888         case "$_vghi_mod" in
889             (-x)
890                 eval $_vghi_var=\$_vghi_obj
891                 ;;
892             (-e)
893                 read _vghi_tmp <"$_vghi_obj"
894                 eval $_vghi_var=:\$_vghi_tmp
895                 ;;
896             (*) panic $"Internal error, unexpected modifier '$_vghi_mod'"
897         esac
898         return 0
899     done
900     
901     return 1
902 }
903
904 ## Usage: vshelper.getHandler <result-var> <vserver> <action>
905 function vshelper.getHandler
906 {
907     local _vgh_appdir
908     _vgh_appdir=$($_VSERVER_INFO "$2" APPDIR vshelper) || _vgh_appdir=
909
910     declare -a _vgh_search_list=( X )
911     ## HACK: when we are in 'set -u' mode, empty lists are causing errors
912
913     test -z "$_vgh_appdir" || _vgh_search_list=( "${_vgh_search_list[@]}" -x "$_vgh_appdir/$3" )
914     test -z "$_vgh_appdir" || _vgh_search_list=( "${_vgh_search_list[@]}" -e "$_vgh_appdir/action" )
915     _vgh_search_list=( "${_vgh_search_list[@]}" -x "$__CONFDIR"/.defaults/apps/vshelper/"$3" )
916     _vgh_search_list=( "${_vgh_search_list[@]}" -e "$__CONFDIR"/.defaults/apps/vshelper/action )
917
918     ! vshelper._getHandlerInternal "$1" "${_vgh_search_list[@]}" || return 0
919     eval $1=':restart'
920 }
921
922 ## Usage: vshelper.init <vserver> [<method> <args>*]
923 function vshelper.doInit
924 {
925     vshelper.isEnabled || return 0
926     
927     local xid
928     xid=$($_VSERVER_INFO "$1" CONTEXT false) && test -n "$xid" || {
929         warning $"vshelper.init: can not determine xid of vserver '$vserver'; returned value was '$xid'"
930         return 1
931     }
932
933     local f="$__VSHELPERSTATEDIR/$xid"
934     
935     set -C
936     $_RM -f "$f"
937     echo "$1" >"$f"
938     set +C
939     
940     if test -n "$2"; then
941         shift 1
942         local i
943         for i; do
944             echo "$i" 
945         done
946     else
947         echo "default"
948     fi >>"$f"
949
950     return 0
951 }
952
953 ## Usage: vshelper.doDestroy <vserver> <xid>
954 function vshelper.doDestroy
955 {
956     vshelper.isEnabled || return 0
957
958     $_RM -f "$__VSHELPERSTATEDIR/$2"
959 }
960
961 ## Usage: vshelper.initSync <vserver> <pipe-varname> [<method>]
962 function vshelper.initSync
963 {
964     local _vis_tmpdir
965     _vis_tmpdir=$($_MKTEMPDIR /tmp/vserver-stop.XXXXXX) || {
966         warning $"Failed to generate temporary directory for vshelper sync"
967         return 1
968     }
969
970     local _vis_fifo="$_vis_tmpdir"/pipe
971     $_MKFIFO -m700 "$_vis_fifo"
972     vshelper.doInit "$1" "${3:-sync}" "$_vis_fifo"
973     eval $2=\$_vis_fifo
974 }
975
976 ## Usage: vshelper.getSyncTimeout <vserver> <varname>
977 function vshelper.getSyncTimeout
978 {
979     local _vgst_appdir _vgst_file _vgst_tmp
980     _vgst_appdir=$($_VSERVER_INFO "$1" APPDIR vshelper) || _vgst_appdir=
981
982     findFile _vgst_file ${_vgst_appdir:+"$_vgst_appdir"/sync-timeout} "$__CONFDIR"/.defaults/apps/vshelper/sync-timeout ''
983     test -n "$_vgst_file" || return 1
984     read _vgst_tmp <"$_vgst_file"
985     eval $2=\$_vgst_tmp
986 }
987
988
989 function _rpmFake.getCapFlags
990 {
991     local ctx=$1
992     
993     if test -n "$ctx" && ! $_VSERVER_INFO - FEATURE migrate; then
994         set -- $($_CHCONTEXT_COMPAT --xid 1 \
995             $_SH -c "$_CAT /proc/[0-9]*/status | $_EGREP '^(CapBset|s_context|ctxflags)'" | \
996             $_GREP -B 1 -A 1 "^s_context: $ctx " | \
997             $_SED -e '1,3p;d' | $_AWK '{ print $2 }')
998     else
999         set --
1000     fi
1001
1002     if test -n "$3"; then
1003         RPM_FAKE_CAP=$[ ~0x$1 ]
1004         RPM_FAKE_FLAGS=$3
1005     else
1006         RPM_FAKE_CAP=$[ ~0xd40c04ff ]
1007         RPM_FAKE_FLAGS=4
1008     fi
1009 }
1010
1011 function rpmFake.init
1012 {
1013     local vdir ctx
1014     
1015     vdir=$($_VSERVER_INFO "$1" VDIR)    || vdir="$1"
1016     ctx=$($_VSERVER_INFO  "$1" CONTEXT) || ctx=
1017
1018     test -d "$vdir" ||
1019         panic $"Can not find chroot environment at '$vdir' for '$1'"
1020
1021     _rpmFake.getCapFlags "$ctx"
1022
1023     RPM_FAKE_CHROOT=$vdir
1024     RPM_FAKE_CTX=$ctx
1025 }
1026
1027 function rpmFake.exec
1028 {
1029     export RPM_FAKE_CHROOT RPM_FAKE_CTX RPM_FAKE_CAP RPM_FAKE_FLAGS
1030     
1031     LD_PRELOAD=$_RPM_FAKE_SO${LD_PRELOAD:+:$LD_PRELOAD} \
1032         exec "$@"
1033 }