]> git.pld-linux.org Git - packages/rpm.git/blame - rpm-5.4.14-rpmdbchk.patch
use libexec directory for private binaries - optional since FHS 3.0
[packages/rpm.git] / rpm-5.4.14-rpmdbchk.patch
CommitLineData
0004e9b0
ER
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 \
6 xiu-echo xiu-hash \
7- roto rpmkey sandbox semodule spooktool
8+ roto rpmdbchk rpmkey sandbox semodule spooktool
9
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@
15 if WITH_DB
16-pkgbin_PROGRAMS += dbconvert
17+pkgbin_PROGRAMS += dbconvert rpmdbchk
18 endif
19 dist_man_MANS = rpmgrep.1
20
21@@ -234,6 +234,13 @@ rpm2cpio_LDFLAGS = @LDFLAGS_STATIC@ $(LD
22 rpm2cpio_LDADD = $(LDFLAGS) $(RPM_LDADD_COMMON)
23
24 ##
25+## rpmdbchk tool for finding and fixing broken headers
26+##
27+rpmdbchk_SOURCES = rpmdbchk.c
28+rpmdbchk_LDFLAGS = @LDFLAGS_STATIC@ $(LDFLAGS)
29+rpmdbchk_LDADD = $(LDFLAGS) $(RPM_LDADD_COMMON)
30+
31+##
32 ## keyctl(1) clone
33 ##
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
37@@ -0,0 +1,297 @@
38+#include <arpa/inet.h>
39+#include <stdint.h>
40+#include <sys/types.h>
41+#include <sys/stat.h>
42+#include <fcntl.h>
43+#include <errno.h>
44+#include <popt.h>
45+
46+#include <rpmio.h>
47+#include <rpmlog.h>
48+#include <rpmmacro.h>
49+#include <argv.h>
50+
51+#define _RPMTAG_INTERNAL
52+#define _RPMDB_INTERNAL
53+#define WITH_DB
54+#include <rpmdb.h>
55+
56+#include <rpmts.h>
57+#include <rpmrc.h>
58+#include <pkgio.h>
59+#include <rpmcli.h>
60+
61+static char *rootPath = NULL;
62+static char *rpmdbPath = NULL;
63+static int checkOnly = 0;
64+
65+struct node {
66+ uint32_t state;
67+ uint32_t keysize;
68+ void *keydata;
69+ struct node *next;
70+};
71+
72+static int
73+rpmdb_check(uint32_t **state, uint32_t *nkeys, struct node **broken)
74+{
75+ rpmts ts = NULL;
76+ DBC *dbcp = NULL;
77+ dbiIndex dbi = NULL;
78+ DBT key;
79+ DBT data;
80+ DB_TXN *txnid = NULL;
81+ DB *bdb;
82+
83+ uint32_t hdrNum = 0;
84+ uint32_t damaged = 0;
85+ float pct = 0;
86+ uint8_t tmp;
87+
88+ int xx;
89+
90+ ts = rpmtsCreate();
91+
92+ rpmtsSetRootDir(ts, rootPath && rootPath[0] ? rootPath : NULL);
93+ if(rpmtsOpenDB(ts, O_RDONLY))
94+ goto exit;
95+
96+ dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_PACKAGES, 0);
97+
98+ if ((xx = dbiCopen(dbi, NULL, NULL, 0)))
99+ goto exit;
100+
101+ txnid = dbiTxnid(dbi);
102+ *nkeys = 0;
103+
104+ memset(&key, 0, sizeof(key));
105+ memset(&data, 0, sizeof(data));
106+ bdb = dbi->dbi_db;
107+
108+ /* Acquire a cursor for the database. */
109+ xx = bdb->cursor(bdb, NULL, &dbcp, 0);
110+ if (xx)
111+ bdb->err(bdb, xx, "DB->cursor");
112+
113+ xx = bdb->stat(bdb, txnid, &dbi->dbi_stats, 0);
114+ if (xx)
115+ goto exit;
116+
117+ switch (bdb->type) {
118+ case DB_BTREE:
119+ case DB_RECNO:{
120+ DB_BTREE_STAT *db_stat = dbi->dbi_stats;
121+ *nkeys = db_stat->bt_nkeys;
122+ } break;
123+ case DB_HASH:{
124+ DB_HASH_STAT *db_stat = dbi->dbi_stats;
125+ *nkeys = db_stat->hash_nkeys;
126+ } break;
127+ case DB_QUEUE:{
128+ DB_QUEUE_STAT *db_stat = dbi->dbi_stats;
129+ *nkeys = db_stat->qs_nkeys;
130+ } break;
131+ case DB_UNKNOWN:
132+ default:
133+ xx = -1;
134+ goto exit;
135+ break;
136+ }
137+ uint32_t *status = calloc(*nkeys, sizeof(uint32_t));
138+ struct node *curr;
139+
140+ hdrNum = 0;
141+ pct = 0;
142+
143+ while ((xx = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
144+ tmp = pct;
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);
151+ }
152+ const char *msg = NULL;
153+ int lvl = headerCheck(rpmtsDig(ts), data.data, data.size, &msg);
154+ rpmtsCleanDig(ts);
155+ if (lvl == RPMRC_FAIL) {
156+ status[hdrNum-1] = htonl(*(uint32_t*)(dbcp->rkey->data));
157+ damaged++;
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;
166+ *broken = curr;
167+ status[hdrNum-1] = -1;
168+ damaged++;
169+ fprintf(stderr, "\n%d: %s (key.size(%d) != %d)\n", hdrNum-1, msg, key.size, sizeof(hdrNum));
170+ } else
171+ status[hdrNum-1] = -1;
172+ fflush(stderr);
173+ }
174+
175+ fprintf(stderr, "\n");
176+
177+
178+ *state = status;
179+ xx = dbiCclose(dbi, dbcp, 0);
180+
181+exit:
182+ xx = rpmtsCloseDB(ts);
183+ ts = rpmtsFree(ts);
184+
185+ return damaged;
186+}
187+
188+static int
189+rpmdb_dump_delete(DB *dbp, const char *db, const char *lost, DBT *key, uint32_t n) {
190+ int gotrec;
191+ int ret = 0;
192+ DBT data;
193+
194+ memset(&data, 0, sizeof(data));
195+
196+ if ((ret = dbp->get(dbp, NULL, key, &data, 0)) == 0) {
197+ char copy[1024];
198+ snprintf(copy, sizeof(copy), "%s/header.%d", lost, n);
199+ FILE *fp = fopen(copy, "w");
200+ fwrite(data.data, data.size, 1, fp);
201+ fclose(fp);
202+ gotrec = 0;
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);
208+ } else {
209+ dbp->err(dbp, ret, "DB->get");
210+ if (ret == DB_NOTFOUND)
211+ return 0;
212+ return ret;
213+ }
214+
215+ if ((ret = dbp->del(dbp, NULL, key, 0)) == 0) {
216+ gotrec = 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);
221+ } else {
222+ dbp->err(dbp, ret, "DB->del");
223+ return ret;
224+ }
225+ return 0;
226+}
227+
228+static int
229+rpmdb_fix(uint32_t *state, uint32_t nkeys, struct node *broken)
230+{
231+ DB * dbp;
232+ DBT key;
233+ struct stat sb;
234+ const char * db = rpmGetPath(rootPath && rootPath[0] ? rootPath : "", rpmdbPath, "/Packages", NULL);
235+ const char * lost = rpmGetPath(rootPath && rootPath[0] ? rootPath : "", rpmdbPath, "/broken", NULL);
236+ int ret, t_ret;
237+ uint32_t i;
238+
239+
240+ if ((ret = db_create(&dbp, NULL, 0)) != 0) {
241+ fprintf(stderr, "db_create: %s\n", db_strerror(ret));
242+ exit (1);
243+ }
244+
245+ if (Stat(lost, &sb))
246+ Mkdir(lost, 0700);
247+
248+ if ((ret = dbp->open(dbp, NULL, db, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
249+ dbp->err(dbp, ret, "%s", db);
250+ goto err;
251+ }
252+
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);
262+
263+ ret = rpmdb_dump_delete(dbp, db, lost, &key, state[i]);
264+ }
265+
266+ while (broken) {
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);
272+ free(broken);
273+ broken = broken->next;
274+ }
275+
276+
277+err:
278+ if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
279+ ret = t_ret;
280+ _free(db);
281+ _free(lost);
282+
283+ return 0;
284+}
285+
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},
293+
294+ POPT_AUTOALIAS
295+ POPT_AUTOHELP
296+ POPT_TABLEEND
297+};
298+
299+int main(int argc, char *argv[])
300+{
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;
308+
309+ if (ac) {
310+ poptPrintUsage(optCon, stderr, 0);
311+ goto exit;
312+ }
313+
314+ rc = rpmReadConfigFiles(NULL, NULL);
315+
316+ if(!rpmdbPath)
317+ rpmdbPath = rpmExpand("%{?_dbpath}%{?!_dbpath:/var/lib/rpm}", NULL);
318+ else
319+ addMacro(NULL, "_dbpath", NULL, rpmdbPath, -1);
320+
321+
322+ rc = rpmdb_check(&state, &nkeys, &broken);
323+ printf("%d/%d (%f%%) headers damaged", rc, nkeys, (float)rc/nkeys);
324+ printf("\n");
325+ if (!checkOnly && rc) {
326+ printf("fixing...\n");
327+ rc = rpmdb_fix(state, nkeys, broken);
328+ }
329+
330+exit:
331+ _free(state);
332+ optCon = rpmcliFini(optCon);
333+ return rc;
334+}
This page took 0.060837 seconds and 4 git commands to generate.