Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

tools/rpmcache.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 #include <fnmatch.h>
00007 #include <fts.h>
00008 
00009 #include <rpmcli.h>
00010 
00011 #include "rpmps.h"
00012 #include "rpmdb.h"
00013 #include "rpmds.h"
00014 #include "rpmts.h"
00015 
00016 #include "misc.h"       /* XXX myGlobPatternP */
00017 #include "debug.h"
00018 
00019 static int _debug = 0;
00020 
00021 /* XXX should be flag in ts */
00022 static int noCache = 0;
00023 
00024 static char ** ftsSet;
00025 static int ftsOpts = 0;
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 rc;
00196         int xx;
00197 
00198         if (fd == NULL || Ferror(fd)) {
00199             if (fd) xx = Fclose(fd);
00200             goto exit;
00201         }
00202 
00203         rc = rpmReadPackageFile(ts, fd, fts->fts_path, &h);
00204         xx = Fclose(fd);
00205         if (rc != 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 = (myGlobPatternP(argv[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  { "comfollow", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00521         &ftsOpts, FTS_COMFOLLOW,
00522         N_("follow command line symlinks"), NULL },
00523  { "logical", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00524         &ftsOpts, FTS_LOGICAL,
00525         N_("logical walk"), NULL },
00526  { "nochdir", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00527         &ftsOpts, FTS_NOCHDIR,
00528         N_("don't change directories"), NULL },
00529  { "nostat", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00530         &ftsOpts, FTS_NOSTAT,
00531         N_("don't get stat info"), NULL },
00532  { "physical", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00533         &ftsOpts, FTS_PHYSICAL,
00534         N_("physical walk"), NULL },
00535  { "seedot", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00536         &ftsOpts, FTS_SEEDOT,
00537         N_("return dot and dot-dot"), NULL },
00538  { "xdev", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00539         &ftsOpts, FTS_XDEV,
00540         N_("don't cross devices"), NULL },
00541  { "whiteout", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN,
00542         &ftsOpts, FTS_WHITEOUT,
00543         N_("return whiteout information"), NULL },
00544 
00545  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
00546         N_("Common options for all rpm modes and executables:"),
00547         NULL },
00548 
00549     POPT_AUTOALIAS
00550     POPT_AUTOHELP
00551     POPT_TABLEEND
00552 };
00553 
00554 int
00555 main(int argc, char *const argv[])
00556 {
00557     rpmts ts = NULL;
00558     poptContext optCon;
00559     const char * s;
00560     FTS * ftsp;
00561     FTSENT * fts;
00562     int ec = 1;
00563     rpmRC rpmrc;
00564     int xx;
00565 
00566     optCon = rpmcliInit(argc, argv, optionsTable);
00567     if (optCon == NULL)
00568         exit(EXIT_FAILURE);
00569 
00570     /* Configure the path to cache database, creating if necessary. */
00571     s = rpmExpand("%{?_cache_dbpath}", NULL);
00572     if (!(s && *s))
00573         rpmrc = RPMRC_FAIL;
00574     else
00575         rpmrc = rpmMkdirPath(s, "cache_dbpath");
00576     s = _free(s);
00577     if (rpmrc != RPMRC_OK) {
00578         fprintf(stderr, _("%s: %%{_cache_dbpath} macro is mis-configured.\n"),
00579                 __progname);
00580         exit(EXIT_FAILURE);
00581     }
00582 
00583     ts = rpmtsCreate();
00584 
00585     if (rpmcliQueryFlags & VERIFY_DIGEST)
00586         vsflags |= _RPMVSF_NODIGESTS;
00587     if (rpmcliQueryFlags & VERIFY_SIGNATURE)
00588         vsflags |= _RPMVSF_NOSIGNATURES;
00589     if (rpmcliQueryFlags & VERIFY_HDRCHK)
00590         vsflags |= RPMVSF_NOHDRCHK;
00591     (void) rpmtsSetVSFlags(ts, vsflags);
00592 
00593     {   int_32 tid = (int_32) time(NULL);
00594         (void) rpmtsSetTid(ts, tid);
00595     }
00596 
00597     initGlobs(ts, poptGetArgs(optCon));
00598     if (ftsOpts == 0)
00599         ftsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
00600 
00601     if (noCache)
00602         ftsOpts |= FTS_NOSTAT;
00603     else
00604         ftsOpts &= ~FTS_NOSTAT;
00605 
00606     /* Walk file tree, filter paths, save matched items. */
00607     ftsp = Fts_open(ftsSet, ftsOpts, NULL);
00608     while((fts = Fts_read(ftsp)) != NULL) {
00609         xx = ftsPrint(ftsp, fts, ts);
00610     }
00611     xx = Fts_close(ftsp);
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 
00624     ts = rpmtsFree(ts);
00625 
00626     optCon = rpmcliFini(optCon);
00627 
00628     return ec;
00629 }

Generated on Sun Oct 26 13:02:04 2003 for rpm by doxygen1.2.18