From 243041f5fb68b68102243d713a1c5a3dc52698a2 Mon Sep 17 00:00:00 2001
From: Michael Schroeder <mls@suse.de>
Date: Mon, 3 Feb 2020 14:20:19 +0100
Subject: [PATCH] Add a --salvagedb option to the rpmdb tool

URL:https://github.com/rpm-software-management/rpm/commit/243041f5fb68b68102243d713a1c5a3dc52698a2
---
 lib/backend/dbi.h      | 1 +
 lib/backend/ndb/glue.c | 7 +++++--
 lib/rpmdb.c            | 7 +++++--
 lib/rpmdb_internal.h   | 8 +++++++-
 lib/rpmts.c            | 8 ++++++--
 rpmdb.c                | 6 ++++++
 6 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h
index c4bf387..f70eb33 100644
--- a/lib/backend/dbi.h
+++ b/lib/backend/dbi.h
@@ -10,6 +10,7 @@ enum rpmdbFlags {
     RPMDB_FLAG_JUSTCHECK	= (1 << 0),
     RPMDB_FLAG_REBUILD		= (1 << 1),
     RPMDB_FLAG_VERIFYONLY	= (1 << 2),
+    RPMDB_FLAG_SALVAGE		= (1 << 3),
 };
 
 typedef enum dbCtrlOp_e {
diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c
index d19da7c..ae30ceb 100644
--- a/lib/backend/ndb/glue.c
+++ b/lib/backend/ndb/glue.c
@@ -128,8 +128,11 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
 	rpmpkgdb pkgdb = 0;
 	char *path = rstrscat(NULL, dbhome, "/", rdb->db_ops->path, NULL);
 	rpmlog(RPMLOG_DEBUG, "opening  db index       %s mode=0x%x\n", path, rdb->db_mode);
-	rc = rpmpkgOpen(&pkgdb, path, oflags, 0666);
- 	if (rc && errno == ENOENT) {
+	if ((rdb->db_flags & RPMDB_FLAG_SALVAGE) == 0)
+	    rc = rpmpkgOpen(&pkgdb, path, oflags, 0666);
+	else
+	    rc = rpmpkgSalvage(&pkgdb, path);
+ 	if (rc && errno == ENOENT && (rdb->db_flags & RPMDB_FLAG_SALVAGE) == 0) {
 	    oflags = O_RDWR|O_CREAT;
 	    dbi->dbi_flags |= DBI_CREATED;
 	    rc = rpmpkgOpen(&pkgdb, path, oflags, 0666);
diff --git a/lib/rpmdb.c b/lib/rpmdb.c
index 91543eb..a072813 100644
--- a/lib/rpmdb.c
+++ b/lib/rpmdb.c
@@ -2479,7 +2479,8 @@ static int rpmdbSetPermissions(char * src, char * dest)
 }
 
 int rpmdbRebuild(const char * prefix, rpmts ts,
-		rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
+		rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg),
+		int rebuildflags)
 {
     rpmdb olddb;
     char * dbpath = NULL;
@@ -2519,7 +2520,9 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
     }
 
     if (openDatabase(prefix, dbpath, &olddb,
-		     O_RDONLY, 0644, RPMDB_FLAG_REBUILD)) {
+		     O_RDONLY, 0644, RPMDB_FLAG_REBUILD |
+		     (rebuildflags & RPMDB_REBUILD_FLAG_SALVAGE ?
+		         RPMDB_FLAG_SALVAGE : 0))) {
 	rc = 1;
 	goto exit;
     }
diff --git a/lib/rpmdb_internal.h b/lib/rpmdb_internal.h
index 5ad844c..d7446e5 100644
--- a/lib/rpmdb_internal.h
+++ b/lib/rpmdb_internal.h
@@ -23,6 +23,10 @@ extern "C" {
 #undef HTKEYTYPE
 #undef HTDATATYPE
 
+enum rpmdbRebuildFlags_e {
+    RPMDB_REBUILD_FLAG_SALVAGE	= (1 << 0),
+};
+
 /** \ingroup rpmdb
  * Reference a database instance.
  * @param db		rpm database
@@ -63,11 +67,13 @@ int rpmdbClose (rpmdb db);
  * @param prefix	path to top of install tree
  * @param ts		transaction set (or NULL)
  * @param (*hdrchk)	headerCheck() vector (or NULL)
+ * @param rebuildflags	flags
  * @return		0 on success
  */
 RPM_GNUC_INTERNAL
 int rpmdbRebuild(const char * prefix, rpmts ts,
-		rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg));
+		rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg),
+		int rebuildflags);
 
 /** \ingroup rpmdb
  * Verify database components.
diff --git a/lib/rpmts.c b/lib/rpmts.c
index d0fdfbe..eb98da7 100644
--- a/lib/rpmts.c
+++ b/lib/rpmts.c
@@ -135,17 +135,21 @@ int rpmtsRebuildDB(rpmts ts)
 {
     int rc = -1;
     rpmtxn txn = NULL;
+    int rebuildflags = 0;
 
     /* Cannot do this on a populated transaction set */
     if (rpmtsNElements(ts) > 0)
 	return -1;
 
+    if (rpmExpandNumeric("%{?_rebuilddb_salvage}"))
+	rebuildflags |= RPMDB_REBUILD_FLAG_SALVAGE;
+
     txn = rpmtxnBegin(ts, RPMTXN_WRITE);
     if (txn) {
 	if (!(ts->vsflags & RPMVSF_NOHDRCHK))
-	    rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
+	    rc = rpmdbRebuild(ts->rootDir, ts, headerCheck, rebuildflags);
 	else
-	    rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
+	    rc = rpmdbRebuild(ts->rootDir, NULL, NULL, rebuildflags);
 	rpmtxnEnd(txn);
     }
     return rc;
diff --git a/rpmdb.c b/rpmdb.c
index 25c088d..b72f0a5 100644
--- a/rpmdb.c
+++ b/rpmdb.c
@@ -12,6 +12,7 @@ enum modes {
     MODE_VERIFYDB	= (1 << 2),
     MODE_EXPORTDB	= (1 << 3),
     MODE_IMPORTDB	= (1 << 4),
+    MODE_SALVAGEDB	= (1 << 5),
 };
 
 static int mode = 0;
@@ -24,6 +25,8 @@ static struct poptOption dbOptsTable[] = {
 	NULL},
     { "verifydb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN),
 	&mode, MODE_VERIFYDB, N_("verify database files"), NULL},
+    { "salvagedb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN),
+	&mode, MODE_SALVAGEDB, N_("salvage database"), NULL},
     { "exportdb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_EXPORTDB,
 	N_("export database to stdout header list"),
 	NULL},
@@ -108,8 +111,11 @@ int main(int argc, char *argv[])
 	ec = rpmtsInitDB(ts, 0644);
 	break;
     case MODE_REBUILDDB:
+    case MODE_SALVAGEDB:
     {   rpmVSFlags vsflags = rpmExpandNumeric("%{_vsflags_rebuilddb}");
 	rpmVSFlags ovsflags = rpmtsSetVSFlags(ts, vsflags);
+	if (mode == MODE_SALVAGEDB)
+	    rpmDefineMacro(NULL, "_rebuilddb_salvage 1", 0);
 	ec = rpmtsRebuildDB(ts);
 	rpmtsSetVSFlags(ts, ovsflags);
     }	break;
-- 
1.8.3.1

