]> git.pld-linux.org Git - packages/rpm.git/blob - rpm-5.4.14-rpmdbchk.patch
- missing #include
[packages/rpm.git] / rpm-5.4.14-rpmdbchk.patch
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.070792 seconds and 3 git commands to generate.