rpm 5.2.1

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

- File List
- Globals

lib/query.c
Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #ifndef PATH_MAX
    00009 /*@-incondefs@*/        /* FIX: long int? */
    00010 # define PATH_MAX 255
    00011 /*@=incondefs@*/
    00012 #endif
    00013
    00014 #include <rpmio.h>
    00015 #include <rpmiotypes.h>
    00016 #include <poptIO.h>
    00017
    00018 #include <rpmtag.h>
    00019 #include "rpmdb.h"
    00020
    00021 #include "rpmfi.h"
    00022 #define _RPMTS_INTERNAL         /* XXX for ts->rdb */
    00023 #include "rpmts.h"
    00024 #include "rpmgi.h"
    00025
    00026 #include "manifest.h"
    00027 #include "misc.h"       /* XXX for currentDirectory() */
    00028
    00029 #include <rpmcli.h>
    00030
    00031 #include "debug.h"
    00032
    00033 /*@access rpmts @*/     /* XXX cast */
    00034
    00037 static void printFileInfo(char * te, const char * name,
    00038                           size_t size, unsigned short mode,
    00039                           unsigned int mtime,
    00040                           unsigned short rdev, unsigned int nlink,
    00041                           const char * owner, const char * group,
    00042                           const char * linkto)
    00043         /*@modifies *te @*/
    00044 {
    00045     char sizefield[15];
    00046 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
    00047     /* In verbose file listing output, give the owner and group fields
    00048        more width and at the same time reduce the nlink and size fields
    00049        more to typical sizes within OpenPKG. */
    00050     char ownerfield[13+1], groupfield[13+1];
    00051 #else
    00052     char ownerfield[8+1], groupfield[8+1];
    00053 #endif
    00054     char timefield[100];
    00055     time_t when = mtime;  /* important if sizeof(rpmuint32_t) ! sizeof(time_t) */
    00056     struct tm * tm;
    00057     static time_t now;
    00058     static struct tm nowtm;
    00059     const char * namefield = name;
    00060     char * perms = rpmPermsString(mode);
    00061
    00062     /* On first call, grab snapshot of now */
    00063     if (now == 0) {
    00064         now = time(NULL);
    00065         tm = localtime(&now);
    00066         if (tm) nowtm = *tm;    /* structure assignment */
    00067     }
    00068
    00069     strncpy(ownerfield, owner, sizeof(ownerfield));
    00070     ownerfield[sizeof(ownerfield)-1] = '\0';
    00071
    00072     strncpy(groupfield, group, sizeof(groupfield));
    00073     groupfield[sizeof(groupfield)-1] = '\0';
    00074
    00075     /* this is normally right */
    00076 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
    00077     /* In verbose file listing output, give the owner and group fields
    00078        more width and at the same time reduce the nlink and size fields
    00079        more to typical sizes within OpenPKG. */
    00080     sprintf(sizefield, "%8u", (unsigned)size);
    00081 #else
    00082     sprintf(sizefield, "%12u", (unsigned)size);
    00083 #endif
    00084
    00085     /* this knows too much about dev_t */
    00086
    00087     if (S_ISLNK(mode)) {
    00088         char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
    00089         sprintf(nf, "%s -> %s", name, linkto);
    00090         namefield = nf;
    00091     } else if (S_ISCHR(mode)) {
    00092         perms[0] = 'c';
    00093         sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
    00094                         ((unsigned)rdev & 0xff));
    00095     } else if (S_ISBLK(mode)) {
    00096         perms[0] = 'b';
    00097         sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
    00098                         ((unsigned)rdev & 0xff));
    00099     }
    00100
    00101     /* Convert file mtime to display format */
    00102     tm = localtime(&when);
    00103     timefield[0] = '\0';
    00104     if (tm != NULL)
    00105     {   const char *fmt;
    00106         if (now > when + 6L * 30L * 24L * 60L * 60L ||  /* Old. */
    00107             now < when - 60L * 60L)                     /* In the future.  */
    00108         {
    00109         /* The file is fairly old or in the future.
    00110          * POSIX says the cutoff is 6 months old;
    00111          * approximate this by 6*30 days.
    00112          * Allow a 1 hour slop factor for what is considered "the future",
    00113          * to allow for NFS server/client clock disagreement.
    00114          * Show the year instead of the time of day.
    00115          */
    00116             fmt = "%b %e  %Y";
    00117         } else {
    00118             fmt = "%b %e %H:%M";
    00119         }
    00120         (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
    00121     }
    00122
    00123 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
    00124     /* In verbose file listing output, give the owner and group fields
    00125        more width and at the same time reduce the nlink and size fields
    00126        more to typical sizes within OpenPKG. */
    00127     sprintf(te, "%s %d %-13s %-13s %8s %s %s", perms,
    00128         (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
    00129 #else
    00130     sprintf(te, "%s %4d %-7s %-8s %10s %s %s", perms,
    00131         (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
    00132 #endif
    00133     perms = _free(perms);
    00134 }
    00135
    00138 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
    00139         /*@globals internalState @*/
    00140         /*@modifies h, internalState @*/
    00141 {
    00142     const char * errstr = "(unkown error)";
    00143     const char * str;
    00144
    00145 /*@-modobserver@*/
    00146     str = headerSprintf(h, qfmt, NULL, rpmHeaderFormats, &errstr);
    00147 /*@=modobserver@*/
    00148     if (str == NULL)
    00149         rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
    00150     return str;
    00151 }
    00152
    00155 static void flushBuffer(char ** tp, char ** tep, int nonewline)
    00156         /*@modifies *tp, **tp, *tep, **tep @*/
    00157 {
    00158     char *t, *te;
    00159
    00160     t = *tp;
    00161     te = *tep;
    00162     if (te > t) {
    00163         if (!nonewline) {
    00164             *te++ = '\n';
    00165             *te = '\0';
    00166         }
    00167         rpmlog(RPMLOG_NOTICE, "%s", t);
    00168         te = t;
    00169         *t = '\0';
    00170     }
    00171     *tp = t;
    00172     *tep = te;
    00173 }
    00174
    00175 int showQueryPackage(QVA_t qva, rpmts ts, Header h)
    00176 {
    00177     int scareMem = 0;
    00178     rpmfi fi = NULL;
    00179     size_t tb = 2 * BUFSIZ;
    00180     size_t sb;
    00181     char * t, * te;
    00182     char * prefix = NULL;
    00183     int rc = 0;         /* XXX FIXME: need real return code */
    00184     int i;
    00185
    00186     te = t = xmalloc(tb);
    00187     *te = '\0';
    00188
    00189     if (qva->qva_queryFormat != NULL) {
    00190         const char * str;
    00191 /*@-type@*/     /* FIX rpmtsGetRDB()? */
    00192         (void) headerSetRpmdb(h, ts->rdb);
    00193 /*@=type@*/
    00194         str = queryHeader(h, qva->qva_queryFormat);
    00195         (void) headerSetRpmdb(h, NULL);
    00196         if (str) {
    00197             size_t tx = (te - t);
    00198
    00199             sb = strlen(str);
    00200             if (sb) {
    00201                 tb += sb;
    00202                 t = xrealloc(t, tb);
    00203                 te = t + tx;
    00204             }
    00205             /*@-usereleased@*/
    00206             te = stpcpy(te, str);
    00207             /*@=usereleased@*/
    00208             str = _free(str);
    00209             flushBuffer(&t, &te, 1);
    00210         }
    00211     }
    00212
    00213     if (!(qva->qva_flags & QUERY_FOR_LIST))
    00214         goto exit;
    00215
    00216     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
    00217     if (rpmfiFC(fi) <= 0) {
    00218         te = stpcpy(te, _("(contains no files)"));
    00219         goto exit;
    00220     }
    00221
    00222     fi = rpmfiInit(fi, 0);
    00223     if (fi != NULL)
    00224     while ((i = rpmfiNext(fi)) >= 0) {
    00225         rpmfileAttrs fflags;
    00226         unsigned short fmode;
    00227         unsigned short frdev;
    00228         unsigned int fmtime;
    00229         rpmfileState fstate;
    00230         size_t fsize;
    00231         const char * fn;
    00232         const char * fdigest;
    00233         const char * fuser;
    00234         const char * fgroup;
    00235         const char * flink;
    00236         rpmuint32_t fnlink;
    00237
    00238         fflags = rpmfiFFlags(fi);
    00239         fmode = rpmfiFMode(fi);
    00240         frdev = rpmfiFRdev(fi);
    00241         fmtime = rpmfiFMtime(fi);
    00242         fstate = rpmfiFState(fi);
    00243         fsize = rpmfiFSize(fi);
    00244         fn = rpmfiFN(fi);
    00245         {   static char hex[] = "0123456789abcdef";
    00246             int dalgo = 0;
    00247             size_t dlen = 0;
    00248             const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
    00249             char * p;
    00250             size_t j;
    00251             fdigest = p = xcalloc(1, ((2 * dlen) + 1));
    00252             for (j = 0; j < dlen; j++) {
    00253                 unsigned k = *digest++;
    00254                 *p++ = hex[ (k >> 4) & 0xf ];
    00255                 *p++ = hex[ (k     ) & 0xf ];
    00256             }
    00257             *p = '\0';
    00258         }
    00259         fuser = rpmfiFUser(fi);
    00260         fgroup = rpmfiFGroup(fi);
    00261         flink = rpmfiFLink(fi);
    00262         fnlink = rpmfiFNlink(fi);
    00263 assert(fn != NULL);
    00264 assert(fdigest != NULL);
    00265
    00266         /* If querying only docs, skip non-doc files. */
    00267         if ((qva->qva_flags & QUERY_FOR_DOCS) && !(fflags & RPMFILE_DOC))
    00268             continue;
    00269
    00270         /* If querying only configs, skip non-config files. */
    00271         if ((qva->qva_flags & QUERY_FOR_CONFIG) && !(fflags & RPMFILE_CONFIG))
    00272             continue;
    00273
    00274         /* If not querying %config, skip config files. */
    00275         if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG))
    00276             continue;
    00277
    00278         /* If not querying %doc, skip doc files. */
    00279         if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC))
    00280             continue;
    00281
    00282         /* If not querying %ghost, skip ghost files. */
    00283         if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
    00284             continue;
    00285
    00286         /* Insure space for header derived data */
    00287         sb = 0;
    00288         if (fn)         sb += strlen(fn);
    00289         if (fdigest)    sb += strlen(fdigest);
    00290         if (fuser)      sb += strlen(fuser);
    00291         if (fgroup)     sb += strlen(fgroup);
    00292         if (flink)      sb += strlen(flink);
    00293         if ((sb + BUFSIZ) > tb) {
    00294             size_t tx = (te - t);
    00295             tb += sb + BUFSIZ;
    00296             t = xrealloc(t, tb);
    00297             te = t + tx;
    00298         }
    00299
    00300         if (!rpmIsVerbose() && prefix)
    00301             te = stpcpy(te, prefix);
    00302
    00303         if (qva->qva_flags & QUERY_FOR_STATE) {
    00304             switch (fstate) {
    00305             case RPMFILE_STATE_NORMAL:
    00306                 te = stpcpy(te, _("normal        "));
    00307                 /*@switchbreak@*/ break;
    00308             case RPMFILE_STATE_REPLACED:
    00309                 te = stpcpy(te, _("replaced      "));
    00310                 /*@switchbreak@*/ break;
    00311             case RPMFILE_STATE_NOTINSTALLED:
    00312                 te = stpcpy(te, _("not installed "));
    00313                 /*@switchbreak@*/ break;
    00314             case RPMFILE_STATE_NETSHARED:
    00315                 te = stpcpy(te, _("net shared    "));
    00316                 /*@switchbreak@*/ break;
    00317             case RPMFILE_STATE_WRONGCOLOR:
    00318                 te = stpcpy(te, _("wrong color   "));
    00319                 /*@switchbreak@*/ break;
    00320             case RPMFILE_STATE_MISSING:
    00321                 te = stpcpy(te, _("(no state)    "));
    00322                 /*@switchbreak@*/ break;
    00323             default:
    00324                 sprintf(te, _("(unknown %3d) "), fstate);
    00325                 te += strlen(te);
    00326                 /*@switchbreak@*/ break;
    00327             }
    00328         }
    00329
    00330         if (qva->qva_flags & QUERY_FOR_DUMPFILES) {
    00331             sprintf(te, "%s %d %d %s 0%o ",
    00332                                 fn, (int)fsize, fmtime, fdigest, fmode);
    00333             te += strlen(te);
    00334
    00335             if (fuser && fgroup) {
    00336 /*@-nullpass@*/
    00337                 sprintf(te, "%s %s", fuser, fgroup);
    00338 /*@=nullpass@*/
    00339                 te += strlen(te);
    00340             } else {
    00341                 rpmlog(RPMLOG_CRIT, _("package without owner/group tags\n"));
    00342             }
    00343
    00344             sprintf(te, " %s %s %u ",
    00345                                  fflags & RPMFILE_CONFIG ? "1" : "0",
    00346                                  fflags & RPMFILE_DOC ? "1" : "0",
    00347                                  frdev);
    00348             te += strlen(te);
    00349
    00350             sprintf(te, "%s", (flink && *flink ? flink : "X"));
    00351             te += strlen(te);
    00352         } else
    00353         if (!rpmIsVerbose()) {
    00354             te = stpcpy(te, fn);
    00355         }
    00356         else {
    00357
    00358             /* XXX Adjust directory link count and size for display output. */
    00359             if (S_ISDIR(fmode)) {
    00360                 fnlink++;
    00361                 fsize = 0;
    00362             }
    00363
    00364             if (fuser && fgroup) {
    00365 /*@-nullpass@*/
    00366                 printFileInfo(te, fn, fsize, fmode, fmtime, frdev, fnlink,
    00367                                         fuser, fgroup, flink);
    00368 /*@=nullpass@*/
    00369                 te += strlen(te);
    00370             } else {
    00371                 rpmlog(RPMLOG_CRIT, _("package without owner/group tags\n"));
    00372             }
    00373         }
    00374         flushBuffer(&t, &te, 0);
    00375         fdigest = _free(fdigest);
    00376     }
    00377
    00378     rc = 0;
    00379
    00380 exit:
    00381     flushBuffer(&t, &te, 0);
    00382     t = _free(t);
    00383
    00384     fi = rpmfiFree(fi);
    00385     return rc;
    00386 }
    00387
    00388 static int rpmgiShowMatches(QVA_t qva, rpmts ts)
    00389         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00390         /*@modifies qva, rpmGlobalMacroContext, h_errno, internalState @*/
    00391 {
    00392     rpmgi gi = qva->qva_gi;
    00393     rpmRC rpmrc = RPMRC_NOTFOUND;
    00394     int ec = 0;
    00395
    00396     while ((rpmrc = rpmgiNext(gi)) == RPMRC_OK) {
    00397         Header h;
    00398         int rc;
    00399
    00400 #ifdef  NOTYET  /* XXX exiting here will leave stale locks. */
    00401         (void) rpmdbCheckSignals();
    00402 #endif
    00403
    00404         h = rpmgiHeader(gi);
    00405         if (h == NULL)          /* XXX perhaps stricter break instead? */
    00406             continue;
    00407         if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
    00408             ec = rc;
    00409         if (qva->qva_source == RPMQV_DBOFFSET)
    00410             break;
    00411     }
    00412     if (ec == 0 && rpmrc == RPMRC_FAIL)
    00413         ec++;
    00414     return ec;
    00415 }
    00416
    00417 int rpmcliShowMatches(QVA_t qva, rpmts ts)
    00418 {
    00419     Header h;
    00420     int ec = 1;
    00421
    00422     qva->qva_showFAIL = qva->qva_showOK = 0;
    00423     while ((h = rpmmiNext(qva->qva_mi)) != NULL) {
    00424         ec = qva->qva_showPackage(qva, ts, h);
    00425         if (ec)
    00426             qva->qva_showFAIL++;
    00427         else
    00428             qva->qva_showOK++;
    00429         if (qva->qva_source == RPMQV_DBOFFSET)
    00430             break;
    00431     }
    00432     qva->qva_mi = rpmmiFree(qva->qva_mi);
    00433     return ec;
    00434 }
    00435
    00441 static inline unsigned char nibble(char c)
    00442         /*@*/
    00443 {
    00444     if (c >= '0' && c <= '9')
    00445         return (c - '0');
    00446     if (c >= 'A' && c <= 'F')
    00447         return (c - 'A') + 10;
    00448     if (c >= 'a' && c <= 'f')
    00449         return (c - 'a') + 10;
    00450     return 0;
    00451 }
    00452
    00453 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
    00454 {
    00455     int res = 0;
    00456     const char * s;
    00457     int i;
    00458     int provides_checked = 0;
    00459
    00460     (void) rpmdbCheckSignals();
    00461
    00462     if (qva->qva_showPackage == NULL)
    00463         return 1;
    00464
    00465     switch (qva->qva_source) {
    00466 #ifdef  NOTYET
    00467     default:
    00468 #endif
    00469     case RPMQV_GROUP:
    00470     case RPMQV_TRIGGEREDBY:
    00471     case RPMQV_WHATCONFLICTS:
    00472     case RPMQV_WHATOBSOLETES:
    00473         qva->qva_mi = rpmtsInitIterator(ts, qva->qva_source, arg, 0);
    00474         if (qva->qva_mi == NULL) {
    00475             rpmlog(RPMLOG_NOTICE, _("key \"%s\" not found in %s table\n"),
    00476                         arg, tagName((rpmTag)qva->qva_source));
    00477             res = 1;
    00478         } else
    00479             res = rpmcliShowMatches(qva, ts);
    00480         break;
    00481
    00482     case RPMQV_RPM:
    00483         res = rpmgiShowMatches(qva, ts);
    00484         break;
    00485
    00486     case RPMQV_ALL:
    00487         res = rpmgiShowMatches(qva, ts);
    00488         break;
    00489
    00490     case RPMQV_HDLIST:
    00491         res = rpmgiShowMatches(qva, ts);
    00492         break;
    00493
    00494     case RPMQV_FTSWALK:
    00495         res = rpmgiShowMatches(qva, ts);
    00496         break;
    00497
    00498     case RPMQV_SPECSRPM:
    00499     case RPMQV_SPECFILE:
    00500         res = ((qva->qva_specQuery != NULL)
    00501                 ? qva->qva_specQuery(ts, qva, arg) : 1);
    00502         break;
    00503
    00504 #ifdef  DYING
    00505     case RPMQV_GROUP:
    00506         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
    00507         if (qva->qva_mi == NULL) {
    00508             rpmlog(RPMLOG_ERR,
    00509                 _("group %s does not contain any packages\n"), arg);
    00510             res = 1;
    00511         } else
    00512             res = rpmcliShowMatches(qva, ts);
    00513         break;
    00514
    00515     case RPMQV_TRIGGEREDBY:
    00516         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
    00517         if (qva->qva_mi == NULL) {
    00518             rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg);
    00519             res = 1;
    00520         } else
    00521             res = rpmcliShowMatches(qva, ts);
    00522         break;
    00523 #endif
    00524
    00525     case RPMQV_SOURCEPKGID:
    00526     case RPMQV_PKGID:
    00527     {   unsigned char MD5[16];
    00528         unsigned char * t;
    00529         rpmuint32_t tag;
    00530
    00531         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
    00532             {};
    00533         if (i != 32) {
    00534             rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "pkgid", arg);
    00535             return 1;
    00536         }
    00537
    00538         MD5[0] = '\0';
    00539         for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
    00540             *t = (nibble(s[0]) << 4) | nibble(s[1]);
    00541
    00542         tag = (qva->qva_source == RPMQV_PKGID
    00543                 ? RPMTAG_SOURCEPKGID : RPMTAG_PKGID);
    00544         qva->qva_mi = rpmtsInitIterator(ts, tag, MD5, sizeof(MD5));
    00545         if (qva->qva_mi == NULL) {
    00546             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
    00547                         "pkgid", arg);
    00548             res = 1;
    00549         } else
    00550             res = rpmcliShowMatches(qva, ts);
    00551     }   break;
    00552
    00553     case RPMQV_HDRID:
    00554         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
    00555             {};
    00556         if (i != 40) {
    00557             rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "hdrid", arg);
    00558             return 1;
    00559         }
    00560
    00561         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
    00562         if (qva->qva_mi == NULL) {
    00563             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
    00564                         "hdrid", arg);
    00565             res = 1;
    00566         } else
    00567             res = rpmcliShowMatches(qva, ts);
    00568         break;
    00569
    00570     case RPMQV_FILEID:
    00571     {   unsigned char * t;
    00572         unsigned char * digest;
    00573         size_t dlen;
    00574
    00575         /* Insure even no. of digits and at least 8 digits. */
    00576         for (dlen = 0, s = arg; *s && isxdigit(*s); s++, dlen++)
    00577             {};
    00578         if ((dlen & 1) || dlen < 8) {
    00579             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "fileid", arg);
    00580             return 1;
    00581         }
    00582
    00583         dlen /= 2;
    00584         digest = memset(alloca(dlen), 0, dlen);
    00585         for (t = digest, s = arg; *s; t++, s += 2)
    00586             *t = (nibble(s[0]) << 4) | nibble(s[1]);
    00587
    00588         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEDIGESTS, digest, dlen);
    00589         if (qva->qva_mi == NULL) {
    00590             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
    00591                         "fileid", arg);
    00592             res = 1;
    00593         } else
    00594             res = rpmcliShowMatches(qva, ts);
    00595     }   break;
    00596
    00597     case RPMQV_TID:
    00598     {   int mybase = 10;
    00599         const char * myarg = arg;
    00600         char * end = NULL;
    00601         unsigned iid;
    00602
    00603         /* XXX should be in strtoul */
    00604         if (*myarg == '0') {
    00605             myarg++;
    00606             mybase = 8;
    00607             if (*myarg == 'x') {
    00608                 myarg++;
    00609                 mybase = 16;
    00610             }
    00611         }
    00612         iid = (unsigned) strtoul(myarg, &end, mybase);
    00613         if ((*end) || (end == arg) || (iid == UINT_MAX)) {
    00614             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg);
    00615             return 1;
    00616         }
    00617         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
    00618         if (qva->qva_mi == NULL) {
    00619             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
    00620                         "tid", arg);
    00621             res = 1;
    00622         } else
    00623             res = rpmcliShowMatches(qva, ts);
    00624     }   break;
    00625
    00626     case RPMQV_WHATNEEDS:
    00627     case RPMQV_WHATREQUIRES:
    00628         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
    00629         if (qva->qva_mi == NULL) {
    00630             rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg);
    00631             res = 1;
    00632         } else
    00633             res = rpmcliShowMatches(qva, ts);
    00634         break;
    00635
    00636     case RPMQV_WHATPROVIDES:
    00637         if (arg[0] != '/') {
    00638             provides_checked = 1;
    00639             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
    00640             if (qva->qva_mi == NULL) {
    00641                 rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg);
    00642                 res = 1;
    00643             } else
    00644                 res = rpmcliShowMatches(qva, ts);
    00645             break;
    00646         }
    00647         /*@fallthrough@*/
    00648     case RPMQV_PATH:
    00649     {   char * fn;
    00650
    00651         for (s = arg; *s != '\0'; s++)
    00652             if (!(*s == '.' || *s == '/'))
    00653                 /*@loopbreak@*/ break;
    00654
    00655         if (*s == '\0') {
    00656             char fnbuf[PATH_MAX];
    00657             fn = Realpath(arg, fnbuf);
    00658             fn = xstrdup( (fn != NULL ? fn : arg) );
    00659         } else if (*arg != '/') {
    00660             const char *curDir = currentDirectory();
    00661             fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
    00662             curDir = _free(curDir);
    00663         } else
    00664             fn = xstrdup(arg);
    00665 assert(fn != NULL);
    00666         (void) rpmCleanPath(fn);
    00667
    00668         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
    00669         if (qva->qva_mi == NULL && !provides_checked)
    00670             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, fn, 0);
    00671
    00672         if (qva->qva_mi == NULL) {
    00673             struct stat sb;
    00674             if (Lstat(fn, &sb) != 0)
    00675                 rpmlog(RPMLOG_NOTICE, _("file %s: %s\n"), fn, strerror(errno));
    00676             else
    00677                 rpmlog(RPMLOG_NOTICE,
    00678                         _("file %s is not owned by any package\n"), fn);
    00679             res = 1;
    00680         } else
    00681             res = rpmcliShowMatches(qva, ts);
    00682
    00683         fn = _free(fn);
    00684     }   break;
    00685
    00686     case RPMQV_DBOFFSET:
    00687     {   int mybase = 10;
    00688         const char * myarg = arg;
    00689         char * end = NULL;
    00690         unsigned recOffset;
    00691
    00692         /* XXX should be in strtoul */
    00693         if (*myarg == '0') {
    00694             myarg++;
    00695             mybase = 8;
    00696             if (*myarg == 'x') {
    00697                 myarg++;
    00698                 mybase = 16;
    00699             }
    00700         }
    00701         recOffset = (unsigned) strtoul(myarg, &end, mybase);
    00702         if ((*end) || (end == arg) || (recOffset == UINT_MAX)) {
    00703             rpmlog(RPMLOG_NOTICE, _("invalid package number: %s\n"), arg);
    00704             return 1;
    00705         }
    00706         rpmlog(RPMLOG_DEBUG, D_("package record number: %u\n"), recOffset);
    00707         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
    00708         if (qva->qva_mi == NULL) {
    00709             rpmlog(RPMLOG_NOTICE,
    00710                 _("record %u could not be read\n"), recOffset);
    00711             res = 1;
    00712         } else
    00713             res = rpmcliShowMatches(qva, ts);
    00714     }   break;
    00715
    00716     case RPMQV_PACKAGE:
    00717         /* XXX HACK to get rpmdbFindByLabel out of the API */
    00718         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
    00719         if (qva->qva_mi == NULL) {
    00720             rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
    00721             res = 1;
    00722         } else {
    00723             res = rpmcliShowMatches(qva, ts);
    00724             /* detect foo.bogusarch empty iterations. */
    00725             if (qva->qva_showOK == 0 && qva->qva_showFAIL == 0) {
    00726                 rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
    00727                 res = 1;
    00728             }
    00729         }
    00730         break;
    00731     }
    00732
    00733     return res;
    00734 }
    00735
    00736 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_t argv)
    00737         /*@globals rpmioFtsOpts @*/
    00738         /*@modifies rpmioFtsOpts @*/
    00739 {
    00740     rpmRC rpmrc = RPMRC_NOTFOUND;
    00741     int ec = 0;
    00742
    00743     switch (qva->qva_source) {
    00744     case RPMQV_ALL:
    00745         qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
    00746         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, RPMGI_NONE);
    00747
    00748         if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD)   /* Load the ts with headers. */
    00749         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
    00750             {};
    00751         if (rpmrc != RPMRC_NOTFOUND)
    00752             return 1;   /* XXX should be no. of failures. */
    00753
    00754         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
    00755         ec = rpmQueryVerify(qva, ts, (const char *) argv);
    00756         /*@=nullpass@*/
    00757         rpmtsEmpty(ts);
    00758         break;
    00759     case RPMQV_RPM:
    00760         qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
    00761         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
    00762
    00763         if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD)   /* Load the ts with headers. */
    00764         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
    00765             {};
    00766         if (rpmrc != RPMRC_NOTFOUND)
    00767             return 1;   /* XXX should be no. of failures. */
    00768
    00769         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
    00770         ec = rpmQueryVerify(qva, ts, NULL);
    00771         /*@=nullpass@*/
    00772         rpmtsEmpty(ts);
    00773         break;
    00774     case RPMQV_HDLIST:
    00775         qva->qva_gi = rpmgiNew(ts, RPMDBI_HDLIST, NULL, 0);
    00776         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
    00777
    00778         if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD)   /* Load the ts with headers. */
    00779         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
    00780             {};
    00781         if (rpmrc != RPMRC_NOTFOUND)
    00782             return 1;   /* XXX should be no. of failures. */
    00783
    00784         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
    00785         ec = rpmQueryVerify(qva, ts, NULL);
    00786         /*@=nullpass@*/
    00787         rpmtsEmpty(ts);
    00788         break;
    00789     case RPMQV_FTSWALK:
    00790         if (rpmioFtsOpts == 0)
    00791             rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
    00792         qva->qva_gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
    00793         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
    00794
    00795         if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD)   /* Load the ts with headers. */
    00796         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
    00797             {};
    00798         if (rpmrc != RPMRC_NOTFOUND)
    00799             return 1;   /* XXX should be no. of failures. */
    00800
    00801         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
    00802         ec = rpmQueryVerify(qva, ts, NULL);
    00803         /*@=nullpass@*/
    00804         rpmtsEmpty(ts);
    00805         break;
    00806     default:
    00807       if (giFlags & RPMGI_TSADD) {
    00808         qva->qva_gi = rpmgiNew(ts, RPMDBI_LABEL, NULL, 0);
    00809         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
    00810                 (giFlags | (RPMGI_NOGLOB               )));
    00811         if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD)   /* Load the ts with headers. */
    00812         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
    00813             {};
    00814         if (rpmrc != RPMRC_NOTFOUND)
    00815             return 1;   /* XXX should be no. of failures. */
    00816         qva->qva_source = RPMQV_ALL;
    00817         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
    00818         ec = rpmQueryVerify(qva, ts, NULL);
    00819         /*@=nullpass@*/
    00820         rpmtsEmpty(ts);
    00821       } else {
    00822         qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
    00823         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
    00824                 (giFlags | (RPMGI_NOGLOB|RPMGI_NOHEADER)));
    00825         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK) {
    00826             const char * path;
    00827             path = rpmgiHdrPath(qva->qva_gi);
    00828 assert(path != NULL);
    00829             ec += rpmQueryVerify(qva, ts, path);
    00830             rpmtsEmpty(ts);
    00831         }
    00832       }
    00833         break;
    00834     }
    00835
    00836     qva->qva_gi = rpmgiFree(qva->qva_gi);
    00837
    00838     return ec;
    00839 }
    00840
    00841 int rpmcliQuery(rpmts ts, QVA_t qva, const char ** argv)
    00842 {
    00843     rpmdepFlags depFlags = qva->depFlags, odepFlags;
    00844     rpmtransFlags transFlags = qva->transFlags, otransFlags;
    00845     rpmVSFlags vsflags, ovsflags;
    00846     int ec = 0;
    00847
    00848     if (qva->qva_showPackage == NULL)
    00849         qva->qva_showPackage = showQueryPackage;
    00850
    00851     /* If --queryformat unspecified, then set default now. */
    00852     if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) {
    00853         qva->qva_queryFormat = rpmExpand("%{?_query_all_fmt}\n", NULL);
    00854         if (!(qva->qva_queryFormat != NULL && *qva->qva_queryFormat != '\0')) {
    00855             qva->qva_queryFormat = _free(qva->qva_queryFormat);
    00856             qva->qva_queryFormat = xstrdup("%{name}-%{version}-%{release}.%{arch}\n");
    00857         }
    00858     }
    00859
    00860     vsflags = rpmExpandNumeric("%{?_vsflags_query}");
    00861     if (qva->qva_flags & VERIFY_DIGEST)
    00862         vsflags |= _RPMVSF_NODIGESTS;
    00863     if (qva->qva_flags & VERIFY_SIGNATURE)
    00864         vsflags |= _RPMVSF_NOSIGNATURES;
    00865     if (qva->qva_flags & VERIFY_HDRCHK)
    00866         vsflags |= RPMVSF_NOHDRCHK;
    00867
    00868     odepFlags = rpmtsSetDFlags(ts, depFlags);
    00869     otransFlags = rpmtsSetFlags(ts, transFlags);
    00870     ovsflags = rpmtsSetVSFlags(ts, vsflags);
    00871     ec = rpmcliArgIter(ts, qva, argv);
    00872     vsflags = rpmtsSetVSFlags(ts, ovsflags);
    00873     transFlags = rpmtsSetFlags(ts, otransFlags);
    00874     depFlags = rpmtsSetDFlags(ts, odepFlags);
    00875
    00876     if (qva->qva_showPackage == showQueryPackage)
    00877         qva->qva_showPackage = NULL;
    00878
    00879     return ec;
    00880 }