rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmcache.c
Go to the documentation of this file.
1
5 #include "system.h"
6 const char *__progname;
7
8 #include <fnmatch.h>
9 #include <fts.h>
10
11 #include <rpmio.h>
12 #include <rpmiotypes.h>
13 #include <poptIO.h>
14
15 #include <rpmtypes.h>
16 #include <rpmtag.h>
17
18 #include "rpmdb.h"
19
20 #include "rpmps.h"
21
22 #include "misc.h" /* XXX rpmMkdirPath */
23
24 #define _RPMGI_INTERNAL
25 #include <rpmgi.h>
26
27 #include <rpmcli.h>
28
29 #include "debug.h"
30
31 static int _debug = 0;
32
33 /* XXX should be flag in ts */
34 static int noCache = -1;
35
36 static ARGV_t ftsSet;
37
38 const char * bhpath;
39 int bhpathlen = 0;
40 int bhlvl = -1;
41
42 struct ftsglob_s {
43 const char ** patterns;
44 int fnflags;
45 };
46
47 static struct ftsglob_s * bhglobs;
48 static int nbhglobs = 5;
49
50 static int indent = 2;
51
52 typedef struct Item_s {
53 const char * path;
54 uint32_t size;
55 uint32_t mtime;
56 rpmds this;
57 Header h;
58 } * Item;
59
60 static Item * items = NULL;
61 static int nitems = 0;
62
63 static inline Item freeItem(Item item) {
64 if (item != NULL) {
65 item->path = _free(item->path);
66 (void)rpmdsFree(item->this);
67 item->this = NULL;
68 (void)headerFree(item->h);
69 item->h = NULL;
70 item = _free(item);
71 }
72 return NULL;
73 }
74
75 static inline Item newItem(void) {
76 Item item = xcalloc(1, sizeof(*item));
77 return item;
78 }
79
80 static int cmpItem(const void * a, const void * b) {
81 Item aitem = *(Item *)a;
82 Item bitem = *(Item *)b;
83 int rc = strcmp(rpmdsN(aitem->this), rpmdsN(bitem->this));
84 return rc;
85 }
86
87 static void freeItems(void) {
88 int i;
89 for (i = 0; i < nitems; i++)
90 items[i] = freeItem(items[i]);
91 items = _free(items);
92 nitems = 0;
93 }
94
95 static int ftsCachePrint(/*@unused@*/ rpmts ts, FILE * fp)
96 {
97 int rc = 0;
98 int i;
99
100 if (fp == NULL) fp = stdout;
101 for (i = 0; i < nitems; i++) {
102 Item ip;
103
104 ip = items[i];
105 if (ip == NULL) {
106 rc = 1;
107 break;
108 }
109
110 fprintf(fp, "%s\n", ip->path);
111 }
112 return rc;
113 }
114
115 static int ftsCacheUpdate(rpmts ts)
116 {
117 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
118 uint32_t tid = rpmtsGetTid(ts);
119 rpmmi mi;
120 unsigned char * md5;
121 int rc = 0;
122 int xx;
123 int i;
124
125 rc = rpmtsCloseDB(ts);
126 rc = rpmDefineMacro(NULL, "_dbpath %{_cache_dbpath}", RMIL_CMDLINE);
127 rc = rpmtsOpenDB(ts, O_RDWR);
128 if (rc != 0)
129 return rc;
130
131 for (i = 0; i < nitems; i++) {
132 Item ip;
133
134 ip = items[i];
135 if (ip == NULL) {
136 rc = 1;
137 break;
138 }
139
140 /* --- Check that identical package is not already cached. */
141 he->tag = RPMTAG_SIGMD5;
142 xx = headerGet(ip->h, he, 0);
143 md5 = he->p.ui8p;
144 if (!xx || md5 == NULL) {
145 md5 = _free(md5);
146 rc = 1;
147 break;
148 }
149 mi = rpmtsInitIterator(ts, RPMTAG_SIGMD5, md5, 16);
150 md5 = _free(md5);
151 rc = rpmmiCount(mi);
152 mi = rpmmiFree(mi);
153 if (rc) {
154 rc = 0;
155 continue;
156 }
157
158 /* --- Add cache tags to new cache header. */
159 he->tag = RPMTAG_CACHECTIME;
160 he->t = RPM_UINT32_TYPE;
161 he->p.ui32p = &tid;
162 he->c = 1;
163 he->append = 1;
164 rc = headerPut(ip->h, he, 0);
165 he->append = 0;
166 if (rc != 1) break;
167
168 he->tag = RPMTAG_CACHEPKGPATH;
169 he->t = RPM_STRING_ARRAY_TYPE;
170 he->p.argv = &ip->path;
171 he->c = 1;
172 he->append = 1;
173 rc = headerPut(ip->h, he, 0);
174 he->append = 0;
175 if (rc != 1) break;
176
177 he->tag = RPMTAG_CACHEPKGSIZE;
178 he->t = RPM_UINT32_TYPE;
179 he->p.ui32p = &ip->size;
180 he->c = 1;
181 he->append = 1;
182 rc = headerPut(ip->h, he, 0);
183 he->append = 0;
184 if (rc != 1) break;
185
186 he->tag = RPMTAG_CACHEPKGMTIME;
187 he->t = RPM_UINT32_TYPE;
188 he->p.ui32p = &ip->mtime;
189 he->c = 1;
190 he->append = 1;
191 rc = headerPut(ip->h, he, 0);
192 he->append = 0;
193 if (rc != 1) break;
194
195 /* --- Add new cache header to database. */
196 if (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
197 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, ip->h, ts);
198 else
199 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, ip->h, NULL);
200 if (rc) break;
201
202 }
203 xx = rpmtsCloseDB(ts);
204 return rc;
205 }
206
207 static rpmRC cacheStashLatest(rpmgi gi, Header h)
208 {
209 FTSENT * fts = gi->fts;
210 rpmds add = NULL;
211 struct stat sb, * st;
212 int ec = -1; /* assume not found */
213 int i = 0;
214 int xx;
215
216 rpmlog(RPMLOG_DEBUG, "============== %s\n", fts->fts_accpath);
217
218 /* XXX DIEDIEDIE: check platform compatibility. */
219
220 add = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_LESS));
221
222 if (items != NULL && nitems > 0) {
223 Item needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
224 Item * found, * fneedle = &needle;
225
226 needle->this = add;
227
228 found = bsearch(fneedle, items, nitems, sizeof(*found), cmpItem);
229
230 /* Rewind to the first item with same name. */
231 while (found > items && cmpItem(found-1, fneedle) == 0)
232 found--;
233
234 /* Check that all saved items are newer than this item. */
235 if (found != NULL)
236 while (found < (items + nitems) && cmpItem(found, fneedle) == 0) {
237 ec = rpmdsCompare(needle->this, (*found)->this);
238 if (ec == 0) {
239 found++;
240 continue;
241 }
242 i = found - items;
243 break;
244 }
245 }
246
247 /*
248 * At this point, ec is
249 * -1 no item with the same name has been seen.
250 * 0 item exists, but already saved item EVR is newer.
251 * 1 item exists, but already saved item EVR is same/older.
252 */
253 if (ec == 0) {
254 goto exit;
255 } else if (ec == 1) {
256 items[i] = freeItem(items[i]);
257 } else {
258 i = nitems++;
259 items = xrealloc(items, nitems * sizeof(*items));
260 }
261
262 items[i] = newItem();
263 items[i]->path = xstrdup(fts->fts_path);
264 st = fts->fts_statp;
265 if (st == NULL || ((long)st & 0xffff0000) == 0L) {
266 st = &sb;
267 memset(st, 0, sizeof(*st));
268 xx = Stat(fts->fts_accpath, &sb);
269 }
270
271 if (st != NULL) {
272 items[i]->size = st->st_size;
273 items[i]->mtime = st->st_mtime;
274 }
275 st = NULL;
276 items[i]->this = rpmdsThis(h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
277 items[i]->h = headerLink(h);
278
279 if (nitems > 1)
280 qsort(items, nitems, sizeof(*items), cmpItem);
281
282 #if 0
283 fprintf(stderr, "\t%*s [%d] %s\n",
284 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
285 i, fts->fts_name);
286 #endif
287
288 exit:
289 (void)rpmdsFree(add);
290 add = NULL;
291 return (ec ? RPMRC_NOTFOUND : RPMRC_OK);
292 }
293
294 static const char * ftsInfoStrings[] = {
295 "UNKNOWN",
296 "D",
297 "DC",
298 "DEFAULT",
299 "DNR",
300 "DOT",
301 "DP",
302 "ERR",
303 "F",
304 "INIT",
305 "NS",
306 "NSOK",
307 "SL",
308 "SLNONE",
309 "W",
310 };
311
312 static const char * ftsInfoStr(int fts_info) {
313 if (!(fts_info >= 1 && fts_info <= 14))
314 fts_info = 0;
315 return ftsInfoStrings[ fts_info ];
316 }
317
318 static rpmRC cacheWalkPathFilter(rpmgi gi)
319 {
320 FTS * ftsp = gi->ftsp;
321 FTSENT * fts = gi->fts;
322 struct ftsglob_s * bhg;
323 const char ** patterns;
324 const char * pattern;
325 const char * s;
326 int lvl;
327 int xx;
328
329 switch (fts->fts_info) {
330 case FTS_D: /* preorder directory */
331 if (fts->fts_pathlen < bhpathlen)
332 break;
333
334 /* Grab the level of the beehive top directory. */
335 if (bhlvl < 0) {
336 if (fts->fts_pathlen == bhpathlen && !strcmp(fts->fts_path, bhpath))
337 bhlvl = fts->fts_level;
338 else
339 break;
340 }
341 lvl = fts->fts_level - bhlvl;
342
343 if (lvl < 0)
344 break;
345
346 #if 0
347 if (_debug)
348 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
349 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
350 fts->fts_name);
351 #endif
352
353 /* Full path glob expression check. */
354 bhg = bhglobs;
355
356 if ((patterns = bhg->patterns) != NULL)
357 while ((pattern = *patterns++) != NULL) {
358 if (*pattern == '/')
359 xx = fnmatch(pattern, fts->fts_path, bhg->fnflags);
360 else
361 xx = fnmatch(pattern, fts->fts_name, bhg->fnflags);
362 if (xx == 0)
363 break;
364 }
365
366 /* Level specific glob expression check(s). */
367 if (lvl == 0 || lvl >= nbhglobs)
368 break;
369 bhg += lvl;
370
371 if ((patterns = bhg->patterns) != NULL)
372 while ((pattern = *patterns++) != NULL) {
373 if (*pattern == '/')
374 xx = fnmatch(pattern, fts->fts_path, bhg->fnflags);
375 else
376 xx = fnmatch(pattern, fts->fts_name, bhg->fnflags);
377 if (xx == 0)
378 break;
379 else
380 xx = Fts_set(ftsp, fts, FTS_SKIP);
381 }
382
383 break;
384 case FTS_DP: /* postorder directory */
385 #if 0
386 if (_debug)
387 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
388 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
389 fts->fts_name);
390 #endif
391 break;
392 case FTS_F: /* regular file */
393 #if 0
394 if (_debug)
395 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
396 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
397 fts->fts_name);
398 #endif
399 if (fts->fts_level >= 0) {
400 /* Ignore source packages. */
401 if (!strcmp(fts->fts_parent->fts_name, "SRPMS")) {
402 xx = Fts_set(ftsp, fts->fts_parent, FTS_SKIP);
403 break;
404 }
405 }
406
407 /* Ignore all but *.rpm files. */
408 s = fts->fts_name + fts->fts_namelen + 1 - sizeof(".rpm");
409 if (strcmp(s, ".rpm"))
410 break;
411
412 break;
413 case FTS_NS: /* stat(2) failed */
414 case FTS_DNR: /* unreadable directory */
415 case FTS_ERR: /* error; errno is set */
416 if (_debug)
417 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
418 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
419 fts->fts_name);
420 break;
421 case FTS_DC: /* directory that causes cycles */
422 case FTS_DEFAULT: /* none of the above */
423 case FTS_DOT: /* dot or dot-dot */
424 case FTS_INIT: /* initialized only */
425 case FTS_NSOK: /* no stat(2) requested */
426 case FTS_SL: /* symbolic link */
427 case FTS_SLNONE: /* symbolic link without target */
428 case FTS_W: /* whiteout object */
429 default:
430 if (_debug)
431 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
432 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
433 fts->fts_name);
434 break;
435 }
436
437 return RPMRC_OK;
438 }
439
445 static void initGlobs(/*@unused@*/ rpmts ts, const char ** argv)
446 {
447 char buf[BUFSIZ];
448 int i;
449
450 buf[0] = '\0';
451 if (argv != NULL && * argv != NULL) {
452 const char * arg;
453 int single = (Glob_pattern_p(argv[0], 0) && argv[1] == NULL);
454 char * t;
455
456 t = buf;
457 if (!single)
458 t = stpcpy(t, "@(");
459 while ((arg = *argv++) != NULL) {
460 t = stpcpy(t, arg);
461 *t++ = '|';
462 }
463 t[-1] = (char)(single ? '\0' : ')');
464 *t = '\0';
465 }
466
467 bhpath = rpmExpand("%{_bhpath}", NULL);
468 bhpathlen = strlen(bhpath);
469
470 ftsSet = xcalloc(2, sizeof(*ftsSet));
471 ftsSet[0] = rpmExpand("%{_bhpath}", NULL);
472
473 nbhglobs = 5;
474 bhglobs = xcalloc(nbhglobs, sizeof(*bhglobs));
475 for (i = 0; i < nbhglobs; i++) {
476 const char * pattern;
477 const char * macro;
478
479 switch (i) {
480 case 0:
481 macro = "%{_bhpath}";
482 break;
483 case 1:
484 macro = "%{_bhcoll}";
485 break;
486 case 2:
487 macro = (buf[0] == '\0' ? "%{_bhN}" : buf);
488 break;
489 case 3:
490 macro = "%{_bhVR}";
491 break;
492 case 4:
493 macro = "%{_bhA}";
494 break;
495 default:
496 macro = NULL;
497 break;
498 }
499 bhglobs[i].patterns = xcalloc(2, sizeof(*bhglobs[i].patterns));
500 if (macro == NULL)
501 continue;
502 pattern = rpmExpand(macro, NULL);
503 if (pattern == NULL || *pattern == '\0') {
504 pattern = _free(pattern);
505 continue;
506 }
507 bhglobs[i].patterns[0] = pattern;
508 bhglobs[i].fnflags = (FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH);
509 if (bhglobs[i].patterns[0] != NULL)
510 rpmlog(RPMLOG_DEBUG, "\t%d \"%s\"\n",
511 i, bhglobs[i].patterns[0]);
512 }
513 }
514
515 static void freeGlobs(void)
516 {
517 int i;
518 for (i = 0; i < nbhglobs; i++) {
519 bhglobs[i].patterns[0] = _free(bhglobs[i].patterns[0]);
520 bhglobs[i].patterns = _free(bhglobs[i].patterns);
521 }
522 bhglobs = _free(bhglobs);
523 ftsSet[0] = _free(ftsSet[0]);
524 ftsSet = _free(ftsSet);
525 }
526
527 static rpmVSFlags vsflags = 0;
528
529 static struct poptOption optionsTable[] = {
530 { "nolegacy", '\0', POPT_BIT_SET, &vsflags, RPMVSF_NEEDPAYLOAD,
531 N_("don't verify header+payload signature"), NULL },
532
533 { "cache", '\0', POPT_ARG_VAL, &noCache, 0,
534 N_("update cache database"), NULL },
535 { "nocache", '\0', POPT_ARG_VAL, &noCache, -1,
536 N_("don't update cache database, only print package paths"), NULL },
537
538 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0,
539 N_("File tree walk options:"),
540 NULL },
541
542 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
543 N_("Common options for all rpm modes and executables:"),
544 NULL },
545
546 POPT_AUTOALIAS
547 POPT_AUTOHELP
548 POPT_TABLEEND
549 };
550
551 int
552 main(int argc, char *argv[])
553 {
554 poptContext optCon = rpmcliInit(argc, argv, optionsTable);
555 rpmts ts = NULL;
556 rpmgi gi = NULL;
557 const char * s;
558 int ec = 1;
559 rpmRC rpmrc;
560 int xx;
561
562 if (optCon == NULL)
563 exit(EXIT_FAILURE);
564
565 /* Configure the path to cache database, creating if necessary. */
566 s = rpmExpand("%{?_cache_dbpath}", NULL);
567 if (!(s && *s))
568 rpmrc = RPMRC_FAIL;
569 else
570 rpmrc = rpmMkdirPath(s, "cache_dbpath");
571 if (rpmrc == RPMRC_OK && Access(s, W_OK))
572 rpmrc = RPMRC_FAIL;
573 s = _free(s);
574 if (rpmrc != RPMRC_OK) {
575 fprintf(stderr, _("%s: %%{_cache_dbpath} macro is mis-configured.\n"),
576 __progname);
577 exit(EXIT_FAILURE);
578 }
579
580 ts = rpmtsCreate();
581
582 if (rpmcliQueryFlags & VERIFY_DIGEST)
583 vsflags |= _RPMVSF_NODIGESTS;
584 if (rpmcliQueryFlags & VERIFY_SIGNATURE)
585 vsflags |= _RPMVSF_NOSIGNATURES;
586 if (rpmcliQueryFlags & VERIFY_HDRCHK)
587 vsflags |= RPMVSF_NOHDRCHK;
588 (void) rpmtsSetVSFlags(ts, vsflags);
589
590 { uint32_t tid = (uint32_t) time(NULL);
591 (void) rpmtsSetTid(ts, tid);
592 }
593
594 initGlobs(ts, poptGetArgs(optCon));
595
596 gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
597
598 if (rpmioFtsOpts == 0)
599 rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
600
601 if (noCache)
602 rpmioFtsOpts |= FTS_NOSTAT;
603 else
604 rpmioFtsOpts &= ~FTS_NOSTAT;
605
606 xx = rpmgiSetArgs(gi, ftsSet, rpmioFtsOpts, giFlags);
607
608 gi->walkPathFilter = cacheWalkPathFilter;
609 gi->stash = cacheStashLatest;
610 while ((rpmrc = rpmgiNext(gi)) == RPMRC_OK)
611 {};
612
613 if (noCache)
614 ec = ftsCachePrint(ts, stdout);
615 else
616 ec = ftsCacheUpdate(ts);
617 if (ec) {
618 fprintf(stderr, _("%s: cache operation failed: ec %d.\n"),
619 __progname, ec);
620 }
621
622 freeItems();
623 freeGlobs();
624
625 gi = rpmgiFree(gi);
626 (void)rpmtsFree(ts);
627 ts = NULL;
628 optCon = rpmcliFini(optCon);
629
630 return ec;
631 }