util-vserver-0.30.208
[util-vserver.git] / scripts / pkgmgmt
diff --git a/scripts/pkgmgmt b/scripts/pkgmgmt
new file mode 100755 (executable)
index 0000000..99cc96c
--- /dev/null
@@ -0,0 +1,467 @@
+#!/bin/bash
+# $Id: pkgmgmt,v 1.13 2005/07/03 17:43:34 ensc Exp $
+
+# 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
+# the Free Software Foundation; version 2 of the License.
+#  
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#  
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+: ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars}
+test -e "$UTIL_VSERVER_VARS" || {
+    echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2
+    exit 1
+}
+. "$UTIL_VSERVER_VARS"
+. "$_LIB_FUNCTIONS"
+. "$_LIB_VSERVER_BUILD_FUNCTIONS_PKGMGMT"
+. "$__PKGLIBDIR/vserver.functions"
+
+function showHelp()
+{
+    echo \
+$"Usage: $0 --externalize|--internalize [-y] [--] <vserver-name>
+
+Report bugs to <$PACKAGE_BUGREPORT>."
+    exit 0
+}
+
+function showVersion()
+{
+    echo $"\
+vpkg $PACKAGE_VERSION -- shows information about packages in vservers
+This program is part of $PACKAGE_STRING
+
+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
+}
+
+function init()
+{
+    if test -z "$WORKAROUND_106057"; then
+       rpmdb_mntpoint=/dev
+    else
+       rpmdb_mntpoint=/.rpmdb
+    fi
+    pkgmgmt.initVariables
+}
+
+function _createDirs()
+{
+    for i; do
+       test -n "$i" || continue
+       mkdir -p -m755 "$i"
+    done
+}
+
+function _copySecure()
+{
+    local chroot=$1
+    local srcdir=$2
+    local dstdir=$3
+
+    
+    ( cd "$srcdir" && tar chf - '.' ) | \
+    ( cd "$chroot" && $_EXEC_CD "$dstdir" $_TAR xf - )
+}
+
+function _copySecureRev()
+{
+    local chroot=$1
+    local srcdir=$2
+    local dstdir=$3
+
+    ( cd "$chroot" && $_EXEC_CD "$srcdir" $_TAR cf - '.' ) | \
+    ( 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
+
+    $_CHROOT_SH testfile "$file" || return 0
+    
+    local tmp=$($_MKTEMP /tmp/apt.conf.XXXXXX)
+    trap "$_RM -f $tmp" EXIT
+
+    $_CHROOT_SH cat "$file" | \
+       $_SED -e "s|^\([^$hash].*@autogenerated@\)|$hash$hash\1|" >$tmp
+
+    $_CHROOT_SH cat "$file" | $_CMP -s $tmp - || \
+       $_CHROOT_SH truncate "$file" <$tmp
+
+    $_RM -f $tmp
+}
+
+function _unhashAuto()
+{
+    test -e "$1" || return 0
+
+    local hash=$2
+    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"
+}
+
+# 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
+
+    return $res
+}
+
+function processVserver_RH()
+{
+    local vserver=$1
+    local is_internalize=$2
+    local have_apt
+    local cfgdir
+    local i
+
+    cfgdir=$($_VSERVER_INFO "$vserver" APPDIR pkgmgmt) || \
+    cfgdir=$($_VSERVER_INFO "$vserver" APPDIR)/pkgmgmt
+
+    ## 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=
+    local APTCACHEDIR=
+    local APTARCHIVDIR=
+    local RPMETCDIR=
+    local RPMSTATEDIR=
+
+    ## Create directories and assign variables where configuration
+    ## can/will be found on the host
+    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 $_RM            rpm &&
+           $_EXEC_CD /var/lib $_MKDIR -m755   rpm &&
+           $_EXEC_CD /var/lib $_CHOWN rpm:rpm rpm ||
+           :
+       } </dev/null 2>/dev/null
+
+       for i in var/cache/apt/{,archives/{,partial},genpkglist,gensrclist} \
+                var/state/{,apt/{,lists/{,partial}}} \
+                etc/apt etc/rpm; do
+           test -d "$i" ||
+               $_EXEC_CD /$(dirname "$i") $_MKDIR -m755 $(basename "$i") || :
+       done #2>/dev/null
+       
+       popd >/dev/null
+       
+       if test -n "$have_apt"; then
+           findDir APTETCDIR    "$cfgdir"/aptetc "$cfgdir"/base/apt/etc /etc/apt /
+       fi
+
+       findDir RPMETCDIR   "$cfgdir"/rpmetc   "$cfgdir"/base/rpm/etc    /etc/rpm /
+       findDir RPMSTATEDIR "$cfgdir"/rpmstate "$cfgdir"/base/rpm/state
+    else
+       mkdir -m755 -p "$cfgdir"
+       local need_base=
+
+       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     /
+           findDir APTARCHIVDIR "$cfgdir"/aptarchives "$cfgdir"/base/apt/archives  /
+           
+           test "$APTETCDIR"    != / || APTETCDIR=$cfgdir/base/apt/etc
+           test "$APTSTATEDIR"  != / || APTSTATEDIR=$cfgdir/base/apt/state
+           test "$APTCACHEDIR"  != / || APTCACHEDIR=$cfgdir/base/apt/cache
+           test "$APTARCHIVDIR" != / || APTARCHIVDIR=$cfgdir/base/apt/archive
+
+           test -d "$cfgdir"/aptetc   -a -d "$cfgdir"/aptstate -a \
+                -d "$cfgdir"/aptcache -a -d "$cfgdir"/aptarchives || need_base=1
+       fi
+
+       findDir RPMETCDIR     "$cfgdir"/rpmetc   "$cfgdir"/base/rpm/etc    /
+       findDir RPMSTATEDIR   "$cfgdir"/rpmstate "$cfgdir"/base/rpm/state  /
+
+       test "$RPMETCDIR"   != / || RPMETCDIR=$cfgdir/base/rpm/etc
+       test "$RPMSTATEDIR" != / || RPMSTATEDIR=$cfgdir/base/rpm/state
+
+       test -d "$cfgdir"/rpmetc -a -d "$cfgdir"/rpmstate || need_base=1
+       test ! -e "$cfgdir"/base || need_base=
+
+       test -z "$need_base" || ln -s "$PKGCFGDIR" "$cfgdir"/base
+
+       mkdir -m755 -p "$PKGCFGDIR"
+       _createDirs "$APTETCDIR" "$APTSTATEDIR" "$APTCACHEDIR" "$APTARCHIVDIR" \
+                   "$RPMETCDIR" "$RPMSTATEDIR"
+    fi
+
+    ## Copy the files...
+    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 '/'
+           popd >/dev/null
+       fi
+
+       _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 -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 -n "$is_internalize"; then
+       :
+    else
+       tmpdir=$($_MKTEMPDIR /var/tmp/pgmgmt.XXXXXX)
+       trap "$_RM -rf $tmpdir" EXIT
+       pushd "$vdir" >/dev/null
+       $_EXEC_CD /var/lib $_MV rpm $tmpdir/
+       $_EXEC_CD /var/lib $_LN_S "$rpmdb_mntpoint" rpm
+       $_RM -rf $tmpdir
+    fi
+
+    ## Finish it...
+    if test -n "$is_internalize"; then
+       $_TOUCH "$cfgdir"/internal
+    else
+       $_RM -f "$cfgdir"/internal
+    fi
+}
+
+function processVserver_Debian()
+{
+    local vserver=$1
+    local is_internalize=$2
+
+    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
+    fi
+
+    return 1
+}
+
+function processVserver()
+{
+    local vserver=$1
+    local is_external=
+    local skip=1
+    local vdir
+
+    ! $_VSERVER_INFO -q "$vserver" RUNNING || {
+       echo $"Can not operate on running vservers; please stop '$vserver' and retry again..."
+       return 1
+    } >&2
+
+    vdir=$($_VSERVER_INFO "$vserver" VDIR) && test -d "$vdir" || {
+       echo $"Vserver '$vserver' does not seem to exist; skipping it..."
+       return 1
+    } >&2
+    
+    pkgmgmt.isInternal "$vserver" || is_external=1
+
+    case "$is_external"X"$IS_INTERNALIZE"X"$IS_EXTERNALIZE" in
+       (*X1X1) echo $"Can not externalize and internalize at the same time";;
+       (*XX)   echo $"No operation specified; try '--help' for more information";;
+       (1XX1)  echo $"Vserver '$vserver' has already external packagemanagment; skipping it...";;
+       (X1X)   echo $"Vserver '$vserver' has already internal packagemanagment; skipping it...";;
+       (*)     skip=
+    esac >&2
+
+    test -z "$skip" || return 1
+
+    local style
+    _mountFilesystems  "$vserver"       || return 1
+    pkgmgmt.guessStyle "$vserver" style || return 1
+
+    case "$style" in
+       (redhat|mandrake)       processVserver_RH     "$vserver" "$IS_INTERNALIZE";;
+       (debian)                processVserver_Debian "$vserver" "$IS_INTERNALIZE";;
+       (*)
+           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,force -n "$0" -- "$@") || exit 1
+eval set -- "$tmp"
+
+IS_EXTERNALIZE=
+IS_INTERNALIZE=
+IS_YES=
+IS_FORCE=
+
+while true; do
+    case "$1" in
+       (--help)        showHelp $0;;
+       (--version)     showVersion;;
+       (--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;;
+    esac
+    shift
+done
+
+test -n "$1" || {
+    echo $"No vserver specified; try '--help' for more information"
+    exit 1
+} >&2
+
+
+set -e
+init
+
+ok=1
+passed=
+for i; do
+    processVserver "$i" && passed=1 || ok=
+done
+    
+test -z "$ok"     || exit 0
+test -z "$passed" || exit 1
+exit 2