rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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 <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 }