diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h index c4bf38787..f70eb331f 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 d19da7c5c..ae30ceb9c 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 91543eb68..a07281376 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 5ad844c71..d7446e58f 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 d0fdfbed9..eb98da7b0 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 25c088da9..b72f0a598 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;