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