diff -r 71503088f51b -r f880f219c566 openpkg/rpmdb --- a/openpkg/rpmdb Tue Jul 31 12:12:54 2012 +0200 +++ b/openpkg/rpmdb Tue Jul 31 12:23:42 2012 +0200 @@ -1,15 +1,14 @@ #!@l_prefix@/lib/openpkg/bash ## ## rpmdb -- OpenPKG RPM Database Administration Utility -## Copyright (c) 2000-2007 OpenPKG Foundation e.V. -## Copyright (c) 2000-2007 Ralf S. Engelschall +## Copyright (c) 2000-2012 OpenPKG GmbH ## -## Permission to use, copy, modify, and distribute this software for -## any purpose with or without fee is hereby granted, provided that -## the above copyright notice and this permission notice appear in all -## copies. +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. ## -## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR @@ -30,6 +29,8 @@ help="" prefix="@l_prefix@" dbpath="" +dbapi="" +tmpdir="" rpm="" musr="@l_musr@" mgrp="@l_mgrp@" @@ -42,6 +43,7 @@ ## # iterate over argument line +args="" for opt do case $opt in @@ -51,6 +53,7 @@ case $opt in -h|--help ) help="Usage" ;; -B|--build ) mode=build ;; + -M|--migrate ) mode=migrate ;; -R|--rebuild ) mode=rebuild ;; -C|--cleanup ) mode=cleanup ;; -F|--fixate ) mode=fixate ;; @@ -60,14 +63,19 @@ -v|--verbose ) verbose=`expr $verbose + 1` ;; --prefix=* ) prefix=$arg ;; --dbpath=* ) dbpath=$arg ;; + --dblib=* ) dblib=$arg ;; + --tmpdir=* ) tmpdir=$arg ;; --rpm=* ) rpm=$arg ;; --musr=* ) musr=$arg ;; --mgrp=* ) mgrp=$arg ;; - * ) help="Invalid option \`$opt'"; break ;; + -- ) ;; + -* ) help="Invalid option \`$opt'"; break ;; + * ) args="$args \"$opt\"" ;; esac done +eval "set -- $args" -# makre sure exactly one run-time mode is specified +# make sure exactly one run-time mode is specified if [ ".$mode" = . ]; then help="No or invalid run-time mode specified" fi @@ -82,6 +90,7 @@ -h, --help print usage message (this one) -B, --build build new RPM database from scratch + -M, --migrate migrate RPM database to new format -R, --rebuild rebuild new from old RPM database -C, --cleanup cleanup existing RPM database -F, --fixate fixate existing RPM database @@ -91,12 +100,14 @@ -v, --verbose operate in more verbose mode (increase verbose level) --prefix=PREFIX use OpenPKG instance under PREFIX --dbpath=PATH use OpenPKG RPM database under PATH + --dblib=LIB use OpenPKG RPM database backend library ("db" or "sqlite") + --tmpdir=PATH use OpenPKG temporary directory under PATH --rpm=PROG use OpenPKG RPM executable PROG --musr=USERNAME use OpenPKG management user USERNAME --mgrp=GROUPNAME use OpenPKG management group GROUPNAME This is OpenPKG rpmdb, an RPM database administration utility, providing -lower-level maintainance functions for the Berkeley-DB 4.1 based RPM 4.2 +lower-level maintainance functions for the Berkeley-DB based RPM database. It allows building new RPM databases from scratch, rebuilding a new from an old RPM database (content dumping and reloading), cleaning up problems on an existing RPM database (removal of DB region @@ -115,6 +126,12 @@ if [ ".$dbpath" = . ]; then dbpath="$prefix/RPM/DB" fi +if [ ".$dblib" = . ]; then + dblib="${1-db}" +fi +if [ ".$tmpdir" = . ]; then + tmpdir="$prefix/RPM/TMP" +fi if [ ".$rpm" = . ]; then rpm="$prefix/bin/openpkg rpm" fi @@ -124,32 +141,61 @@ ## dbfiles=" - hash:Basenames - hash:Conflictname - hash:Depends - btree:Dirnames - hash:Filemd5s - hash:Group - btree:Installtid - hash:Name - hash:Packages - hash:Providename - btree:Provideversion - hash:Pubkeys - hash:Requirename - btree:Requireversion - hash:Sha1header - hash:Sigmd5 - hash:Triggername - region:__db.001 - region:__db.002 - region:__db.003 - region:__db.004 - region:__db.005 - region:__db.006 - region:__db.007 - region:__db.008 - region:__db.009 + 3:btree:Basenames + 3:btree:Conflictname + 3:temporary:Depends + 3:btree:Dirnames + 3:btree:Filedigests + 3:btree:Filepaths + 3:btree:Group + 3:btree:Installtid + 3:btree:Name + 3:hash:Packagecolor + 3:btree:Packages + 3:btree:Providename + 3:btree:Provideversion + 3:hash:Pubkeys + 3:btree:Requirename + 3:btree:Requireversion + 3:hash:Sha1header + 3:hash:Sigmd5 + 3:btree:Triggername + 3:btree:Obsoletename + 3:btree:Nvra + 3:btree:Sourcepkgid + 3:btree:BuildEnvironment + 3:region:__db.001 + 3:region:__db.002 + 3:region:__db.003 + 3:region:__db.004 + 3:region:__db.005 + 3:region:__db.006 + 3:region:__db.007 + 3:region:__db.008 + 3:region:__db.009 + 4:*:Basenames + 4:*:Conflictname + 4:temporary:Depends + 4:*:Dirnames + 4:*:Filedigests + 4:*:Filepaths + 4:*:Group + 4:*:Installtid + 4:*:Name + 4:*:Packagecolor + 4:*:Packages + 4:*:Providename + 4:*:Provideversion + 4:*:Pubkeys + 4:*:Requirename + 4:*:Requireversion + 4:*:Sha1header + 4:*:Sigmd5 + 4:*:Triggername + 4:*:Obsoletename + 4:*:Nvra + 4:*:Sourcepkgid + 4:*:BuildEnvironment " ## @@ -180,8 +226,45 @@ fi } +rpmdb_version_load () { + if [ -f $dbpath/VERSION ]; then + eval `(. $dbpath/VERSION || exit $?; echo "DBAPI=\"$DBAPI\"; DBLIB=\"$DBLIB\"; DBVER=\"$DBVER\"")` + fi + if [ ".$DBAPI" = . ]; then DBAPI="3"; fi + if [ ".$DBLIB" = . ]; then DBLIB="db"; fi + if [ ".$DBVER" = . ]; then DBVER="4.1.2"; fi +} + +rpmdb_version_save () { + if [ ".$DBAPI" = .3 ]; then + DBLIB="db" + DBVER=`$rpmdb_load -V 2>&1 |\ + grep 'Berkeley DB [0-9][0-9]*\.[0-9][0-9]*' |\ + sed -e 's;^;X;' \ + -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$;\1;' \ + -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\).*$;\1.0;' \ + -e 's;^X.*$;0.0.0;'` + elif [ ".$DBAPI" = .4 ]; then + DBLIB="sqlite" + DBVER=`$rpmdb_sqlite --version 2>&1 |\ + grep '^[0-9][0-9]*\.[0-9][0-9]*' |\ + sed -e 's;^;X;' \ + -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$;\1;' \ + -e 's;^X[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\).*$;\1.0;' \ + -e 's;^X.*$;0.0.0;'` + fi + ( echo "DBAPI=$DBAPI" + echo "DBLIB=$DBLIB" + echo "DBVER=$DBVER" + ) >$dbpath/VERSION.new || exit $? + mv $dbpath/VERSION.new $dbpath/VERSION || exit $? + chown $musr:$mgrp $dbpath/VERSION 2>/dev/null || true + chmod 644 $dbpath/VERSION 2>/dev/null || true +} + rpm () { - local opts="--dbpath `echo $dbpath | sed -e 's;/*$;;' -e 's;$;/;'`" + local opts="--define '_dbpath `echo $dbpath | sed -e 's;/*$;;' -e 's;$;/;'`'" + opts="$opts --define '_repackage_all_erasures 0'" if [ ".$force" = .yes ]; then opts="$opts --define '__dbi_private yes'" fi @@ -189,13 +272,9 @@ eval "$rpm $opts \"\$@\"" } -rpmdb_load () { - $prefix/lib/openpkg/rpmdb_load ${1+"$@"} -} - -rpmdb_dump () { - $prefix/lib/openpkg/rpmdb_dump ${1+"$@"} -} +rpmdb_load="$prefix/lib/openpkg/db_tool load" +rpmdb_dump="$prefix/lib/openpkg/db_tool dump" +rpmdb_sqlite="$prefix/lib/openpkg/sqlite3" ## ## RPM DATABASE OPERATIONS @@ -225,60 +304,61 @@ # remove all known files verbose 2 "removing (possibly existing) old RPM database DB files" for dbfile in $dbfiles; do - eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\)$/dbtype="\1"; dbfile="\2";/'` - verbose 3 "removing database file: $dbpath/$dbfile ($dbtype)" + eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'` + verbose 3 "removing database file: $dbpath/$dbfile ($dbapi:$dbtype)" rm -f $dbpath/$dbfile done } db_init () { # perform official "initdb" operation - # (is mostly a no-operation in RPM 4.2, but anyway) verbose 2 "creating new RPM database (built-in RPM procedure)" rpm --initdb - - # perform some real RPM work, so more database files - # magically spring into existence - verbose 2 "operating on new RPM database" - rpm --import $prefix/etc/openpkg/openpkg.org.pgp || true - rpm -e gpg-pubkey-63c4cb9f-3c591eda --allmatches || true - - # perform official "rebuilddb" operation in the hope it - # creates even more database files now that we have some content - verbose 2 "rebuilding new RPM database (built-in RPM procedure)" - rpm --rebuilddb + rpmdb_version_save } db_unbreak () { - # cleanup DB region files - verbose 2 "cleaning up RPM database DB region files" + # cleanup DB files + verbose 2 "cleaning up RPM database DB files" for dbfile in $dbfiles; do - eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\)$/dbtype="\1"; dbfile="\2";/'` - if [ ".$dbtype" = .region ]; then - verbose 3 "cleaning up DB file: $dbpath/$dbfile ($dbtype)" - rm -f $dbpath/$dbfile || true - touch $dbpath/$dbfile || true + eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'` + if [ -f $dbpath/$dbfile ]; then + if [ ".$dbapi" = .3 -a ".$dbtype" = .region ]; then + verbose 3 "cleaning up DB file: $dbpath/$dbfile ($dbapi:$dbtype)" + rm -f $dbpath/$dbfile || true + elif [ ".$dbtype" = .temporary ]; then + verbose 3 "cleaning up DB file: $dbpath/$dbfile ($dbapi:$dbtype)" + rm -f $dbpath/$dbfile || true + fi fi done } -db_extend () { - # make sure all RPM database DB files are present - verbose 2 "making sure RPM database contains all possible DB files" +db_convert () { + # make sure all RPM database DB files have the correct type + # (as the type can be different during upgrading from RPM 4 to RPM 5) + verbose 2 "making sure RPM database are of the correct type" for dbfile in $dbfiles; do - eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\)$/dbtype="\1"; dbfile="\2";/'` - if [ ! -f $dbpath/$dbfile ]; then - verbose 3 "creating DB file: $dbpath/$dbfile ($dbtype)" - if [ ".$dbtype" = .hash -o ".$dbtype" = .btree ]; then - ( echo "VERSION=3" - echo "format=bytevalue" - echo "type=$dbtype" - echo "db_pagesize=16384" - echo "HEADER=END" - echo "DATA=END" - ) | rpmdb_load $dbpath/$dbfile || true - else - touch $dbpath/$dbfile || true + eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'` + if [ ".$dbapi" != ".$DBAPI" ]; then + continue + fi + if [ -f $dbpath/$dbfile ]; then + if [ ".$dbapi" = .3 ] && [ ".$dbtype" = .hash -o ".$dbtype" = .btree ]; then + dbtype_old="`$rpmdb_dump -h $tmpdir -r $dbpath/$dbfile | grep '^type=' | sed -e 'q' | sed -e 's/^type=//'`" + if [ ".$dbtype_old" != ".$dbtype" ]; then + verbose 3 "converting DB file: $dbpath/$dbfile ($dbtype_old -> $dbtype)" + rm -f $dbpath/$dbfile.new + $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile |\ + sed -e "s/^type=.*/type=$dbtype/" -e '/^h_nelem=.*/d' |\ + $rpmdb_load -h $tmpdir $dbpath/$dbfile.new + if $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile.new >/dev/null 2>&1; then + rm -f $dbpath/$dbfile + mv $dbpath/$dbfile.new $dbpath/$dbfile + else + warning "failed to convert RPM DB file \"$dbfile\"" + fi + fi fi fi done @@ -289,26 +369,75 @@ # reloading their entire content verbose 2 "dumping and reloading RPM database DB file contents" for dbfile in $dbfiles; do - eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\)$/dbtype="\1"; dbfile="\2";/'` - verbose 3 "dumping and reloading DB file: $dbpath/$dbfile ($dbtype)" + eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'` + if [ ".$dbapi" != ".$DBAPI" ]; then + continue + fi if [ -f $dbpath/$dbfile ]; then - if [ ".$dbtype" = .hash -o ".$dbtype" = .btree ]; then - rpmdb_dump $dbpath/$dbfile |\ - rpmdb_load $dbpath/$dbfile.new - rm -f $dbpath/$dbfile - mv $dbpath/$dbfile.new $dbpath/$dbfile - else - rm -f $dbpath/$dbfile || true - touch $dbpath/$dbfile || true + if [ ".$dbapi" = .3 ]; then + verbose 3 "dumping and reloading DB file: $dbpath/$dbfile ($dbtype)" + if [ ".$dbtype" = .hash -o ".$dbtype" = .btree ]; then + rm -f $dbpath/$dbfile.new + $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile |\ + $rpmdb_load -h $tmpdir $dbpath/$dbfile.new + if $rpmdb_dump -h $tmpdir -r $dbpath/$dbfile.new >/dev/null 2>&1; then + rm -f $dbpath/$dbfile + mv $dbpath/$dbfile.new $dbpath/$dbfile + else + warning "failed to reload RPM DB file \"$dbfile\"" + fi + elif [ ".$dbtype" = .region ]; then + rm -f $dbpath/$dbfile || true + elif [ ".$dbtype" = .temporary ]; then + rm -f $dbpath/$dbfile || true + fi + elif [ ".$dbapi" = .4 ]; then + verbose 3 "dumping and reloading DB file: $dbpath/$dbfile ($dbtype)" + rm -f $dbpath/$dbfile.new + $rpmdb_sqlite $dbpath/$dbfile .dump |\ + $rpmdb_sqlite $dbpath/$dbfile.new + if $rpmdb_sqlite $dbpath/$dbfile.new >/dev/null 2>&1; then + rm -f $dbpath/$dbfile + mv $dbpath/$dbfile.new $dbpath/$dbfile + else + warning "failed to reload RPM DB file \"$dbfile\"" + fi fi fi done + rpmdb_version_save +} + +db_migrate () { + # perform database migration + if [ ".$1" != . ]; then + dblib="$1" + fi + dbapi_old="$DBAPI" + if [ ".$dblib" = .db ]; then + dbapi_new="3" + elif [ ".$dblib" = .sqlite ]; then + dbapi_new="4" + else + error "unknown RPM database backend library \"$dblib\"" + fi + if [ ".$dbapi_new" = ".$dbapi_old" ]; then + error "RPM database already uses requested backend ($DBAPI:$DBLIB:$DBVER)" + fi + verbose 2 "migrating RPM database" + rpm --rebuilddb --dbapi "$dbapi_old" --rebuilddbapi "$dbapi_new" + verbose 3 "old RPM database format: $DBAPI:$DBLIB:$DBVER" + DBAPI="$dbapi_new" + rpmdb_version_save + rpmdb_version_load + verbose 3 "new RPM database format: $DBAPI:$DBLIB:$DBVER" } db_rebuild () { # perform official "rebuilddb" operation verbose 2 "rebuilding RPM database (built-in RPM procedure)" rpm --rebuilddb + rpmdb_version_save } db_operate () { @@ -333,17 +462,30 @@ # RPM database files to make sure they are consistent verbose 2 "making sure RPM database files have consistent attributes" for dbfile in $dbfiles; do - eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\)$/dbtype="\1"; dbfile="\2";/'` + eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'` + if [ ".$dbapi" != ".$DBAPI" ]; then + continue + fi verbose 3 "fixating DB file: $dbpath/$dbfile ($dbtype)" - chown $musr:$mgrp $dbpath/$dbfile 2>/dev/null || true - chmod 644 $dbpath/$dbfile 2>/dev/null || true + if [ -f $dbpath/$dbfile ]; then + chown $musr:$mgrp $dbpath/$dbfile 2>/dev/null || true + chmod 644 $dbpath/$dbfile 2>/dev/null || true + fi done + chown $musr:$mgrp $dbpath/VERSION 2>/dev/null || true + chmod 644 $dbpath/VERSION 2>/dev/null || true } db_list () { # list all database files for dbfile in $dbfiles; do - eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\)$/dbtype="\1"; dbfile="\2";/'` + eval `echo $dbfile | sed -e 's/^\(.*\):\(.*\):\(.*\)$/dbapi="\1"; dbtype="\2"; dbfile="\3";/'` + if [ ".$dbapi" != ".$DBAPI" ]; then + continue + fi + if [ ! -f "$dbpath/$dbfile" ]; then + continue + fi if [ $verbose -eq 0 ]; then echo "$dbfile" elif [ $verbose -eq 1 ]; then @@ -380,6 +522,9 @@ error "OpenPKG RPM database directory \"$dbpath\" not writable" fi +# load database information +rpmdb_version_load + ## ## DISPATCH INTO COMMANDS ## @@ -389,7 +534,15 @@ verbose 1 "BUILDING NEW RPM DATABASE FROM SCRATCH ($dbpath)" db_remove db_init - db_extend + db_fixate + db_operate + ;; + + migrate ) + verbose 1 "MIGRATING RPM DATABASE FORMAT ($dbpath)" + db_unbreak + db_convert + db_migrate db_rebuild db_fixate db_operate @@ -398,7 +551,7 @@ rebuild ) verbose 1 "REBUILDING NEW FROM OLD RPM DATABASE ($dbpath)" db_unbreak - db_extend + db_convert db_reload db_rebuild db_fixate @@ -408,7 +561,7 @@ cleanup ) verbose 1 "CLEANING UP EXISTING RPM DATABASE ($dbpath)" db_unbreak - db_extend + db_convert db_rebuild db_fixate db_operate @@ -416,9 +569,7 @@ fixate ) verbose 1 "FIXATING EXISTING RPM DATABASE ($dbpath)" - db_extend db_fixate - db_operate ;; list )