rpm 5.2.1
|
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" /* XXX rpmMkdirPath */ 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 /* XXX should be flag in ts */ 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(/*@unused@*/ 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 /* --- Check that identical package is not already cached. */ 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 /* --- Add cache tags to new cache header. */ 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 /* --- Add new cache header to database. */ 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; /* assume not found */ 00213 int i = 0; 00214 int xx; 00215 00216 rpmlog(RPMLOG_DEBUG, "============== %s\n", fts->fts_accpath); 00217 00218 /* XXX DIEDIEDIE: check platform compatibility. */ 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 /* Rewind to the first item with same name. */ 00231 while (found > items && cmpItem(found-1, fneedle) == 0) 00232 found--; 00233 00234 /* Check that all saved items are newer than this item. */ 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 * At this point, ec is 00249 * -1 no item with the same name has been seen. 00250 * 0 item exists, but already saved item EVR is newer. 00251 * 1 item exists, but already saved item EVR is same/older. 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: /* preorder directory */ 00331 if (fts->fts_pathlen < bhpathlen) 00332 break; 00333 00334 /* Grab the level of the beehive top directory. */ 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 /* Full path glob expression check. */ 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 /* Level specific glob expression check(s). */ 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: /* postorder directory */ 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: /* regular file */ 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 /* Ignore source packages. */ 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 /* Ignore all but *.rpm files. */ 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: /* stat(2) failed */ 00414 case FTS_DNR: /* unreadable directory */ 00415 case FTS_ERR: /* error; errno is set */ 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: /* directory that causes cycles */ 00422 case FTS_DEFAULT: /* none of the above */ 00423 case FTS_DOT: /* dot or dot-dot */ 00424 case FTS_INIT: /* initialized only */ 00425 case FTS_NSOK: /* no stat(2) requested */ 00426 case FTS_SL: /* symbolic link */ 00427 case FTS_SLNONE: /* symbolic link without target */ 00428 case FTS_W: /* whiteout object */ 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(/*@unused@*/ 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 /* Configure the path to cache database, creating if necessary. */ 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 }