rpm/rpm-5.4.10-rpmdbchk.patch

334 lines
8.5 KiB
Diff
Raw Permalink Normal View History

--- rpm-5.4.10/tools/Makefile.am.rpmdbchk~ 2012-05-04 17:58:08.000000000 +0200
+++ rpm-5.4.10/tools/Makefile.am 2013-04-02 09:11:56.264985289 +0200
@@ -29,7 +29,7 @@ EXTRA_PROGRAMS = augtool cudftool dbconv
nix-env nix-hash nix-install-package nix-instantiate \
nix-log2xml nix-prefetch-url nix-pull nix-push nix-store nix-worker \
xiu-echo xiu-hash xiu-instantiate xiu-store \
- roto rpmkey sandbox semodule spooktool
+ roto rpmdbchk rpmkey sandbox semodule spooktool
RPMMISC_LDADD_COMMON = \
$(top_builddir)/misc/librpmmisc.la \
@@ -60,7 +60,7 @@ pkgbin_PROGRAMS = \
rpmcache rpmdigest rpmrepo rpmspecdump \
rpmcmp rpmdeps sqlite3 @WITH_KEYUTILS_RPMKEY@ @WITH_LIBELF_DEBUGEDIT@
if WITH_DB
-pkgbin_PROGRAMS += dbconvert
+pkgbin_PROGRAMS += dbconvert rpmdbchk
endif
dist_man_MANS = rpmgrep.1
@@ -230,6 +230,13 @@ rpm2cpio_LDFLAGS = @LDFLAGS_STATIC@ $(LD
rpm2cpio_LDADD = $(LDFLAGS) $(RPM_LDADD_COMMON)
##
+## rpmdbchk tool for finding and fixing broken headers
+##
+rpmdbchk_SOURCES = rpmdbchk.c
+rpmdbchk_LDFLAGS = @LDFLAGS_STATIC@ $(LDFLAGS)
+rpmdbchk_LDADD = $(LDFLAGS) $(RPM_LDADD_COMMON)
+
+##
## keyctl(1) clone
##
rpmkey_SOURCES = rpmkey.c
--- rpm-5.4.10/tools/rpmdbchk.c.rpmdbchk~ 2013-04-02 09:11:56.264985289 +0200
+++ rpm-5.4.10/tools/rpmdbchk.c 2013-04-06 01:03:20.082982283 +0200
@@ -0,0 +1,296 @@
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <popt.h>
+
+#include <rpmio.h>
+#include <rpmlog.h>
+#include <rpmmacro.h>
+#include <argv.h>
+
+#define _RPMTAG_INTERNAL
+#define _RPMDB_INTERNAL
+#define WITH_DB
+#include <rpmdb.h>
+
+#include <rpmts.h>
+#include <rpmrc.h>
+#include <pkgio.h>
+#include <rpmcli.h>
+
+static char *rootPath = NULL;
+static char *rpmdbPath = NULL;
+static int checkOnly = 0;
+
+struct node {
+ uint32_t state;
+ uint32_t keysize;
+ void *keydata;
+ struct node *next;
+};
+
+static int
+rpmdb_check(const char *prefix, const char *path, uint32_t **state, uint32_t *nkeys, struct node **broken)
+{
+ rpmts ts = NULL;
+
+ const char * dbpath = path ? path : rpmExpand("%{?_dbpath}", NULL);
+
+ DBC *dbcp = NULL;
+ dbiIndex dbi = NULL;
+ DBT key;
+ DBT data;
+ DB_TXN *txnid = NULL;
+ DB *bdb;
+
+ uint32_t hdrNum = 0;
+ uint32_t damaged = 0;
+ float pct = 0;
+ uint8_t tmp;
+
+ int xx;
+
+ ts = rpmtsCreate();
+
+ addMacro(NULL, "_dbpath", NULL, dbpath, -1);
+ rpmtsSetRootDir(ts, prefix && prefix[0] ? prefix : NULL);
+ if(rpmtsOpenDB(ts, O_RDONLY))
+ goto exit;
+
+ dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_PACKAGES, 0);
+
+ if ((xx = dbiCopen(dbi, NULL, NULL, 0)))
+ goto exit;
+
+ txnid = dbiTxnid(dbi);
+ *nkeys = 0;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ bdb = dbi->dbi_db;
+
+ /* Acquire a cursor for the database. */
+ xx = bdb->cursor(bdb, NULL, &dbcp, 0);
+ if (xx)
+ bdb->err(bdb, xx, "DB->cursor");
+
+ xx = bdb->stat(bdb, txnid, &dbi->dbi_stats, 0);
+ if (xx)
+ goto exit;
+
+ switch (bdb->type) {
+ case DB_BTREE:
+ case DB_RECNO:{
+ DB_BTREE_STAT *db_stat = dbi->dbi_stats;
+ *nkeys = db_stat->bt_nkeys;
+ } break;
+ case DB_HASH:{
+ DB_HASH_STAT *db_stat = dbi->dbi_stats;
+ *nkeys = db_stat->hash_nkeys;
+ } break;
+ case DB_QUEUE:{
+ DB_QUEUE_STAT *db_stat = dbi->dbi_stats;
+ *nkeys = db_stat->qs_nkeys;
+ } break;
+ case DB_UNKNOWN:
+ default:
+ xx = -1;
+ goto exit;
+ break;
+ }
+ uint32_t *status = calloc(*nkeys, sizeof(uint32_t));
+ struct node *curr;
+
+ hdrNum = 0;
+ pct = 0;
+
+ while ((xx = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
+ tmp = pct;
+ pct = (100 * (float) ++hdrNum / *nkeys) + 0.5;
+ /* TODO: callbacks for status output? */
+ if (tmp < (int) (pct + 0.5)) {
+ fprintf(stderr, "\rchecking %s%s/Packages: %u/%u %d%%",
+ prefix && prefix[0] ? prefix : "",
+ dbpath, hdrNum, *nkeys, (int) pct);
+ }
+ const char *msg = NULL;
+ int lvl = headerCheck(rpmtsDig(ts), data.data, data.size, &msg);
+ rpmtsCleanDig(ts);
+ if (lvl == RPMRC_FAIL) {
+ status[hdrNum-1] = htonl(*(uint32_t*)(dbcp->rkey->data));
+ damaged++;
+ fprintf(stderr, "\n%d (%d): %s\n", hdrNum-1, status[hdrNum-1], msg);
+ } else if (key.size != sizeof(hdrNum)) {
+ curr = malloc(sizeof(struct node));
+ curr->state = htonl(*(uint32_t*)(dbcp->rkey->data));
+ curr->keysize = key.size;
+ curr->keydata = malloc(key.size);
+ memcpy(curr->keydata, key.data, key.size);
+ curr->next = *broken;
+ *broken = curr;
+ status[hdrNum-1] = -1;
+ damaged++;
+ fprintf(stderr, "\n%d: %s (key.size(%d) != %d)\n", hdrNum-1, msg, key.size, sizeof(hdrNum));
+ } else
+ status[hdrNum-1] = -1;
+ fflush(stderr);
+ }
+
+ fprintf(stderr, "\n");
+
+
+ *state = status;
+ xx = dbiCclose(dbi, dbcp, 0);
+
+exit:
+ xx = rpmtsCloseDB(ts);
+ ts = rpmtsFree(ts);
+
+ return damaged;
+}
+
+static int
+rpmdb_dump_delete(DB *dbp, const char *db, const char *lost, DBT *key, uint32_t n) {
+ int gotrec;
+ int ret = 0;
+ DBT data;
+
+ memset(&data, 0, sizeof(data));
+
+ if ((ret = dbp->get(dbp, NULL, key, &data, 0)) == 0) {
+ char copy[1024];
+ snprintf(copy, sizeof(copy), "%s/header.%d", lost, n);
+ FILE *fp = fopen(copy, "w");
+ fwrite(data.data, data.size, 1, fp);
+ fclose(fp);
+ gotrec = 0;
+ memcpy(&gotrec, key->data, sizeof(gotrec));
+ printf("db: get key: %p[%d] = 0x%x, data at %p[%d].\n",
+ (char *)key->data, key->size, gotrec,
+ (char *)data.data, data.size);
+ printf("Dumping broken header to disk: %s\n", copy);
+ } else {
+ dbp->err(dbp, ret, "DB->get");
+ if (ret == DB_NOTFOUND)
+ return 0;
+ return ret;
+ }
+
+ if ((ret = dbp->del(dbp, NULL, key, 0)) == 0) {
+ gotrec = 0;
+ memcpy(&gotrec, key->data, sizeof(gotrec));
+ printf("db: del key: %p[%d] = 0x%x, data at %p[%d].\n",
+ (char *)key->data, key->size, gotrec,
+ (char *)data.data, data.size);
+ } else {
+ dbp->err(dbp, ret, "DB->del");
+ return ret;
+ }
+ return 0;
+}
+
+static int
+rpmdb_fix(const char *prefix, const char *path, uint32_t *state, uint32_t nkeys, struct node *broken)
+{
+ DB * dbp;
+ DBT key;
+ struct stat sb;
+ const char * db = rpmGetPath(prefix && prefix[0] ? prefix : "", path, "/Packages", NULL);
+ const char * lost = rpmGetPath(prefix && prefix[0] ? prefix : "", path, "/broken", NULL);
+ int ret, t_ret;
+ uint32_t i;
+
+
+ if ((ret = db_create(&dbp, NULL, 0)) != 0) {
+ fprintf(stderr, "db_create: %s\n", db_strerror(ret));
+ exit (1);
+ }
+
+ if (Stat(lost, &sb))
+ Mkdir(lost, 0700);
+
+ if ((ret = dbp->open(dbp, NULL, db, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
+ dbp->err(dbp, ret, "%s", db);
+ goto err;
+ }
+
+ for (i = 0; i < nkeys; i++) {
+ if (state[i] == -1) continue;
+ int badrec, badrec2;
+ memset(&key, 0, sizeof(key));
+ badrec2 = state[i];
+ badrec = htonl(badrec2);
+ printf("fix record[%d] at #%d/#%d --\n", i, badrec2, badrec);
+ key.data = &badrec;
+ key.size = sizeof(badrec);
+
+ ret = rpmdb_dump_delete(dbp, db, lost, &key, state[i]);
+ }
+
+ while (broken) {
+ memset(&key, 0, sizeof(key));
+ key.size = broken->keysize;
+ key.data = broken->keydata;
+ ret = rpmdb_dump_delete(dbp, db, lost, &key, broken->state);
+ free(broken->keydata);
+ free(broken);
+ broken = broken->next;
+ }
+
+
+err:
+ if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
+ ret = t_ret;
+ _free(db);
+ _free(lost);
+
+ return 0;
+}
+
+static struct poptOption optionsTable[] = {
+ { "root", '\0', POPT_ARG_STRING, &rootPath, 0,
+ "rpm root path", "path"},
+ { "dbpath", '\0', POPT_ARG_STRING, &rpmdbPath, 0,
+ "rpmdb path", "path"},
+ { "checkonly", '\0', POPT_ARG_VAL, &checkOnly, 1,
+ "only check, don't fix anything", NULL},
+
+ POPT_AUTOALIAS
+ POPT_AUTOHELP
+ POPT_TABLEEND
+};
+
+int main(int argc, char *argv[])
+{
+ poptContext optCon = rpmcliInit(argc, argv, optionsTable);
+ ARGV_t av = poptGetArgs(optCon);
+ int ac = argvCount(av);
+ int rc = 2; /* assume failure */
+ uint32_t nkeys = 0;
+ uint32_t *state = NULL;
+ struct node *broken = NULL;
+
+ if (ac) {
+ poptPrintUsage(optCon, stderr, 0);
+ goto exit;
+ }
+
+ rc = rpmReadConfigFiles(NULL, NULL);
+
+
+ rc = rpmdb_check(rootPath, rpmdbPath, &state, &nkeys, &broken);
+ printf("%d/%d (%f%%) headers damaged", rc, nkeys, (float)rc/nkeys);
+ printf("\n");
+ if (!checkOnly && rc) {
+ printf("fixing...\n");
+ rc = rpmdb_fix(rootPath, rpmdbPath, state, nkeys, broken);
+ }
+
+exit:
+ _free(state);
+ optCon = rpmcliFini(optCon);
+ return rc;
+}