tools/rpmcache.c

Go to the documentation of this file.
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 /* XXX should be flag in ts */
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(/*@unused@*/ 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         /* --- Check that identical package is not already cached. */
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         /* --- Add cache tags to new cache header. */
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         /* --- Add new cache header to database. */
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(/*@null@*/ 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(/*@null@*/ 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;        /* assume not found */
00189     int i = 0;
00190 
00191     rpmMessage(RPMMESS_DEBUG, "============== %s\n", fts->fts_accpath);
00192 
00193     /* Read header from file. */
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     /* Make sure arch and os match this platform. */
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         /* 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 && 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:         /* preorder directory */
00325         if (fts->fts_pathlen < bhpathlen)
00326             break;
00327 
00328         /* Grab the level of the beehive top directory. */
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         /* Full path glob expression check. */
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         /* Level specific glob expression check(s). */
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:        /* postorder directory */
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:         /* regular file */
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             /* Ignore source packages. */
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         /* Ignore all but *.rpm files. */
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:        /* stat(2) failed */
00410     case FTS_DNR:       /* unreadable directory */
00411     case FTS_ERR:       /* error; errno is set */
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:        /* directory that causes cycles */
00418     case FTS_DEFAULT:   /* none of the above */
00419     case FTS_DOT:       /* dot or dot-dot */
00420     case FTS_INIT:      /* initialized only */
00421     case FTS_NSOK:      /* no stat(2) requested */
00422     case FTS_SL:        /* symbolic link */
00423     case FTS_SLNONE:    /* symbolic link without target */
00424     case FTS_W:         /* whiteout object */
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(/*@unused@*/ 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     /* Configure the path to cache database, creating if necessary. */
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     /* Walk file tree, filter paths, save matched items. */
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 }

Generated on Fri Oct 12 08:44:55 2007 for rpm by  doxygen 1.5.2