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