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