1 --- rpm-5.4.14/tools/Makefile.am.rpmdbchk~ 2013-08-18 21:40:58.000000000 +0200
2 +++ rpm-5.4.14/tools/Makefile.am 2014-02-17 17:52:10.032157038 +0100
3 @@ -33,7 +33,7 @@ EXTRA_PROGRAMS += augtool cudftool dbcon
4 nix-build nix-channel nix-collect-garbage \
5 nix-log2xml nix-prefetch-url nix-pull nix-push \
7 - roto rpmkey sandbox semodule spooktool
8 + roto rpmdbchk rpmkey sandbox semodule spooktool
10 RPMMISC_LDADD_COMMON = \
11 $(top_builddir)/misc/librpmmisc.la \
12 @@ -64,7 +64,7 @@ pkgbin_PROGRAMS = \
13 rpmcache rpmdigest rpmrepo rpmspecdump \
14 rpmcmp rpmdeps sqlite3 @WITH_KEYUTILS_RPMKEY@ @WITH_LIBELF_DEBUGEDIT@
16 -pkgbin_PROGRAMS += dbconvert
17 +pkgbin_PROGRAMS += dbconvert rpmdbchk
19 dist_man_MANS = rpmgrep.1
21 @@ -234,6 +234,13 @@ rpm2cpio_LDFLAGS = @LDFLAGS_STATIC@ $(LD
22 rpm2cpio_LDADD = $(LDFLAGS) $(RPM_LDADD_COMMON)
25 +## rpmdbchk tool for finding and fixing broken headers
27 +rpmdbchk_SOURCES = rpmdbchk.c
28 +rpmdbchk_LDFLAGS = @LDFLAGS_STATIC@ $(LDFLAGS)
29 +rpmdbchk_LDADD = $(LDFLAGS) $(RPM_LDADD_COMMON)
34 rpmkey_SOURCES = rpmkey.c
35 --- rpm-5.4.14/tools/rpmdbchk.c.rpmdbchk~ 2014-02-17 17:52:10.032157038 +0100
36 +++ rpm-5.4.14/tools/rpmdbchk.c 2014-02-17 17:52:28.846342856 +0100
38 +#include <arpa/inet.h>
40 +#include <sys/types.h>
41 +#include <sys/stat.h>
48 +#include <rpmmacro.h>
51 +#define _RPMTAG_INTERNAL
52 +#define _RPMDB_INTERNAL
61 +static char *rootPath = NULL;
62 +static char *rpmdbPath = NULL;
63 +static int checkOnly = 0;
73 +rpmdb_check(uint32_t **state, uint32_t *nkeys, struct node **broken)
77 + dbiIndex dbi = NULL;
80 + DB_TXN *txnid = NULL;
83 + uint32_t hdrNum = 0;
84 + uint32_t damaged = 0;
92 + rpmtsSetRootDir(ts, rootPath && rootPath[0] ? rootPath : NULL);
93 + if(rpmtsOpenDB(ts, O_RDONLY))
96 + dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_PACKAGES, 0);
98 + if ((xx = dbiCopen(dbi, NULL, NULL, 0)))
101 + txnid = dbiTxnid(dbi);
104 + memset(&key, 0, sizeof(key));
105 + memset(&data, 0, sizeof(data));
108 + /* Acquire a cursor for the database. */
109 + xx = bdb->cursor(bdb, NULL, &dbcp, 0);
111 + bdb->err(bdb, xx, "DB->cursor");
113 + xx = bdb->stat(bdb, txnid, &dbi->dbi_stats, 0);
117 + switch (bdb->type) {
120 + DB_BTREE_STAT *db_stat = dbi->dbi_stats;
121 + *nkeys = db_stat->bt_nkeys;
124 + DB_HASH_STAT *db_stat = dbi->dbi_stats;
125 + *nkeys = db_stat->hash_nkeys;
128 + DB_QUEUE_STAT *db_stat = dbi->dbi_stats;
129 + *nkeys = db_stat->qs_nkeys;
137 + uint32_t *status = calloc(*nkeys, sizeof(uint32_t));
143 + while ((xx = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
145 + pct = (100 * (float) ++hdrNum / *nkeys) + 0.5;
146 + /* TODO: callbacks for status output? */
147 + if (tmp < (int) (pct + 0.5)) {
148 + fprintf(stderr, "\rchecking %s%s/Packages: %u/%u %d%%",
149 + rootPath && rootPath[0] ? rootPath : "",
150 + rpmdbPath, hdrNum, *nkeys, (int) pct);
152 + const char *msg = NULL;
153 + int lvl = headerCheck(rpmtsDig(ts), data.data, data.size, &msg);
155 + if (lvl == RPMRC_FAIL) {
156 + status[hdrNum-1] = htonl(*(uint32_t*)(dbcp->rkey->data));
158 + fprintf(stderr, "\n%d (%d): %s\n", hdrNum-1, status[hdrNum-1], msg);
159 + } else if (key.size != sizeof(hdrNum)) {
160 + curr = malloc(sizeof(struct node));
161 + curr->state = htonl(*(uint32_t*)(dbcp->rkey->data));
162 + curr->keysize = key.size;
163 + curr->keydata = malloc(key.size);
164 + memcpy(curr->keydata, key.data, key.size);
165 + curr->next = *broken;
167 + status[hdrNum-1] = -1;
169 + fprintf(stderr, "\n%d: %s (key.size(%d) != %d)\n", hdrNum-1, msg, key.size, sizeof(hdrNum));
171 + status[hdrNum-1] = -1;
175 + fprintf(stderr, "\n");
179 + xx = dbiCclose(dbi, dbcp, 0);
182 + xx = rpmtsCloseDB(ts);
183 + ts = rpmtsFree(ts);
189 +rpmdb_dump_delete(DB *dbp, const char *db, const char *lost, DBT *key, uint32_t n) {
194 + memset(&data, 0, sizeof(data));
196 + if ((ret = dbp->get(dbp, NULL, key, &data, 0)) == 0) {
198 + snprintf(copy, sizeof(copy), "%s/header.%d", lost, n);
199 + FILE *fp = fopen(copy, "w");
200 + fwrite(data.data, data.size, 1, fp);
203 + memcpy(&gotrec, key->data, sizeof(gotrec));
204 + printf("db: get key: %p[%d] = 0x%x, data at %p[%d].\n",
205 + (char *)key->data, key->size, gotrec,
206 + (char *)data.data, data.size);
207 + printf("Dumping broken header to disk: %s\n", copy);
209 + dbp->err(dbp, ret, "DB->get");
210 + if (ret == DB_NOTFOUND)
215 + if ((ret = dbp->del(dbp, NULL, key, 0)) == 0) {
217 + memcpy(&gotrec, key->data, sizeof(gotrec));
218 + printf("db: del key: %p[%d] = 0x%x, data at %p[%d].\n",
219 + (char *)key->data, key->size, gotrec,
220 + (char *)data.data, data.size);
222 + dbp->err(dbp, ret, "DB->del");
229 +rpmdb_fix(uint32_t *state, uint32_t nkeys, struct node *broken)
234 + const char * db = rpmGetPath(rootPath && rootPath[0] ? rootPath : "", rpmdbPath, "/Packages", NULL);
235 + const char * lost = rpmGetPath(rootPath && rootPath[0] ? rootPath : "", rpmdbPath, "/broken", NULL);
240 + if ((ret = db_create(&dbp, NULL, 0)) != 0) {
241 + fprintf(stderr, "db_create: %s\n", db_strerror(ret));
245 + if (Stat(lost, &sb))
248 + if ((ret = dbp->open(dbp, NULL, db, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
249 + dbp->err(dbp, ret, "%s", db);
253 + for (i = 0; i < nkeys; i++) {
254 + if (state[i] == -1) continue;
255 + int badrec, badrec2;
256 + memset(&key, 0, sizeof(key));
257 + badrec2 = state[i];
258 + badrec = htonl(badrec2);
259 + printf("fix record[%d] at #%d/#%d --\n", i, badrec2, badrec);
260 + key.data = &badrec;
261 + key.size = sizeof(badrec);
263 + ret = rpmdb_dump_delete(dbp, db, lost, &key, state[i]);
267 + memset(&key, 0, sizeof(key));
268 + key.size = broken->keysize;
269 + key.data = broken->keydata;
270 + ret = rpmdb_dump_delete(dbp, db, lost, &key, broken->state);
271 + free(broken->keydata);
273 + broken = broken->next;
278 + if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
286 +static struct poptOption optionsTable[] = {
287 + { "root", '\0', POPT_ARG_STRING, &rootPath, 0,
288 + "rpm root path", "path"},
289 + { "dbpath", '\0', POPT_ARG_STRING, &rpmdbPath, 0,
290 + "rpmdb path", "path"},
291 + { "checkonly", '\0', POPT_ARG_VAL, &checkOnly, 1,
292 + "only check, don't fix anything", NULL},
299 +int main(int argc, char *argv[])
301 + poptContext optCon = rpmcliInit(argc, argv, optionsTable);
302 + ARGV_t av = poptGetArgs(optCon);
303 + int ac = argvCount(av);
304 + int rc = 2; /* assume failure */
305 + uint32_t nkeys = 0;
306 + uint32_t *state = NULL;
307 + struct node *broken = NULL;
310 + poptPrintUsage(optCon, stderr, 0);
314 + rc = rpmReadConfigFiles(NULL, NULL);
317 + rpmdbPath = rpmExpand("%{?_dbpath}%{?!_dbpath:/var/lib/rpm}", NULL);
319 + addMacro(NULL, "_dbpath", NULL, rpmdbPath, -1);
322 + rc = rpmdb_check(&state, &nkeys, &broken);
323 + printf("%d/%d (%f%%) headers damaged", rc, nkeys, (float)rc/nkeys);
325 + if (!checkOnly && rc) {
326 + printf("fixing...\n");
327 + rc = rpmdb_fix(state, nkeys, broken);
332 + optCon = rpmcliFini(optCon);