added vwait
[util-vserver.git] / util-vserver / scripts / pkgmgmt
index a641dfb..397eca2 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 # $Id$
 
-# Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+# Copyright (C) 2004,2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
 #  
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@ test -e "$UTIL_VSERVER_VARS" || {
 . "$UTIL_VSERVER_VARS"
 . "$_LIB_FUNCTIONS"
 . "$_LIB_VSERVER_BUILD_FUNCTIONS_PKGMGMT"
+. "$__PKGLIBDIR/vserver.functions"
 
 function showHelp()
 {
@@ -40,7 +41,7 @@ function showVersion()
 vpkg $PACKAGE_VERSION -- shows information about packages in vservers
 This program is part of $PACKAGE_STRING
 
-Copyright (C) 2004 Enrico Scholz
+Copyright (C) 2004,2005 Enrico Scholz
 This program is free software; you may redistribute it under the terms of
 the GNU General Public License.  This program has absolutely no warranty."
     exit 0
@@ -59,7 +60,7 @@ function init()
 function _createDirs()
 {
     for i; do
-       test "$i" || continue
+       test -n "$i" || continue
        mkdir -p -m755 "$i"
     done
 }
@@ -85,24 +86,43 @@ function _copySecureRev()
     ( cd "$dstdir" && tar xf - )
 }
 
+## Usage: _substFile <filename> <sed-expression>
+function _substFile()
+{
+    local file=$1
+    local expr=$2
+    
+    $_CHROOT_SH testfile "$file" || return 0
+
+    local tmp=$($_MKTEMP /tmp/pkgmgmt_subst.XXXXXX)
+    trap "$_RM -f $tmp" EXIT
+
+    $_CHROOT_SH cat "$file" | \
+       $_SED -e "$expr" >$tmp
+
+    $_CHROOT_SH cat "$file" | $_CMP -s $tmp - || \
+       $_CHROOT_SH truncate "$file" <$tmp
+
+    $_RM -f $tmp
+}
+
 function _hashAuto()
 {
+    local file=$1
     local hash=$2
-    local dir=$(dirname "$1")
-    local file=$(basename "$1")
 
-    $_EXEC_CD "$dir" "$(which test)" "$file" || return 0
+    $_CHROOT_SH testfile "$file" || return 0
     
-    local tmp=$(mktemp /tmp/apt.conf.XXXXXX)
-    trap "rm -f $tmp" EXIT
+    local tmp=$($_MKTEMP /tmp/apt.conf.XXXXXX)
+    trap "$_RM -f $tmp" EXIT
 
-    $_EXEC_CD "$dir" /bin/cat "$file" | \
-       sed -e "s|^\([^$hash].*@autogenerated@\)|$hash$hash\1|" >$tmp
+    $_CHROOT_SH cat "$file" | \
+       $_SED -e "s|^\([^$hash].*@autogenerated@\)|$hash$hash\1|" >$tmp
 
-    cat $tmp | $_EXEC_CD "$dir" "$(which cmp)" -s - "$file" || \
-       $_CHROOT_CAT "$1" <$tmp
+    $_CHROOT_SH cat "$file" | $_CMP -s $tmp - || \
+       $_CHROOT_SH truncate "$file" <$tmp
 
-    rm -f $tmp
+    $_RM -f $tmp
 }
 
 function _unhashAuto()
@@ -110,14 +130,102 @@ function _unhashAuto()
     test -e "$1" || return 0
 
     local hash=$2
-    local tmp=$(mktemp /tmp/apt.conf.XXXXXX)
-    trap "rm -f $tmp" EXIT
+    local tmp=$($_MKTEMP /tmp/apt.conf.XXXXXX)
+    trap "$_RM -f $tmp" EXIT
+
+    $_SED -e "s|^$hash$hash\(.*@autogenerated@\)|\1|" "$1" >$tmp
+    $_CMP -s "$tmp" "$1" || \
+       $_CAT "$tmp" >"$1"
+
+    $_RM -f $tmp
+}
+
+function _mountFilesystemsInternal()
+{
+    local fstab="$1"
+    test -e "$fstab" || return 0
+    shift
+
+    pushd "$vdir" >/dev/null
+    "$@" $_SECURE_MOUNT -n -a --chroot --fstab "$fstab"
+    popd >/dev/null
+}
+
+function _mountFilesystems()
+{
+    local cfgdir
+    cfgdir=$($_VSERVER_INFO "$1" CFGDIR) || {
+       echo "Can not determine configuration directory for '$1'; ..." >&2
+       return 1
+    }
+    test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
+    
+    _mountFilesystemsInternal "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || return 1
+    _mountFilesystemsInternal "$cfgdir"/fstab.local $_CHBIND "${CHBIND_OPTS[@]}" || return 1
+}
+
+function _umountFilesystems()
+{
+    local cfgdir
+    cfgdir=$($_VSERVER_INFO "$1" CFGDIR) || {
+       echo "Can not determine configuration directory for '$1'; ..." >&2
+       return 1
+    }
+    local vdir=$cfgdir/vdir
+    local is_ok=1
+    test -n "$_HAVE_CHBIND_OPTIONS" || _generateChbindOptions "$1"
+
+    pushd "$vdir/" >/dev/null || return 1
+       _umountVserverInternal  "$cfgdir"/fstab.local                              || is_ok=
+       _umountVserverInternal  "$cfgdir"/fstab       $_CHBIND "${CHBIND_OPTS[@]}" || is_ok=
+    popd >/dev/null           || return 1
+    
+    test -n "$is_ok"
+}
 
-    sed -e "s|^$hash$hash\(.*@autogenerated@\)|\1|" "$1" >$tmp
-    cmp -s "$tmp" "$1" || \
-       cat "$tmp" >"$1"
+# Usage: verifyInternalPackages <vserver> <style>
+function verifyInternalPackages()
+{
+    local pkgs res=0
+    local ERR="\
+The following errors occured while trying to internalize the
+packagemanagement:
+"
+    
+    case $2 in
+       (RH)    pkgs=$(vrpm "$1" -- -q --qf '---%{NAME}---\n' rpm apt yum "${YUM_RELEASEPKGS[@]}")
+               hasSubstring "$pkgs" ---rpm--- || {
+                   warning "$ERR
+* The vserver does not seem to have the 'rpm' package which is required
+  for internal package management. It is suggested to install it before
+  continuing."
+                   res=1
+                   ERR=
+               }
+               
+               hasSubstring "$pkgs"  ---apt--- ---yum--- || {
+                   warning "$ERR
+* The vserver does not seem to have a depsolver like 'apt' or 'yum'
+  installed. It is suggested to install such a program before setting
+  up internal package management."
+                   res=1
+                   ERR=
+               }
+
+               test -n "$have_apt" || test -z "$have_yum"   || \
+               hasSubstring "$pkgs" "${YUM_RELEASEPKGS[@]}" || {
+                   warning "$ERR
+* yum requires a special package which describes the version of the
+  distribution. Such a package could not be found within the vserver
+  so please install it before continuing. Usually, this package is
+  named 'redhat-release' of 'fedora-release'."
+                   res=1
+                   ERR=
+               }
+               ;;
+    esac
 
-    rm -f $tmp
+    return $res
 }
 
 function processVserver_RH()
@@ -133,7 +241,9 @@ function processVserver_RH()
 
     ## Figure out the environment....
     have_apt=1
+    have_yum=1
     pkgmgmt.isAptAvailable "$cfgdir" "$vdir" "$is_internalize" || have_apt=
+    pkgmgmt.isYumAvailable "$cfgdir" "$vdir" "$is_internalize" || have_yum=
 
     local APTETCDIR=
     local APTSTATEDIR=
@@ -144,13 +254,17 @@ function processVserver_RH()
 
     ## Create directories and assign variables where configuration
     ## can/will be found on the host
-    if test "$is_internalize"; then
+    if test -n "$is_internalize"; then
+       verifyInternalPackages "$vserver" RH || test -n "$IS_FORCE" ||
+           panic "
+Can not continue; use '--force' to override this check"
+    
        pushd "$vdir" >/dev/null
 
        test ! -L var/lib/rpm || {
-           $_EXEC_CD /var/lib /bin/rm            rpm &&
-           $_EXEC_CD /var/lib /bin/mkdir -m755   rpm &&
-           $_EXEC_CD /var/lib /bin/chown rpm:rpm rpm ||
+           $_EXEC_CD /var/lib $_RM            rpm &&
+           $_EXEC_CD /var/lib $_MKDIR -m755   rpm &&
+           $_EXEC_CD /var/lib $_CHOWN rpm:rpm rpm ||
            :
        } </dev/null 2>/dev/null
 
@@ -158,12 +272,12 @@ function processVserver_RH()
                 var/state/{,apt/{,lists/{,partial}}} \
                 etc/apt etc/rpm; do
            test -d "$i" ||
-               $_EXEC_CD /$(dirname "$i") /bin/mkdir -m755 $(basename "$i") || :
+               $_EXEC_CD /$(dirname "$i") $_MKDIR -m755 $(basename "$i") || :
        done #2>/dev/null
        
        popd >/dev/null
        
-       if test "$have_apt"; then
+       if test -n "$have_apt"; then
            findDir APTETCDIR    "$cfgdir"/aptetc "$cfgdir"/base/apt/etc /etc/apt /
        fi
 
@@ -173,7 +287,7 @@ function processVserver_RH()
        mkdir -m755 -p "$cfgdir"
        local need_base=
 
-       if test "$have_apt"; then
+       if test -n "$have_apt"; then
            findDir APTETCDIR    "$cfgdir"/aptetc      "$cfgdir"/base/apt/etc       /
            findDir APTSTATEDIR  "$cfgdir"/aptstate    "$cfgdir"/base/apt/state     /
            findDir APTCACHEDIR  "$cfgdir"/aptcache    "$cfgdir"/base/apt/cache     /
@@ -205,8 +319,8 @@ function processVserver_RH()
     fi
 
     ## Copy the files...
-    if test "$is_internalize"; then
-       if test "$have_apt"; then
+    if test -n "$is_internalize"; then
+       if test -n "$have_apt"; then
            _copySecure "$vdir" "$APTETCDIR" /etc/apt
            pushd "$vdir" >/dev/null
                _hashAuto /etc/apt/apt.conf '/'
@@ -216,33 +330,39 @@ function processVserver_RH()
        _copySecure "$vdir" "$RPMETCDIR"   /etc/rpm
        _copySecure "$vdir" "$RPMSTATEDIR" /var/lib/rpm
 
+       pushd "$vdir" >/dev/null
+           ## remove %_dbpath settings
+           _substFile /etc/rpm/macros '/^%_dbpath[ \t].*/D'
+       popd >/dev/null
     else
-       if test "$have_apt"; then
+       if test -n "$have_apt"; then
            _copySecureRev "$vdir" /etc/apt "$APTETCDIR"
            _unhashAuto "$APTETCDIR"/apt.conf '/'
        fi
 
        _copySecureRev "$vdir" /etc/rpm     "$RPMETCDIR"
        _copySecureRev "$vdir" /var/lib/rpm "$RPMSTATEDIR"
+
+       echo -e "%_dbpath\t\t$rpmdb_mntpoint" >>$RPMETCDIR/macros
     fi
 
     ## Cleanups...
-    if test "$is_internalize"; then
+    if test -n "$is_internalize"; then
        :
     else
-       tmpdir=$(mktemp -d /var/tmp/pgmgmt.XXXXXX)
-       trap "rm -rf $tmpdir" EXIT
+       tmpdir=$($_MKTEMPDIR /var/tmp/pgmgmt.XXXXXX)
+       trap "$_RM -rf $tmpdir" EXIT
        pushd "$vdir" >/dev/null
-       $_EXEC_CD /var/lib /bin/mv rpm $tmpdir/
-       $_EXEC_CD /var/lib /bin/ln -s "$rpmdb_mntpoint" rpm
-       rm -rf $tmpdir
+       $_EXEC_CD /var/lib $_MV rpm $tmpdir/
+       $_EXEC_CD /var/lib $_LN_S "$rpmdb_mntpoint" rpm
+       $_RM -rf $tmpdir
     fi
 
     ## Finish it...
-    if test "$is_internalize"; then
-       touch "$cfgdir"/internal
+    if test -n "$is_internalize"; then
+       $_TOUCH "$cfgdir"/internal
     else
-       rm -f "$cfgdir"/internal
+       $_RM -f "$cfgdir"/internal
     fi
 }
 
@@ -251,7 +371,7 @@ function processVserver_Debian()
     local vserver=$1
     local is_internalize=$2
 
-    if test "$is_internalize"; then
+    if test -n "$is_internalize"; then
        echo $"Debian vservers should be internalized everytime; do not know how to handle '$vserver'" >&2
     else
        echo $"External packagemanagement is not supported for Debian vserver" >&2
@@ -290,6 +410,7 @@ function processVserver()
     test -z "$skip" || return 1
 
     local style
+    _mountFilesystems  "$vserver"       || return 1
     pkgmgmt.guessStyle "$vserver" style || return 1
 
     case "$style" in
@@ -299,14 +420,17 @@ function processVserver()
            echo $"Vserver style '$style' is not supported for packagemanagment" >&2
            return 1
     esac
+
+    _umountFilesystems "$vserver"       || return 1
 }
 
-tmp=$(getopt -o y --long debug,externalize,internalize,help,version -n "$0" -- "$@") || exit 1
+tmp=$(getopt -o y --long debug,externalize,internalize,help,version,force -n "$0" -- "$@") || exit 1
 eval set -- "$tmp"
 
 IS_EXTERNALIZE=
 IS_INTERNALIZE=
 IS_YES=
+IS_FORCE=
 
 while true; do
     case "$1" in
@@ -315,6 +439,7 @@ while true; do
        (--debug)       set -x;;
        (--externalize) IS_EXTERNALIZE=1;;
        (--internalize) IS_INTERNALIZE=1;;
+       (--force)       IS_FORCE=1;;
        (-y)            IS_YES=1;;
        (--)            shift; break;;
        (*)             echo $"vserver: internal error; arg=='$1'" >&2; exit 1;;
@@ -322,7 +447,7 @@ while true; do
     shift
 done
 
-test "$1" || {
+test -n "$1" || {
     echo $"No vserver specified; try '--help' for more information"
     exit 1
 } >&2