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

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

Generated on Fri Nov 11 08:34:21 2005 for rpm by  doxygen 1.3.9.1