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