- perform db->verify when closing db files.
authorjbj <devnull@localhost>
Fri, 25 May 2001 19:51:53 +0000 (19:51 +0000)
committerjbj <devnull@localhost>
Fri, 25 May 2001 19:51:53 +0000 (19:51 +0000)
CVS patchset: 4813
CVS date: 2001/05/25 19:51:53

14 files changed:
CHANGES
db3/configure
lib/rpmlib.h
macros.in
rpm.c
rpmdb/Makefile.am
rpmdb/db1.c
rpmdb/db2.c
rpmdb/db3.c
rpmdb/dbconfig.c
rpmdb/rpmdb.c
rpmdb/rpmdb.h
rpmpopt.in
rpmqv.c

diff --git a/CHANGES b/CHANGES
index 968a305..e299ab8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -63,6 +63,7 @@
        - fix: skip %ghost files when building packages (#38218).
        - headerFree() returns NULL, _free is C++ safe.
        - remove all header region assertion failures, return NULL instead.
+       - perform db->verify when closing db files.
 
 4.0 -> 4.0.[12]
        - add doxygen and lclint annotations most everywhere.
index ff79eee..e4782e4 100755 (executable)
@@ -8,8 +8,8 @@ rm -f config.cache
 ln -sf ../dist $db_dist/../db/dist
 ln -sf ../dist $db_dist
 
-CFALGS="-O2" $db_dist/configure \
-       $(echo $* | sed -e "s% --cache-file=.*$% --enable-shared --enable-static --enable-debug --enable-rpc --with-uniquename=rpmdb --srcdir=$db_dist%")
+CC="$CC" CFLAGS="$CFLAGS" $db_dist/configure \
+       `echo $* | sed -e "s% --cache-file=.*$% --enable-shared --enable-static --enable-debug --enable-rpc --with-uniquename=rpmdb --srcdir=$db_dist%"`
 
 # XXX hack to get db-3.3.4 to configure properly
 rm -f $db_dist/../db/dist $db_dist/dist
@@ -20,7 +20,7 @@ cat Makefile.orig | sed -e 's/ -g$/ -g -O2/' -e '/^install:/c\
 listobjs:\
        @echo $(OBJS) $(C_OBJS) \
 \
-distdir install:\
+distdir install check:\
 \
 db3_install: all install_setip \\' > Makefile
 
index 368c984..c08580d 100644 (file)
@@ -603,9 +603,17 @@ int rpmdbInit(/*@null@*/ const char * root, int perms)
                /*@modifies fileSystem @*/;
 
 /** \ingroup rpmdb
+ * Verify database components.
+ * @param root         path to top of install tree
+ * @return             0 on success
+ */
+int rpmdbVerify(/*@null@*/ const char * root)
+               /*@modifies fileSystem @*/;
+
+/** \ingroup rpmdb
  * Close all database indices and free rpmdb.
  * @param rpmdb                rpm database
- * @return             0 always
+ * @return             0 on success
  */
 int rpmdbClose (/*@only@*/ /*@null@*/ rpmdb rpmdb)
                /*@modifies fileSystem @*/;
@@ -613,7 +621,7 @@ int rpmdbClose (/*@only@*/ /*@null@*/ rpmdb rpmdb)
 /** \ingroup rpmdb
  * Sync all database indices.
  * @param rpmdb                rpm database
- * @return             0 always
+ * @return             0 on success
  */
 int rpmdbSync (/*@null@*/ rpmdb rpmdb)
                /*@modifies fileSystem @*/;
@@ -621,7 +629,7 @@ int rpmdbSync (/*@null@*/ rpmdb rpmdb)
 /** \ingroup rpmdb
  * Open all database indices.
  * @param rpmdb                rpm database
- * @return             0 always
+ * @return             0 on success
  */
 int rpmdbOpenAll (/*@null@*/ rpmdb rpmdb)
                /*@modifies fileSystem @*/;
index a4912a7..1aef98a 100644 (file)
--- a/macros.in
+++ b/macros.in
@@ -1,7 +1,7 @@
 #/*! \page config_macros Default configuration: /usr/lib/rpm/macros
 # \verbatim
 #
-# $Id: macros.in,v 1.77 2001/05/14 20:12:10 jbj Exp $
+# $Id: macros.in,v 1.78 2001/05/25 19:51:53 jbj Exp $
 #
 # This is a global RPM configuration file. All changes made here will
 # be lost when the rpm package is upgraded. Any per-system configuration
 #   ht_dup     +++     (hash only) DB_DUP
 #   ht_dupsort +++     (hash only) DB_DUPSORT
 #----------------------- rpmdb specific configuration:
-#   usedbenv   +++     (on if not "traditional") Use db3 environment?
 #   usecursors         (always on) Use db3 cursors in get/put/del ?
+#   usedbenv   +++     (on if not "traditional") Use db3 environment?
+#   verify             (always on, db3 only) Verify db after close?
 #   lockdbfd           (always on for Packages) Use fcntl(2) locking ?
-#   nofsync            Disable fsync(2) call performed after every db3 write?
+#   nofsync            Disable fsync(2) call performed after db3 writes?
 #   temporary          Unlink file when closing.
 #
 # XXX Use a CDB database model for concurrent access (under development,
 # cursor teardown with signals needs work, much more besides.)
 #%__dbi_other                  usedbenv create joinenv cdb mpool \
-#                              mp_mmapsize=8Mb mp_size=512Kb usecursors
+#                              mp_mmapsize=8Mb mp_size=512Kb verify usecursors
 
 # XXX Use transactions and logs for rpmdb durability (no clue yet):
 #%__dbi_other                  usedbenv create joinenv mpool txn log \
-#                              mp_mmapsize=8Mb mp_size=512Kb usecursors
+#                              mp_mmapsize=8Mb mp_size=512Kb verify usecursors
 
 # XXX The "traditional" rpmdb shared/exclusive fcntl(2) lock on Packages model:
-%__dbi_other                   usecursors
+%__dbi_other                   verify usecursors
 
 # Note: adding nofsync here speeds up --rebuilddb a lot.
 %__dbi_rebuild                 nofsync !log !txn !cdb
diff --git a/rpm.c b/rpm.c
index 0e3cd66..35b4b81 100755 (executable)
--- a/rpm.c
+++ b/rpm.c
@@ -10,7 +10,7 @@
 #define GETOPT_ADDSIGN         1005
 #define GETOPT_RESIGN          1006
 #define GETOPT_DBPATH          1010
-#define GETOPT_REBUILDDB        1013
+#define GETOPT_REBUILDDB       1013
 #define GETOPT_INSTALL         1014
 #define GETOPT_RELOCATE                1016
 #define GETOPT_SHOWRC          1018
@@ -18,6 +18,7 @@
 #define        GETOPT_DEFINEMACRO      1020
 #define        GETOPT_EVALMACRO        1021
 #define        GETOPT_RCFILE           1022
+#define GETOPT_VERIFYDB                1023
 
 enum modes {
     MODE_UNKNOWN       = 0,
@@ -33,13 +34,14 @@ enum modes {
     MODE_QUERYTAGS     = (1 <<  9),
     MODE_INITDB                = (1 << 10),
     MODE_TARBUILD      = (1 << 11),
-    MODE_REBUILDDB     = (1 << 12)
+    MODE_REBUILDDB     = (1 << 12),
+    MODE_VERIFYDB      = (1 << 13)
 };
 
 #define        MODES_QV (MODE_QUERY | MODE_VERIFY)
 #define        MODES_BT (MODE_BUILD | MODE_TARBUILD | MODE_REBUILD | MODE_RECOMPILE)
 #define        MODES_IE (MODE_INSTALL | MODE_UNINSTALL)
-#define        MODES_DB (MODE_INITDB | MODE_REBUILDDB)
+#define        MODES_DB (MODE_INITDB | MODE_REBUILDDB | MODE_VERIFYDB)
 #define        MODES_K  (MODE_CHECKSIG | MODES_RESIGN)
 
 #define        MODES_FOR_DBPATH        (MODES_BT | MODES_IE | MODES_QV | MODES_DB)
@@ -184,6 +186,7 @@ static struct poptOption optionsTable[] = {
  { "rcfile", '\0', 0, 0, GETOPT_RCFILE,                NULL, NULL},
 #endif
  { "rebuilddb", '\0', 0, 0, GETOPT_REBUILDDB,  NULL, NULL},
+ { "verifydb", '\0', 0, 0, GETOPT_VERIFYDB,    NULL, NULL},
  { "relocate", '\0', POPT_ARG_STRING, 0, GETOPT_RELOCATE,      NULL, NULL},
  { "repackage", '\0', POPT_ARG_VAL, &rePackage, 1,     NULL, NULL},
  { "replacefiles", '\0', 0, &replaceFiles, 0,  NULL, NULL},
@@ -290,6 +293,7 @@ static void printUsage(void) {
     puts(_("       rpm {--checksig -K} [--nopgp] [--nogpg] [--nomd5] [--rcfile <file>]"));
     puts(_("                           package1 ... packageN"));
     puts(_("       rpm {--rebuilddb} [--rcfile <file>] [--dbpath <dir>]"));
+    puts(_("       rpm {--verifydb} [--rcfile <file>] [--dbpath <dir>]"));
     puts(_("       rpm {--querytags}"));
 }
 
@@ -557,6 +561,8 @@ static void printHelp(void) {
                  _("make sure a valid database exists"));
     printHelpLine(  "    --rebuilddb           ",
                  _("rebuild database from existing database"));
+    printHelpLine(  "    --verifydb            ",
+                 _("verify database files"));
     printHelpLine(_("      --dbpath <dir>      "),
                  _("use <dir> as the directory for the database"));
     printHelpLine(  "      --root <dir>        ",
@@ -810,6 +816,12 @@ int main(int argc, const char ** argv)
            bigMode = MODE_REBUILDDB;
            break;
 
+         case GETOPT_VERIFYDB:
+           if (bigMode != MODE_UNKNOWN && bigMode != MODE_VERIFYDB)
+               argerror(_("only one major mode may be specified"));
+           bigMode = MODE_VERIFYDB;
+           break;
+
          case GETOPT_RELOCATE:
            if (*optArg != '/') 
                argerror(_("relocations must begin with a /"));
@@ -1095,6 +1107,10 @@ int main(int argc, const char ** argv)
        ec = rpmdbRebuild(rootdir);
        break;
 
+      case MODE_VERIFYDB:
+       ec = rpmdbVerify(rootdir);
+       break;
+
       case MODE_QUERYTAGS:
        if (argc != 2)
            argerror(_("unexpected arguments to --querytags "));
index c3a8df3..43422a8 100644 (file)
@@ -44,7 +44,7 @@ falloc.lo: falloc.c $(top_srcdir)/system.h $(top_srcdir)/rpmio/rpmio.h falloc.h
 .PHONY: createlinks
 createlinks:
        for lo in $(DB3LOBJS); do \
-         [ -e $$lo ] || $(LN_S) $(top_builddir)/$(WITH_DB_SUBDIR)/$$lo $$lo ; \
+         [ -f $$lo ] || $(LN_S) $(top_builddir)/$(WITH_DB_SUBDIR)/$$lo $$lo ; \
        done
 
 clean-local:
index cb88f37..1af5f2f 100644 (file)
@@ -125,11 +125,6 @@ static int db1sync(dbiIndex dbi, unsigned int flags) {
     return rc;
 }
 
-static int db1byteswapped(/*@unused@*/dbiIndex dbi)
-{
-    return 0;
-}
-
 static void * doGetRecord(FD_t pkgs, unsigned int offset)
 {
     void * uh = NULL;
@@ -393,6 +388,23 @@ static int db1cput(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
     return rc;
 }
 
+static int db1ccount(dbiIndex dbi, DBC * dbcursor,
+               /*@out@*/ unsigned int * countp,
+               /*@unused@*/ unsigned int flags)
+{
+    return EINVAL;
+}
+
+static int db1byteswapped(/*@unused@*/dbiIndex dbi)
+{
+    return 0;
+}
+
+static int db1stat(dbiIndex dbi, unsigned int flags)
+{
+    return EINVAL;
+}
+
 static int db1close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
 {
     rpmdb rpmdb = dbi->dbi_rpmdb;
@@ -422,7 +434,7 @@ static int db1close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
        (void) unlink(fn);
     }
 
-    db3Free(dbi);
+    dbi = db3Free(dbi);
     base = _free(base);
     urlfn = _free(urlfn);
     return rc;
@@ -515,5 +527,5 @@ exit:
 struct _dbiVec db1vec = {
     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
     db1open, db1close, db1sync, db1copen, db1cclose, db1cdel, db1cget, db1cput,
-    db1byteswapped
+    db1ccount, db1byteswapped, db1stat
 };
index 7a59e87..af6d74f 100644 (file)
@@ -534,6 +534,13 @@ static int db2cget(dbiIndex dbi, DBC * dbcursor,
     return rc;
 }
 
+static int db2ccount(dbiIndex dbi, DBC * dbcursor,
+               /*@out@*/ unsigned int * countp,
+               /*@unused@*/ unsigned int flags)
+{
+    return EINVAL;
+}
+
 static int db2byteswapped(dbiIndex dbi)
 {
     int rc = 0;
@@ -547,6 +554,11 @@ static int db2byteswapped(dbiIndex dbi)
     return rc;
 }
 
+static int db2stat(dbiIndex dbi, unsigned int flags)
+{
+    return EINVAL;
+}
+
 static int db2close(/*@only@*/ dbiIndex dbi, unsigned int flags)
 {
     rpmdb rpmdb = dbi->dbi_rpmdb;
@@ -607,7 +619,7 @@ static int db2close(/*@only@*/ dbiIndex dbi, unsigned int flags)
 
     urlfn = _free(urlfn);
 
-    db3Free(dbi);
+    dbi = db3Free(dbi);
 
     return rc;
 }
@@ -875,7 +887,7 @@ static int db2open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
 struct _dbiVec db2vec = {
     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
     db2open, db2close, db2sync, db2copen, db2cclose, db2cdel, db2cget, db2cput,
-    db2byteswapped
+    db2ccount, db2byteswapped, db2stat
 };
 
 #endif /* DB_VERSION_MAJOR == 2 */
index 7daf6dc..34fe074 100644 (file)
@@ -30,6 +30,52 @@ typedef      int int32_t;
 /*@access dbiIndex@*/
 /*@access dbiIndexSet@*/
 
+/** \ingroup dbi
+ * Hash database statistics.
+ */
+struct dbiHStats_s {
+    unsigned int hash_magic;   /*!< hash database magic number. */
+    unsigned int hash_version; /*!< version of the hash database. */
+    unsigned int hash_nkeys;   /*!< no. of unique keys in the database. */
+    unsigned int hash_ndata;   /*!< no. of key/data pairs in the database. */
+    unsigned int hash_pagesize;        /*!< db page (and bucket) size, in bytes. */
+    unsigned int hash_nelem;   /*!< estimated size of the hash table. */
+    unsigned int hash_ffactor; /*!< no. of items per bucket. */
+    unsigned int hash_buckets; /*!< no. of hash buckets. */
+    unsigned int hash_free;    /*!< no. of pages on the free list. */
+    unsigned int hash_bfree;   /*!< no. of bytes free on bucket pages. */
+    unsigned int hash_bigpages;        /*!< no. of big key/data pages. */
+    unsigned int hash_big_bfree;/*!< no. of bytes free on big item pages. */
+    unsigned int hash_overflows;/*!< no. of overflow pages. */
+    unsigned int hash_ovfl_free;/*!< no. of bytes free on overflow pages. */
+    unsigned int hash_dup;     /*!< no. of duplicate pages. */
+    unsigned int hash_dup_free;        /*!< no. bytes free on duplicate pages. */
+};
+
+/** \ingroup dbi
+ * B-tree database statistics.
+ */
+struct dbiBStats_s {
+    unsigned int bt_magic;     /*!< btree database magic. */
+    unsigned int bt_version;   /*!< version of the btree database. */
+    unsigned int bt_nkeys;     /*!< no. of unique keys in the database. */
+    unsigned int bt_ndata;     /*!< no. of key/data pairs in the database. */
+    unsigned int bt_pagesize;  /*!< database page size, in bytes. */
+    unsigned int bt_minkey;    /*!< minimum keys per page. */
+    unsigned int bt_re_len;    /*!< length of fixed-length records. */
+    unsigned int bt_re_pad;    /*!< padding byte for fixed-length records. */
+    unsigned int bt_levels;    /*!< no. of levels in the database. */
+    unsigned int bt_int_pg;    /*!< no. of database internal pages. */
+    unsigned int bt_leaf_pg;   /*!< no. of database leaf pages. */
+    unsigned int bt_dup_pg;    /*!< no. of database duplicate pages. */
+    unsigned int bt_over_pg;   /*!< no. of database overflow pages. */
+    unsigned int bt_free;      /*!< no. of pages on the free list. */
+    unsigned int bt_int_pgfree;        /*!< no. of bytes free in internal pages. */
+    unsigned int bt_leaf_pgfree;/*!< no. of bytes free in leaf pages. */
+    unsigned int bt_dup_pgfree;        /*!< no. of bytes free in duplicate pages. */
+    unsigned int bt_over_pgfree;/*!< no. of bytes free in overflow pages. */
+};
+
 #if DB_VERSION_MAJOR == 3
 #define        __USE_DB3       1
 
@@ -132,7 +178,7 @@ static int db_fini(dbiIndex dbi, const char * dbhome,
     rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
 
     if (dbfile)
-       rpmMessage(RPMMESS_DEBUG, _("closed  db environment %s/%s\n"),
+       rpmMessage(RPMMESS_DEBUG, _("closed   db environment %s/%s\n"),
                        dbhome, dbfile);
 
     if (rpmdb->db_remove_env || dbi->dbi_tear_down) {
@@ -148,7 +194,7 @@ static int db_fini(dbiIndex dbi, const char * dbhome,
        xx = cvtdberr(dbi, "dbenv->remove", rc, _debug);
 
        if (dbfile)
-           rpmMessage(RPMMESS_DEBUG, _("removed db environment %s/%s\n"),
+           rpmMessage(RPMMESS_DEBUG, _("removed  db environment %s/%s\n"),
                        dbhome, dbfile);
 
     }
@@ -156,7 +202,7 @@ static int db_fini(dbiIndex dbi, const char * dbhome,
 #else  /* __USE_DB3 */
     rc = db_appexit(dbenv);
     rc = cvtdberr(dbi, "db_appexit", rc, _debug);
-    free(dbenv);
+    dbenv = _free(dbenv);
 #endif /* __USE_DB3 */
     dbi->dbi_dbenv = NULL;
     return rc;
@@ -301,7 +347,7 @@ errxit:
        xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
     }
 #else  /* __USE_DB3 */
-    if (dbenv) free(dbenv);
+    dbenv = _free(dbenv);
 #endif /* __USE_DB3 */
     return rc;
 }
@@ -575,6 +621,22 @@ static int db3cget(dbiIndex dbi, DBC * dbcursor,
     /*@=compmempass =nullstate@*/
 }
 
+static int db3ccount(dbiIndex dbi, DBC * dbcursor,
+               /*@out@*/ unsigned int * countp,
+               /*@unused@*/ unsigned int flags)
+{
+    db_recno_t count = 0;
+    int rc = 0;
+
+    flags = 0;
+    rc = dbcursor->c_count(dbcursor, &count, flags);
+    rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
+    if (rc) return rc;
+    if (countp) *countp = count;
+
+    return rc;
+}
+
 static int db3byteswapped(dbiIndex dbi)
 {
     DB * db = dbi->dbi_db;
@@ -588,6 +650,25 @@ static int db3byteswapped(dbiIndex dbi)
     return rc;
 }
 
+static int db3stat(dbiIndex dbi, unsigned int flags)
+{
+    DB * db = dbi->dbi_db;
+    int rc = 0;
+
+    if (db == NULL) return -2;
+#if defined(DB_FAST_STAT)
+    if (flags)
+       flags = DB_FAST_STAT;
+    else
+#endif
+       flags = 0;
+    dbi->dbi_stats = _free(dbi->dbi_stats);
+    rc = db->stat(db, &dbi->dbi_stats, flags);
+    rc = cvtdberr(dbi, "db->stat", rc, _debug);
+    return rc;
+}
+
+/** @todo Add/use per-rpmdb verify_on_close. */
 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
 {
     rpmdb rpmdb = dbi->dbi_rpmdb;
@@ -598,6 +679,8 @@ static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
     DB * db = dbi->dbi_db;
     int rc = 0, xx;
 
+    flags = 0; /* XXX unused */
+
     urlfn = rpmGenPath(
        (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root),
        (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home),
@@ -616,8 +699,6 @@ static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
 #endif
     }
 
-#if defined(__USE_DB2) || defined(__USE_DB3)
-
     if (dbi->dbi_rmw)
        rc = db3cclose(dbi, NULL, 0);
 
@@ -626,31 +707,65 @@ static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
        rc = cvtdberr(dbi, "db->close", rc, _debug);
        db = dbi->dbi_db = NULL;
 
-       rpmMessage(RPMMESS_DEBUG, _("closed  db index       %s/%s\n"),
+       rpmMessage(RPMMESS_DEBUG, _("closed   db index       %s/%s\n"),
                dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
 
     }
 
-    if (dbi->dbi_dbinfo) {
-       free(dbi->dbi_dbinfo);
-       dbi->dbi_dbinfo = NULL;
-    }
+    dbi->dbi_dbinfo = _free(dbi->dbi_dbinfo);
 
-    if (dbi->dbi_use_dbenv)
+    if (dbi->dbi_use_dbenv) {
        /*@-nullstate@*/
        xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
        /*@=nullstate@*/
+    }
 
-#else  /* __USE_DB2 || __USE_DB3 */
+    if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
+       DB_ENV * dbenv = NULL;
 
-    rc = db->close(db);
+       rc = db_env_create(&dbenv, 0);
+       rc = cvtdberr(dbi, "db_env_create", rc, _debug);
+       if (rc) goto exit;
 
-#endif /* __USE_DB2 || __USE_DB3 */
+       if (dbenv)      /* XXX can't happen. */
+       rc = dbenv->open(dbenv, dbhome,
+            DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0);
+       rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
+       if (rc) goto exit;
+
+       if (dbenv) {
+           rc = db_create(&db, dbenv, 0);
+           rc = cvtdberr(dbi, "db_create", rc, _debug);
+
+           if (db != NULL) {
+               const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
+
+               rc = db->verify(db, dbf, NULL, NULL, flags);
+               rc = cvtdberr(dbi, "db->verify", rc, _debug);
+
+               rpmMessage(RPMMESS_DEBUG, _("verified db index       %s/%s\n"),
+                       (dbhome ? dbhome : ""),
+                       (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
+
+               xx = db->close(db, 0);
+               xx = cvtdberr(dbi, "db->close", xx, _debug);
+               db = NULL;
+               if (rc == 0 && xx) rc = xx;
+
+               dbf = _free(dbf);
+           }
+           xx = dbenv->close(dbenv, 0);
+           xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
+           if (rc == 0 && xx) rc = xx;
+       }
+    }
+
+exit:
     dbi->dbi_db = NULL;
 
     urlfn = _free(urlfn);
 
-    db3Free(dbi);
+    dbi = db3Free(dbi);
 
     return rc;
 }
@@ -805,7 +920,7 @@ static int db3open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
     if (dbi->dbi_use_dbenv)
        rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
 
-    rpmMessage(RPMMESS_DEBUG, _("opening db index       %s/%s %s mode=0x%x\n"),
+    rpmMessage(RPMMESS_DEBUG, _("opening  db index       %s/%s %s mode=0x%x\n"),
                dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)),
                prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
 
@@ -992,7 +1107,7 @@ static int db3open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
                        rc = (!dbi->dbi_use_dbenv ? 1 : 0);
                    } else if (dbfile) {
                        rpmMessage(RPMMESS_DEBUG,
-                               _("locked  db index       %s/%s\n"),
+                               _("locked   db index       %s/%s\n"),
                                dbhome, dbfile);
                    }
                }
@@ -1045,8 +1160,10 @@ static int db3open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
     if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
        dbi->dbi_vec = &db3vec;
        *dbip = dbi;
-    } else
+    } else {
+       dbi->dbi_verify_on_close = 0;
        (void) db3close(dbi, 0);
+    }
 
     urlfn = _free(urlfn);
 
@@ -1060,7 +1177,7 @@ static int db3open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
 struct _dbiVec db3vec = {
     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
     db3open, db3close, db3sync, db3copen, db3cclose, db3cdel, db3cget, db3cput,
-    db3byteswapped
+    db3ccount, db3byteswapped, db3stat
 };
 
 #endif /* DB_VERSION_MAJOR == 3 */
index 061956c..35bd2c6 100644 (file)
@@ -137,6 +137,8 @@ struct dbOption rdbOptions[] = {
  { "sv_timeout", 0,POPT_ARG_LONG,      &db3dbi.dbi_sv_timeout, 0,
        NULL, NULL },
 
+ { "verify",   0,POPT_ARG_NONE,        &db3dbi.dbi_verify_on_close, 0,
+       NULL, NULL },
  { "teardown", 0,POPT_ARG_NONE,        &db3dbi.dbi_tear_down, 0,
        NULL, NULL },
  { "usecursors",0,POPT_ARG_NONE,       &db3dbi.dbi_use_cursors, 0,
@@ -295,7 +297,7 @@ static int dbSaveInt(const struct dbOption * opt, int argInfo, long aLong) {
     return 0;
 }
 
-void db3Free(dbiIndex dbi) {
+dbiIndex db3Free(dbiIndex dbi) {
     if (dbi) {
        dbi->dbi_root = _free(dbi->dbi_root);
        dbi->dbi_home = _free(dbi->dbi_home);
@@ -306,8 +308,10 @@ void db3Free(dbiIndex dbi) {
        dbi->dbi_re_source = _free(dbi->dbi_re_source);
        dbi->dbi_dbenv = _free(dbi->dbi_dbenv);
        dbi->dbi_dbinfo = _free(dbi->dbi_dbinfo);
+       dbi->dbi_stats = _free(dbi->dbi_stats);
        dbi = _free(dbi);
     }
+    return dbi;
 }
 
 static const char *db3_config_default =
index cfaa5d9..a2a4f75 100644 (file)
@@ -271,6 +271,32 @@ if (_debug < 0 || dbi->dbi_debug) {
     return rc;
 }
 
+INLINE int dbiCount(dbiIndex dbi, DBC * dbcursor,
+       unsigned int * countp, unsigned int flags)
+{
+    int rc = (*dbi->dbi_vec->ccount) (dbi, dbcursor, countp, flags);
+
+if (rc == 0 && countp && *countp > 1)
+fprintf(stderr, "    Count %s: %u rc %d\n", tagName(dbi->dbi_rpmtag), *countp, rc);
+
+    return rc;
+}
+
+INLINE int dbiVerify(dbiIndex dbi, unsigned int flags)
+{
+    int dbi_debug = dbi->dbi_debug;
+    int dbi_rpmtag = dbi->dbi_rpmtag;
+    int rc;
+
+    dbi->dbi_verify_on_close = 1;
+    rc = (*dbi->dbi_vec->close) (dbi, flags);
+
+if (_debug < 0 || dbi_debug)
+fprintf(stderr, "    Verify %s rc %d\n", tagName(dbi_rpmtag), rc);
+
+    return rc;
+}
+
 INLINE int dbiClose(dbiIndex dbi, unsigned int flags) {
 if (_debug < 0 || dbi->dbi_debug)
 fprintf(stderr, "    Close %s\n", tagName(dbi->dbi_rpmtag));
@@ -363,12 +389,10 @@ dbiIndex dbiOpen(rpmdb rpmdb, int rpmtag, /*@unused@*/ unsigned int flags)
     }
 
 exit:
-    if (rc == 0 && dbi) {
+    if (rc == 0 && dbi)
        rpmdb->_dbi[dbix] = dbi;
-    } else if (dbi) {
-       db3Free(dbi);
-       dbi = NULL;
-    }
+    else
+       dbi = db3Free(dbi);
 
     return dbi;
 }
@@ -664,8 +688,8 @@ unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
 /* XXX transaction.c */
 void dbiFreeIndexSet(dbiIndexSet set) {
     if (set) {
-       if (set->recs) free(set->recs);
-       free(set);
+       set->recs = _free(set->recs);
+       set = _free(set);
     }
 }
 
@@ -712,9 +736,10 @@ static void unblockSignals(rpmdb rpmdb, sigset_t * oldMask)
 };
 /*@=fullinitblock@*/
 
-int rpmdbOpenAll (rpmdb rpmdb)
+int rpmdbOpenAll(rpmdb rpmdb)
 {
     int dbix;
+    int rc = 0;
 
     if (rpmdb == NULL) return -2;
 
@@ -724,20 +749,24 @@ int rpmdbOpenAll (rpmdb rpmdb)
            continue;
        (void) dbiOpen(rpmdb, dbiTags[dbix], rpmdb->db_flags);
     }
-    return 0;
+    return rc;
 }
 
 /* XXX query.c, rpminstall.c, verify.c */
-int rpmdbClose (rpmdb rpmdb)
+int rpmdbClose(rpmdb rpmdb)
 {
     int dbix;
+    int rc = 0;
 
     if (rpmdb == NULL) return 0;
+    if (rpmdb->_dbi)
     for (dbix = rpmdb->db_ndbi; --dbix >= 0; ) {
+       int xx;
        if (rpmdb->_dbi[dbix] == NULL)
            continue;
-       /*@-unqualifiedtrans@*/
-       (void) dbiClose(rpmdb->_dbi[dbix], 0);
+       /*@-unqualifiedtrans@*/         /* FIX: double indirection. */
+       xx = dbiClose(rpmdb->_dbi[dbix], 0);
+       if (xx && rc == 0) rc = xx;
        rpmdb->_dbi[dbix] = NULL;
        /*@=unqualifiedtrans@*/
     }
@@ -746,12 +775,13 @@ int rpmdbClose (rpmdb rpmdb)
     rpmdb->db_home = _free(rpmdb->db_home);
     rpmdb->_dbi = _free(rpmdb->_dbi);
     rpmdb = _free(rpmdb);
-    return 0;
+    return rc;
 }
 
 int rpmdbSync(rpmdb rpmdb)
 {
     int dbix;
+    int rc = 0;
 
     if (rpmdb == NULL) return 0;
     for (dbix = 0; dbix < rpmdb->db_ndbi; dbix++) {
@@ -759,8 +789,9 @@ int rpmdbSync(rpmdb rpmdb)
        if (rpmdb->_dbi[dbix] == NULL)
            continue;
        xx = dbiSync(rpmdb->_dbi[dbix], 0);
+       if (xx && rc == 0) rc = xx;
     }
-    return 0;
+    return rc;
 }
 
 static /*@only@*/ /*@null@*/
@@ -934,8 +965,42 @@ int rpmdbInit (const char * prefix, int perms)
     rc = openDatabase(prefix, NULL, _dbapi, &rpmdb, (O_CREAT | O_RDWR),
                perms, RPMDB_FLAG_JUSTCHECK);
     if (rpmdb) {
-       (void) rpmdbOpenAll(rpmdb);
-       (void) rpmdbClose(rpmdb);
+       int xx;
+       xx = rpmdbOpenAll(rpmdb);
+       if (xx && rc == 0) rc = xx;
+       xx = rpmdbClose(rpmdb);
+       if (xx && rc == 0) rc = xx;
+       rpmdb = NULL;
+    }
+    return rc;
+}
+
+int rpmdbVerify(const char * prefix)
+{
+    rpmdb rpmdb = NULL;
+    int _dbapi = rpmExpandNumeric("%{_dbapi}");
+    int rc = 0;
+
+    rc = openDatabase(prefix, NULL, _dbapi, &rpmdb, O_RDONLY, 0644, 0);
+    if (rc) return rc;
+
+    if (rpmdb) {
+       int dbix;
+       int xx;
+       rc = rpmdbOpenAll(rpmdb);
+
+       for (dbix = rpmdb->db_ndbi; --dbix >= 0; ) {
+           if (rpmdb->_dbi[dbix] == NULL)
+               continue;
+           /*@-unqualifiedtrans@*/             /* FIX: double indirection. */
+           xx = dbiVerify(rpmdb->_dbi[dbix], 0);
+           if (xx && rc == 0) rc = xx;
+           rpmdb->_dbi[dbix] = NULL;
+           /*@=unqualifiedtrans@*/
+       }
+
+       xx = rpmdbClose(rpmdb);
+       if (xx && rc == 0) rc = xx;
        rpmdb = NULL;
     }
     return rc;
@@ -1271,7 +1336,7 @@ static int dbiUpdateRecord(dbiIndex dbi, DBC * dbcursor, int offset, Header h)
        rc = dbiPut(dbi, dbcursor, &offset, sizeof(offset), uh, uhlen, 0);
        xx = dbiSync(dbi, 0);
        unblockSignals(dbi->dbi_rpmdb, &signalMask);
-       free(uh);
+       uh = _free(uh);
     }
     return rc;
 }
@@ -1283,6 +1348,7 @@ struct _rpmdbMatchIterator {
     int                        mi_rpmtag;
     dbiIndexSet                mi_set;
     DBC *              mi_dbc;
+    unsigned int       mi_ndups;
     int                        mi_setx;
 /*@null@*/ Header      mi_h;
     int                        mi_sorted;
@@ -1511,7 +1577,7 @@ exit:
 #ifdef NOTNOW
     if (mi->mi_h) {
        const char *n, *v, *r;
-       headerNVR(mi->mi_h, &n, &v, &r);
+       (void) headerNVR(mi->mi_h, &n, &v, &r);
        rpmMessage(RPMMESS_DEBUG, "%s-%s-%s at 0x%x, h %p\n", n, v, r,
                mi->mi_offset, mi->mi_h);
     }
@@ -1882,10 +1948,7 @@ int rpmdbRemove(rpmdb rpmdb, int rid, unsigned int hdrNum)
            rpmcnt = 0;
        }
 
-       if (rec) {
-           free(rec);
-           rec = NULL;
-       }
+       rec = _free(rec);
     }
 
     unblockSignals(rpmdb, &signalMask);
@@ -2183,10 +2246,7 @@ int rpmdbAdd(rpmdb rpmdb, int iid, Header h)
            rpmcnt = 0;
        }
 
-       if (rec) {
-           free(rec);
-           rec = NULL;
-       }
+       rec = _free(rec);
     }
 
 exit:
@@ -2499,7 +2559,7 @@ int rpmdbRebuild(const char * rootdir)
     int nocleanup = 1;
     int failed = 0;
     int removedir = 0;
-    int rc = 0;
+    int rc = 0, xx;
     int _dbapi;
     int _dbapi_rebuild;
 
@@ -2645,14 +2705,14 @@ int rpmdbRebuild(const char * rootdir)
        olddb->db_remove_env = 1;
        newdb->db_remove_env = 1;
     }
-    (void) rpmdbClose(olddb);
-    (void) rpmdbClose(newdb);
+    xx = rpmdbClose(olddb);
+    xx = rpmdbClose(newdb);
 
     if (failed) {
        rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
                "remains in place\n"));
 
-       (void) rpmdbRemoveDatabase(rootdir, newdbpath, _dbapi_rebuild);
+       xx = rpmdbRemoveDatabase(rootdir, newdbpath, _dbapi_rebuild);
        rc = 1;
        goto exit;
     } else if (!nocleanup) {
index b3de114..8764f3f 100644 (file)
@@ -68,7 +68,7 @@ struct _dbiVec {
     int (*open) (rpmdb rpmdb, int rpmtag, /*@out@*/ dbiIndex * dbip);
 
 /** \ingroup dbi
- * Close index database.
+ * Close index database, and destroy database handle.
  * @param dbi          index database handle
  * @param flags                (unused)
  * @return             0 on success
@@ -143,16 +143,36 @@ struct _dbiVec {
                        unsigned int flags);
 
 /** \ingroup dbi
+ * Retrieve count of (possible) duplicate items using dbcursor->c_count.
+ * @param dbi          index database handle
+ * @param dbcursor     database cursor
+ * @param countp       address of count
+ * @param flags                (unused)
+ * @return             0 on success
+ */
+    int (*ccount) (dbiIndex dbi, DBC * dbcursor,
+                       /*@out@*/ unsigned int * countp,
+                       unsigned int flags);
+
+/** \ingroup dbi
  * Is database byte swapped?
  * @param dbi          index database handle
  * @return             0 no
  */
     int (*byteswapped) (dbiIndex dbi);
 
+/** \ingroup dbi
+ * Save statistics in database handle.
+ * @param dbi          index database handle
+ * @param flags                retrieve statistics that don't require traversal?
+ * @return             0 on success
+ */
+    int (*stat) (dbiIndex dbi, unsigned int flags);
+
 };
 
 /** \ingroup dbi
- * Describes an index database (implemented on Berkeley db[123] API).
+ * Describes an index database (implemented on Berkeley db3 functionality).
  */
 struct _dbiIndex {
 /*@null@*/ const char *        dbi_root;
@@ -173,6 +193,7 @@ struct _dbiIndex {
     long               dbi_shmkey;     /*!< shared memory base key */
     int                        dbi_api;        /*!< Berkeley API type */
 
+    int                        dbi_verify_on_close;
     int                        dbi_tear_down;  /*!< tear down dbenv on close */
     int                        dbi_use_cursors;/*!< access with cursors? (always) */
     int                        dbi_use_dbenv;  /*!< use db environment? */
@@ -243,9 +264,10 @@ struct _dbiIndex {
     unsigned int dbi_lastoffset;       /*!< db1 with falloc.c needs this */
 
 /*@only@*//*@null@*/ void * dbi_db;    /*!< dbi handle */
-/*@only@*//*@null@*/ void * dbi_dbenv;
-/*@only@*//*@null@*/ void * dbi_dbinfo;
+/*@only@*//*@null@*/ void * dbi_dbenv; /*!< */
+/*@only@*//*@null@*/ void * dbi_dbinfo;        /*!< */
 /*@only@*//*@null@*/ void * dbi_rmw;   /*!< db cursor (with DB_WRITECURSOR) */
+/*@only@*//*@null@*/ void * dbi_stats; /*!< */
 
 /*@observer@*/ const struct _dbiVec * dbi_vec; /*!< private methods */
 
@@ -298,8 +320,9 @@ extern "C" {
 /** \ingroup db3
  * Destroy index database handle instance.
  * @param dbi          index database handle
+ * @return             NULL always
  */
-void db3Free( /*@only@*/ /*@null@*/ dbiIndex dbi);
+/*@null@*/ dbiIndex db3Free( /*@only@*/ /*@null@*/ dbiIndex dbi);
 
 /** \ingroup db3
  * Format db3 open flags for debugging print.
@@ -382,6 +405,25 @@ int dbiPut(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen,
        const void * datap, size_t datalen, unsigned int flags);
 
 /** \ingroup dbi
+ * Retrieve count of (possible) duplicate items.
+ * @param dbi          index database handle
+ * @param dbcursor     database cursor
+ * @param countp       address of count
+ * @param flags                (unused)
+ * @return             0 on success
+ */
+int dbiCount(dbiIndex dbi, DBC * dbcursor, /*@out@*/ unsigned int * countp,
+       unsigned int flags);
+
+/** \ingroup dbi
+ * Verify (and close) index database.
+ * @param dbi          index database handle
+ * @param flags                (unused)
+ * @return             0 on success
+ */
+int dbiVerify(/*@only@*/ dbiIndex dbi, unsigned int flags);
+
+/** \ingroup dbi
  * Close index database.
  * @param dbi          index database handle
  * @param flags                (unused)
index 4bd30a9..c8f1cbb 100644 (file)
@@ -138,6 +138,7 @@ rpm exec --short-circuit    rpmb --short-circuit
 
 rpm    exec --initdb           rpmd --initdb
 rpm    exec --rebuilddb        rpmd --rebuilddb
+rpm    exec --verifydb         rpmd --verifydb
 
 #rpm   exec -e                 rpme -e
 #rpm   exec --erase            rpme --erase
diff --git a/rpmqv.c b/rpmqv.c
index ba54d66..d77569b 100755 (executable)
--- a/rpmqv.c
+++ b/rpmqv.c
@@ -20,7 +20,8 @@
 #endif
 
 #ifdef IAM_RPMDB
-#define GETOPT_REBUILDDB        1013
+#define GETOPT_REBUILDDB       1013
+#define GETOPT_VERIFYDB                1023
 static int initdb = 0;
 #endif
 
@@ -76,7 +77,8 @@ enum modes {
 
     MODE_INITDB                = (1 << 10),
     MODE_REBUILDDB     = (1 << 12),
-#define        MODES_DB (MODE_INITDB | MODE_REBUILDDB)
+    MODE_VERIFYDB      = (1 << 13),
+#define        MODES_DB (MODE_INITDB | MODE_REBUILDDB | MODE_VERIFYDB)
 
     MODE_UNKNOWN       = 0
 };
@@ -182,6 +184,9 @@ static struct poptOption rpmDatabasePoptTable[] = {
  { "rebuilddb", '\0', 0, 0, GETOPT_REBUILDDB,
        N_("rebuild database inverted lists from installed package headers"),
        NULL},
+ { "verifydb", '\0', 0, 0, GETOPT_VERIFYDB,
+       N_("verify database files"),
+       NULL},
  { "nodirtokens", '\0', POPT_ARG_VAL, &_noDirTokens, 1,
        N_("generate headers compatible with (legacy) rpm[23] packaging"),
        NULL},
@@ -938,6 +943,11 @@ int main(int argc, const char ** argv)
                argerror(_("only one major mode may be specified"));
            bigMode = MODE_REBUILDDB;
            break;
+         case GETOPT_VERIFYDB:
+           if (bigMode != MODE_UNKNOWN && bigMode != MODE_VERIFYDB)
+               argerror(_("only one major mode may be specified"));
+           bigMode = MODE_VERIFYDB;
+           break;
 #endif
 
 #ifdef IAM_RPMK
@@ -1285,6 +1295,9 @@ int main(int argc, const char ** argv)
       case MODE_REBUILDDB:
        ec = rpmdbRebuild(rootdir);
        break;
+      case MODE_VERIFYDB:
+       ec = rpmdbVerify(rootdir);
+       break;
 #if !defined(__LCLINT__)
       case MODE_QUERY:
       case MODE_VERIFY:
@@ -1404,6 +1417,7 @@ int main(int argc, const char ** argv)
       case MODE_RESIGN:
       case MODE_INITDB:
       case MODE_REBUILDDB:
+      case MODE_VERIFYDB:
        if (!showVersion && !help && !noUsageMsg) printUsage();
        break;
 #endif
@@ -1472,6 +1486,7 @@ int main(int argc, const char ** argv)
       case MODE_RESIGN:
       case MODE_INITDB:
       case MODE_REBUILDDB:
+      case MODE_VERIFYDB:
        if (!showVersion && !help && !noUsageMsg) printUsage();
        break;
 #endif
@@ -1534,6 +1549,7 @@ int main(int argc, const char ** argv)
       case MODE_RESIGN:
       case MODE_INITDB:
       case MODE_REBUILDDB:
+      case MODE_VERIFYDB:
        if (!showVersion && !help && !noUsageMsg) printUsage();
        break;
 #endif
@@ -1570,6 +1586,7 @@ int main(int argc, const char ** argv)
       case MODE_TARBUILD:
       case MODE_INITDB:
       case MODE_REBUILDDB:
+      case MODE_VERIFYDB:
        if (!showVersion && !help && !noUsageMsg) printUsage();
        break;
 #endif