]>
Commit | Line | Data |
---|---|---|
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 | +} |