00001
00005 #include "system.h"
00006 const char *__progname;
00007
00008 #include <fnmatch.h>
00009 #include <fts.h>
00010
00011 #include <rpmio.h>
00012 #include <rpmiotypes.h>
00013 #include <poptIO.h>
00014
00015 #include <rpmtypes.h>
00016 #include <rpmtag.h>
00017
00018 #include "rpmdb.h"
00019
00020 #include "rpmps.h"
00021
00022 #include "misc.h"
00023
00024 #define _RPMGI_INTERNAL
00025 #include <rpmgi.h>
00026
00027 #include <rpmcli.h>
00028
00029 #include "debug.h"
00030
00031 static int _debug = 0;
00032
00033
00034 static int noCache = -1;
00035
00036 static ARGV_t ftsSet;
00037
00038 const char * bhpath;
00039 int bhpathlen = 0;
00040 int bhlvl = -1;
00041
00042 struct ftsglob_s {
00043 const char ** patterns;
00044 int fnflags;
00045 };
00046
00047 static struct ftsglob_s * bhglobs;
00048 static int nbhglobs = 5;
00049
00050 static int indent = 2;
00051
00052 typedef struct Item_s {
00053 const char * path;
00054 uint32_t size;
00055 uint32_t mtime;
00056 rpmds this;
00057 Header h;
00058 } * Item;
00059
00060 static Item * items = NULL;
00061 static int nitems = 0;
00062
00063 static inline Item freeItem(Item item) {
00064 if (item != NULL) {
00065 item->path = _free(item->path);
00066 (void)rpmdsFree(item->this);
00067 item->this = NULL;
00068 (void)headerFree(item->h);
00069 item->h = NULL;
00070 item = _free(item);
00071 }
00072 return NULL;
00073 }
00074
00075 static inline Item newItem(void) {
00076 Item item = xcalloc(1, sizeof(*item));
00077 return item;
00078 }
00079
00080 static int cmpItem(const void * a, const void * b) {
00081 Item aitem = *(Item *)a;
00082 Item bitem = *(Item *)b;
00083 int rc = strcmp(rpmdsN(aitem->this), rpmdsN(bitem->this));
00084 return rc;
00085 }
00086
00087 static void freeItems(void) {
00088 int i;
00089 for (i = 0; i < nitems; i++)
00090 items[i] = freeItem(items[i]);
00091 items = _free(items);
00092 nitems = 0;
00093 }
00094
00095 static int ftsCachePrint( rpmts ts, FILE * fp)
00096 {
00097 int rc = 0;
00098 int i;
00099
00100 if (fp == NULL) fp = stdout;
00101 for (i = 0; i < nitems; i++) {
00102 Item ip;
00103
00104 ip = items[i];
00105 if (ip == NULL) {
00106 rc = 1;
00107 break;
00108 }
00109
00110 fprintf(fp, "%s\n", ip->path);
00111 }
00112 return rc;
00113 }
00114
00115 static int ftsCacheUpdate(rpmts ts)
00116 {
00117 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00118 uint32_t tid = rpmtsGetTid(ts);
00119 rpmmi mi;
00120 unsigned char * md5;
00121 int rc = 0;
00122 int xx;
00123 int i;
00124
00125 rc = rpmtsCloseDB(ts);
00126 rc = rpmDefineMacro(NULL, "_dbpath %{_cache_dbpath}", RMIL_CMDLINE);
00127 rc = rpmtsOpenDB(ts, O_RDWR);
00128 if (rc != 0)
00129 return rc;
00130
00131 for (i = 0; i < nitems; i++) {
00132 Item ip;
00133
00134 ip = items[i];
00135 if (ip == NULL) {
00136 rc = 1;
00137 break;
00138 }
00139
00140
00141 he->tag = RPMTAG_SIGMD5;
00142 xx = headerGet(ip->h, he, 0);
00143 md5 = he->p.ui8p;
00144 if (!xx || md5 == NULL) {
00145 md5 = _free(md5);
00146 rc = 1;
00147 break;
00148 }
00149 mi = rpmtsInitIterator(ts, RPMTAG_SIGMD5, md5, 16);
00150 md5 = _free(md5);
00151 rc = rpmmiCount(mi);
00152 mi = rpmmiFree(mi);
00153 if (rc) {
00154 rc = 0;
00155 continue;
00156 }
00157
00158
00159 he->tag = RPMTAG_CACHECTIME;
00160 he->t = RPM_UINT32_TYPE;
00161 he->p.ui32p = &tid;
00162 he->c = 1;
00163 he->append = 1;
00164 rc = headerPut(ip->h, he, 0);
00165 he->append = 0;
00166 if (rc != 1) break;
00167
00168 he->tag = RPMTAG_CACHEPKGPATH;
00169 he->t = RPM_STRING_ARRAY_TYPE;
00170 he->p.argv = &ip->path;
00171 he->c = 1;
00172 he->append = 1;
00173 rc = headerPut(ip->h, he, 0);
00174 he->append = 0;
00175 if (rc != 1) break;
00176
00177 he->tag = RPMTAG_CACHEPKGSIZE;
00178 he->t = RPM_UINT32_TYPE;
00179 he->p.ui32p = &ip->size;
00180 he->c = 1;
00181 he->append = 1;
00182 rc = headerPut(ip->h, he, 0);
00183 he->append = 0;
00184 if (rc != 1) break;
00185
00186 he->tag = RPMTAG_CACHEPKGMTIME;
00187 he->t = RPM_UINT32_TYPE;
00188 he->p.ui32p = &ip->mtime;
00189 he->c = 1;
00190 he->append = 1;
00191 rc = headerPut(ip->h, he, 0);
00192 he->append = 0;
00193 if (rc != 1) break;
00194
00195
00196 if (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
00197 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, ip->h, ts);
00198 else
00199 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, ip->h, NULL);
00200 if (rc) break;
00201
00202 }
00203 xx = rpmtsCloseDB(ts);
00204 return rc;
00205 }
00206
00207 static rpmRC cacheStashLatest(rpmgi gi, Header h)
00208 {
00209 FTSENT * fts = gi->fts;
00210 rpmds add = NULL;
00211 struct stat sb, * st;
00212 int ec = -1;
00213 int i = 0;
00214 int xx;
00215
00216 rpmlog(RPMLOG_DEBUG, "============== %s\n", fts->fts_accpath);
00217
00218
00219
00220 add = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_LESS));
00221
00222 if (items != NULL && nitems > 0) {
00223 Item needle = memset(alloca(sizeof(*needle)), 0, sizeof(*needle));
00224 Item * found, * fneedle = &needle;
00225
00226 needle->this = add;
00227
00228 found = bsearch(fneedle, items, nitems, sizeof(*found), cmpItem);
00229
00230
00231 while (found > items && cmpItem(found-1, fneedle) == 0)
00232 found--;
00233
00234
00235 if (found != NULL)
00236 while (found < (items + nitems) && cmpItem(found, fneedle) == 0) {
00237 ec = rpmdsCompare(needle->this, (*found)->this);
00238 if (ec == 0) {
00239 found++;
00240 continue;
00241 }
00242 i = found - items;
00243 break;
00244 }
00245 }
00246
00247
00248
00249
00250
00251
00252
00253 if (ec == 0) {
00254 goto exit;
00255 } else if (ec == 1) {
00256 items[i] = freeItem(items[i]);
00257 } else {
00258 i = nitems++;
00259 items = xrealloc(items, nitems * sizeof(*items));
00260 }
00261
00262 items[i] = newItem();
00263 items[i]->path = xstrdup(fts->fts_path);
00264 st = fts->fts_statp;
00265 if (st == NULL || ((long)st & 0xffff0000) == 0L) {
00266 st = &sb;
00267 memset(st, 0, sizeof(*st));
00268 xx = Stat(fts->fts_accpath, &sb);
00269 }
00270
00271 if (st != NULL) {
00272 items[i]->size = st->st_size;
00273 items[i]->mtime = st->st_mtime;
00274 }
00275 st = NULL;
00276 items[i]->this = rpmdsThis(h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
00277 items[i]->h = headerLink(h);
00278
00279 if (nitems > 1)
00280 qsort(items, nitems, sizeof(*items), cmpItem);
00281
00282 #if 0
00283 fprintf(stderr, "\t%*s [%d] %s\n",
00284 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
00285 i, fts->fts_name);
00286 #endif
00287
00288 exit:
00289 (void)rpmdsFree(add);
00290 add = NULL;
00291 return (ec ? RPMRC_NOTFOUND : RPMRC_OK);
00292 }
00293
00294 static const char * ftsInfoStrings[] = {
00295 "UNKNOWN",
00296 "D",
00297 "DC",
00298 "DEFAULT",
00299 "DNR",
00300 "DOT",
00301 "DP",
00302 "ERR",
00303 "F",
00304 "INIT",
00305 "NS",
00306 "NSOK",
00307 "SL",
00308 "SLNONE",
00309 "W",
00310 };
00311
00312 static const char * ftsInfoStr(int fts_info) {
00313 if (!(fts_info >= 1 && fts_info <= 14))
00314 fts_info = 0;
00315 return ftsInfoStrings[ fts_info ];
00316 }
00317
00318 static rpmRC cacheWalkPathFilter(rpmgi gi)
00319 {
00320 FTS * ftsp = gi->ftsp;
00321 FTSENT * fts = gi->fts;
00322 struct ftsglob_s * bhg;
00323 const char ** patterns;
00324 const char * pattern;
00325 const char * s;
00326 int lvl;
00327 int xx;
00328
00329 switch (fts->fts_info) {
00330 case FTS_D:
00331 if (fts->fts_pathlen < bhpathlen)
00332 break;
00333
00334
00335 if (bhlvl < 0) {
00336 if (fts->fts_pathlen == bhpathlen && !strcmp(fts->fts_path, bhpath))
00337 bhlvl = fts->fts_level;
00338 else
00339 break;
00340 }
00341 lvl = fts->fts_level - bhlvl;
00342
00343 if (lvl < 0)
00344 break;
00345
00346 #if 0
00347 if (_debug)
00348 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
00349 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
00350 fts->fts_name);
00351 #endif
00352
00353
00354 bhg = bhglobs;
00355
00356 if ((patterns = bhg->patterns) != NULL)
00357 while ((pattern = *patterns++) != NULL) {
00358 if (*pattern == '/')
00359 xx = fnmatch(pattern, fts->fts_path, bhg->fnflags);
00360 else
00361 xx = fnmatch(pattern, fts->fts_name, bhg->fnflags);
00362 if (xx == 0)
00363 break;
00364 }
00365
00366
00367 if (lvl == 0 || lvl >= nbhglobs)
00368 break;
00369 bhg += lvl;
00370
00371 if ((patterns = bhg->patterns) != NULL)
00372 while ((pattern = *patterns++) != NULL) {
00373 if (*pattern == '/')
00374 xx = fnmatch(pattern, fts->fts_path, bhg->fnflags);
00375 else
00376 xx = fnmatch(pattern, fts->fts_name, bhg->fnflags);
00377 if (xx == 0)
00378 break;
00379 else
00380 xx = Fts_set(ftsp, fts, FTS_SKIP);
00381 }
00382
00383 break;
00384 case FTS_DP:
00385 #if 0
00386 if (_debug)
00387 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
00388 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
00389 fts->fts_name);
00390 #endif
00391 break;
00392 case FTS_F:
00393 #if 0
00394 if (_debug)
00395 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
00396 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
00397 fts->fts_name);
00398 #endif
00399 if (fts->fts_level >= 0) {
00400
00401 if (!strcmp(fts->fts_parent->fts_name, "SRPMS")) {
00402 xx = Fts_set(ftsp, fts->fts_parent, FTS_SKIP);
00403 break;
00404 }
00405 }
00406
00407
00408 s = fts->fts_name + fts->fts_namelen + 1 - sizeof(".rpm");
00409 if (strcmp(s, ".rpm"))
00410 break;
00411
00412 break;
00413 case FTS_NS:
00414 case FTS_DNR:
00415 case FTS_ERR:
00416 if (_debug)
00417 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
00418 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
00419 fts->fts_name);
00420 break;
00421 case FTS_DC:
00422 case FTS_DEFAULT:
00423 case FTS_DOT:
00424 case FTS_INIT:
00425 case FTS_NSOK:
00426 case FTS_SL:
00427 case FTS_SLNONE:
00428 case FTS_W:
00429 default:
00430 if (_debug)
00431 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
00432 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
00433 fts->fts_name);
00434 break;
00435 }
00436
00437 return RPMRC_OK;
00438 }
00439
00445 static void initGlobs( rpmts ts, const char ** argv)
00446 {
00447 char buf[BUFSIZ];
00448 int i;
00449
00450 buf[0] = '\0';
00451 if (argv != NULL && * argv != NULL) {
00452 const char * arg;
00453 int single = (Glob_pattern_p(argv[0], 0) && argv[1] == NULL);
00454 char * t;
00455
00456 t = buf;
00457 if (!single)
00458 t = stpcpy(t, "@(");
00459 while ((arg = *argv++) != NULL) {
00460 t = stpcpy(t, arg);
00461 *t++ = '|';
00462 }
00463 t[-1] = (char)(single ? '\0' : ')');
00464 *t = '\0';
00465 }
00466
00467 bhpath = rpmExpand("%{_bhpath}", NULL);
00468 bhpathlen = strlen(bhpath);
00469
00470 ftsSet = xcalloc(2, sizeof(*ftsSet));
00471 ftsSet[0] = rpmExpand("%{_bhpath}", NULL);
00472
00473 nbhglobs = 5;
00474 bhglobs = xcalloc(nbhglobs, sizeof(*bhglobs));
00475 for (i = 0; i < nbhglobs; i++) {
00476 const char * pattern;
00477 const char * macro;
00478
00479 switch (i) {
00480 case 0:
00481 macro = "%{_bhpath}";
00482 break;
00483 case 1:
00484 macro = "%{_bhcoll}";
00485 break;
00486 case 2:
00487 macro = (buf[0] == '\0' ? "%{_bhN}" : buf);
00488 break;
00489 case 3:
00490 macro = "%{_bhVR}";
00491 break;
00492 case 4:
00493 macro = "%{_bhA}";
00494 break;
00495 default:
00496 macro = NULL;
00497 break;
00498 }
00499 bhglobs[i].patterns = xcalloc(2, sizeof(*bhglobs[i].patterns));
00500 if (macro == NULL)
00501 continue;
00502 pattern = rpmExpand(macro, NULL);
00503 if (pattern == NULL || *pattern == '\0') {
00504 pattern = _free(pattern);
00505 continue;
00506 }
00507 bhglobs[i].patterns[0] = pattern;
00508 bhglobs[i].fnflags = (FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH);
00509 if (bhglobs[i].patterns[0] != NULL)
00510 rpmlog(RPMLOG_DEBUG, "\t%d \"%s\"\n",
00511 i, bhglobs[i].patterns[0]);
00512 }
00513 }
00514
00515 static void freeGlobs(void)
00516 {
00517 int i;
00518 for (i = 0; i < nbhglobs; i++) {
00519 bhglobs[i].patterns[0] = _free(bhglobs[i].patterns[0]);
00520 bhglobs[i].patterns = _free(bhglobs[i].patterns);
00521 }
00522 bhglobs = _free(bhglobs);
00523 ftsSet[0] = _free(ftsSet[0]);
00524 ftsSet = _free(ftsSet);
00525 }
00526
00527 static rpmVSFlags vsflags = 0;
00528
00529 static struct poptOption optionsTable[] = {
00530 { "nolegacy", '\0', POPT_BIT_SET, &vsflags, RPMVSF_NEEDPAYLOAD,
00531 N_("don't verify header+payload signature"), NULL },
00532
00533 { "cache", '\0', POPT_ARG_VAL, &noCache, 0,
00534 N_("update cache database"), NULL },
00535 { "nocache", '\0', POPT_ARG_VAL, &noCache, -1,
00536 N_("don't update cache database, only print package paths"), NULL },
00537
00538 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0,
00539 N_("File tree walk options:"),
00540 NULL },
00541
00542 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
00543 N_("Common options for all rpm modes and executables:"),
00544 NULL },
00545
00546 POPT_AUTOALIAS
00547 POPT_AUTOHELP
00548 POPT_TABLEEND
00549 };
00550
00551 int
00552 main(int argc, char *argv[])
00553 {
00554 poptContext optCon = rpmcliInit(argc, argv, optionsTable);
00555 rpmts ts = NULL;
00556 rpmgi gi = NULL;
00557 const char * s;
00558 int ec = 1;
00559 rpmRC rpmrc;
00560 int xx;
00561
00562 if (optCon == NULL)
00563 exit(EXIT_FAILURE);
00564
00565
00566 s = rpmExpand("%{?_cache_dbpath}", NULL);
00567 if (!(s && *s))
00568 rpmrc = RPMRC_FAIL;
00569 else
00570 rpmrc = rpmMkdirPath(s, "cache_dbpath");
00571 if (rpmrc == RPMRC_OK && Access(s, W_OK))
00572 rpmrc = RPMRC_FAIL;
00573 s = _free(s);
00574 if (rpmrc != RPMRC_OK) {
00575 fprintf(stderr, _("%s: %%{_cache_dbpath} macro is mis-configured.\n"),
00576 __progname);
00577 exit(EXIT_FAILURE);
00578 }
00579
00580 ts = rpmtsCreate();
00581
00582 if (rpmcliQueryFlags & VERIFY_DIGEST)
00583 vsflags |= _RPMVSF_NODIGESTS;
00584 if (rpmcliQueryFlags & VERIFY_SIGNATURE)
00585 vsflags |= _RPMVSF_NOSIGNATURES;
00586 if (rpmcliQueryFlags & VERIFY_HDRCHK)
00587 vsflags |= RPMVSF_NOHDRCHK;
00588 (void) rpmtsSetVSFlags(ts, vsflags);
00589
00590 { uint32_t tid = (uint32_t) time(NULL);
00591 (void) rpmtsSetTid(ts, tid);
00592 }
00593
00594 initGlobs(ts, poptGetArgs(optCon));
00595
00596 gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
00597
00598 if (rpmioFtsOpts == 0)
00599 rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
00600
00601 if (noCache)
00602 rpmioFtsOpts |= FTS_NOSTAT;
00603 else
00604 rpmioFtsOpts &= ~FTS_NOSTAT;
00605
00606 xx = rpmgiSetArgs(gi, ftsSet, rpmioFtsOpts, giFlags);
00607
00608 gi->walkPathFilter = cacheWalkPathFilter;
00609 gi->stash = cacheStashLatest;
00610 while ((rpmrc = rpmgiNext(gi)) == RPMRC_OK)
00611 {};
00612
00613 if (noCache)
00614 ec = ftsCachePrint(ts, stdout);
00615 else
00616 ec = ftsCacheUpdate(ts);
00617 if (ec) {
00618 fprintf(stderr, _("%s: cache operation failed: ec %d.\n"),
00619 __progname, ec);
00620 }
00621
00622 freeItems();
00623 freeGlobs();
00624
00625 gi = rpmgiFree(gi);
00626 (void)rpmtsFree(ts);
00627 ts = NULL;
00628 optCon = rpmcliFini(optCon);
00629
00630 return ec;
00631 }