rpm 5.3.12
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 
00428 static int rpmcliShowMatches(QVA_t qva, rpmts ts)
00429         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00430         /*@modifies qva, rpmGlobalMacroContext, fileSystem, internalState @*/
00431 {
00432     Header h;
00433     int ec = 1;
00434 
00435     qva->qva_showFAIL = qva->qva_showOK = 0;
00436     while ((h = rpmmiNext(qva->qva_mi)) != NULL) {
00437         ec = qva->qva_showPackage(qva, ts, h);
00438         if (ec)
00439             qva->qva_showFAIL++;
00440         else
00441             qva->qva_showOK++;
00442         if (qva->qva_source == RPMQV_DBOFFSET)
00443             break;
00444     }
00445     qva->qva_mi = rpmmiFree(qva->qva_mi);
00446     return ec;
00447 }
00448 
00454 static inline unsigned char nibble(char c)
00455         /*@*/
00456 {
00457     if (c >= '0' && c <= '9')
00458         return (c - '0');
00459     if (c >= 'A' && c <= 'F')
00460         return (c - 'A') + 10;
00461     if (c >= 'a' && c <= 'f')
00462         return (c - 'a') + 10;
00463     return 0;
00464 }
00465 
00466 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
00467 {
00468     int res = 0;
00469     const char * s;
00470     int i;
00471     int provides_checked = 0;
00472 
00473     (void) rpmdbCheckSignals();
00474 
00475     if (qva->qva_showPackage == NULL)
00476         return 1;
00477 
00478     switch (qva->qva_source) {
00479 #ifdef  NOTYET
00480     default:
00481 #endif
00482     case RPMQV_GROUP:
00483     case RPMQV_TRIGGEREDBY:
00484     case RPMQV_WHATCONFLICTS:
00485     case RPMQV_WHATOBSOLETES:
00486         qva->qva_mi = rpmtsInitIterator(ts, qva->qva_source, arg, 0);
00487         if (qva->qva_mi == NULL) {
00488             rpmlog(RPMLOG_NOTICE, _("key \"%s\" not found in %s table\n"),
00489                         arg, tagName((rpmTag)qva->qva_source));
00490             res = 1;
00491         } else
00492             res = rpmcliShowMatches(qva, ts);
00493         break;
00494 
00495     case RPMQV_RPM:
00496         res = rpmgiShowMatches(qva, ts);
00497         break;
00498 
00499     case RPMQV_ALL:
00500         res = rpmgiShowMatches(qva, ts);
00501         break;
00502 
00503     case RPMQV_HDLIST:
00504         res = rpmgiShowMatches(qva, ts);
00505         break;
00506 
00507     case RPMQV_FTSWALK:
00508         res = rpmgiShowMatches(qva, ts);
00509         break;
00510 
00511     case RPMQV_SPECSRPM:
00512     case RPMQV_SPECFILE:
00513         res = ((qva->qva_specQuery != NULL)
00514                 ? qva->qva_specQuery(ts, qva, arg) : 1);
00515         break;
00516 
00517 #ifdef  DYING
00518     case RPMQV_GROUP:
00519         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
00520         if (qva->qva_mi == NULL) {
00521             rpmlog(RPMLOG_ERR,
00522                 _("group %s does not contain any packages\n"), arg);
00523             res = 1;
00524         } else
00525             res = rpmcliShowMatches(qva, ts);
00526         break;
00527 
00528     case RPMQV_TRIGGEREDBY:
00529         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
00530         if (qva->qva_mi == NULL) {
00531             rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg);
00532             res = 1;
00533         } else
00534             res = rpmcliShowMatches(qva, ts);
00535         break;
00536 #endif
00537 
00538     case RPMQV_SOURCEPKGID:
00539     case RPMQV_PKGID:
00540     {   unsigned char MD5[16];
00541         unsigned char * t;
00542         rpmuint32_t tag;
00543 
00544         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
00545             {};
00546         if (i != 32) {
00547             rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "pkgid", arg);
00548             return 1;
00549         }
00550 
00551         MD5[0] = '\0';
00552         for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
00553             *t = (nibble(s[0]) << 4) | nibble(s[1]);
00554         
00555         tag = (qva->qva_source == RPMQV_PKGID
00556                 ? RPMTAG_SOURCEPKGID : RPMTAG_PKGID);
00557         qva->qva_mi = rpmtsInitIterator(ts, tag, MD5, sizeof(MD5));
00558         if (qva->qva_mi == NULL) {
00559             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
00560                         "pkgid", arg);
00561             res = 1;
00562         } else
00563             res = rpmcliShowMatches(qva, ts);
00564     }   break;
00565 
00566     case RPMQV_HDRID:
00567         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
00568             {};
00569         if (i != 40) {
00570             rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "hdrid", arg);
00571             return 1;
00572         }
00573 
00574         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
00575         if (qva->qva_mi == NULL) {
00576             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
00577                         "hdrid", arg);
00578             res = 1;
00579         } else
00580             res = rpmcliShowMatches(qva, ts);
00581         break;
00582 
00583     case RPMQV_FILEID:
00584     {   unsigned char * t;
00585         unsigned char * digest;
00586         size_t dlen;
00587 
00588         /* Insure even no. of digits and at least 8 digits. */
00589         for (dlen = 0, s = arg; *s && isxdigit(*s); s++, dlen++)
00590             {};
00591         if ((dlen & 1) || dlen < 8) {
00592             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "fileid", arg);
00593             return 1;
00594         }
00595 
00596         dlen /= 2;
00597         digest = memset(alloca(dlen), 0, dlen);
00598         for (t = digest, s = arg; *s; t++, s += 2)
00599             *t = (nibble(s[0]) << 4) | nibble(s[1]);
00600 
00601         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEDIGESTS, digest, dlen);
00602         if (qva->qva_mi == NULL) {
00603             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
00604                         "fileid", arg);
00605             res = 1;
00606         } else
00607             res = rpmcliShowMatches(qva, ts);
00608     }   break;
00609 
00610     case RPMQV_TID:
00611     {   int mybase = 10;
00612         const char * myarg = arg;
00613         char * end = NULL;
00614         unsigned iid;
00615 
00616         /* XXX should be in strtoul */
00617         if (*myarg == '0') {
00618             myarg++;
00619             mybase = 8;
00620             if (*myarg == 'x') {
00621                 myarg++;
00622                 mybase = 16;
00623             }
00624         }
00625         iid = (unsigned) strtoul(myarg, &end, mybase);
00626         if ((*end) || (end == arg) || (iid == UINT_MAX)) {
00627             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg);
00628             return 1;
00629         }
00630         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
00631         if (qva->qva_mi == NULL) {
00632             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
00633                         "tid", arg);
00634             res = 1;
00635         } else
00636             res = rpmcliShowMatches(qva, ts);
00637     }   break;
00638 
00639     case RPMQV_WHATNEEDS:
00640     case RPMQV_WHATREQUIRES:
00641         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
00642         if (qva->qva_mi == NULL) {
00643             rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg);
00644             res = 1;
00645         } else
00646             res = rpmcliShowMatches(qva, ts);
00647         break;
00648 
00649     case RPMQV_WHATPROVIDES:
00650         if (arg[0] != '/') {
00651             provides_checked = 1;
00652             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
00653             if (qva->qva_mi == NULL) {
00654                 rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg);
00655                 res = 1;
00656             } else
00657                 res = rpmcliShowMatches(qva, ts);
00658             break;
00659         }
00660         /*@fallthrough@*/
00661     case RPMQV_PATH:
00662     {   int gotpattern = 0;
00663         char * fn;
00664 
00665         if (arg[0] == '^' || arg[strlen(arg)-1] == '$') {
00666             fn = xstrdup(arg);
00667             gotpattern++;
00668         } else
00669 #ifdef  NOTYET
00670         if (arg[0] == '/' && Glob_pattern_p(arg, 1)) {
00671             fn = xstrdup(arg);
00672             gotpattern++;
00673         } else
00674 #endif
00675         {
00676             for (s = arg; *s != '\0'; s++) {
00677                 if (!(*s == '.' || *s == '/'))
00678                     /*@loopbreak@*/ break;
00679             }
00680 
00681             if (*s == '\0') {
00682                 char fnbuf[PATH_MAX];
00683                 fn = Realpath(arg, fnbuf);
00684                 fn = xstrdup( (fn != NULL ? fn : arg) );
00685             } else if (*arg != '/') {
00686                 const char *curDir = currentDirectory();
00687                 fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
00688                 curDir = _free(curDir);
00689             } else
00690                 fn = xstrdup(arg);
00691             (void) rpmCleanPath(fn);
00692         }
00693 
00694         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEPATHS, fn, 0);
00695         if (qva->qva_mi == NULL && !provides_checked && !gotpattern) {
00696             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, fn, 0);
00697 #if defined(RPM_VENDOR_MANDRIVA)
00698         if(rpmmiCount(qva->qva_mi) == 0)
00699             qva->qva_mi = rpmmiFree(qva->qva_mi);
00700 #endif
00701         }
00702 
00703         if (qva->qva_mi == NULL) {
00704             struct stat sb;
00705             if (!gotpattern && Lstat(fn, &sb) != 0)
00706                 rpmlog(RPMLOG_NOTICE, _("file %s: %s\n"), fn, strerror(errno));
00707             else
00708                 rpmlog(RPMLOG_NOTICE,
00709                         _("file %s is not owned by any package\n"), fn);
00710             res = 1;
00711         } else
00712             res = rpmcliShowMatches(qva, ts);
00713 
00714         fn = _free(fn);
00715     }   break;
00716 
00717     case RPMQV_DBOFFSET:
00718     {   int mybase = 10;
00719         const char * myarg = arg;
00720         char * end = NULL;
00721         uint32_t hdrNum;
00722 
00723         /* XXX should be in strtoul */
00724         if (*myarg == '0') {
00725             myarg++;
00726             mybase = 8;
00727             if (*myarg == 'x') {
00728                 myarg++;
00729                 mybase = 16;
00730             }
00731         }
00732         hdrNum = (uint32_t) strtoul(myarg, &end, mybase);
00733         if ((*end) || (end == arg) || (hdrNum == UINT_MAX)) {
00734             rpmlog(RPMLOG_NOTICE, _("invalid package number: %s\n"), arg);
00735             return 1;
00736         }
00737         rpmlog(RPMLOG_DEBUG, D_("package record number: %u\n"), (unsigned)hdrNum);
00738         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
00739         if (qva->qva_mi == NULL) {
00740             rpmlog(RPMLOG_NOTICE,
00741                 _("record %u could not be read\n"), (unsigned)hdrNum);
00742             res = 1;
00743         } else
00744             res = rpmcliShowMatches(qva, ts);
00745     }   break;
00746 
00747     case RPMQV_PACKAGE:
00748         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_NVRA, arg, 0);
00749         if (qva->qva_mi == NULL) {
00750             rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
00751             res = 1;
00752         } else {
00753             res = rpmcliShowMatches(qva, ts);
00754             /* detect foo.bogusarch empty iterations. */
00755             if (qva->qva_showOK == 0 && qva->qva_showFAIL == 0) {
00756                 rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
00757                 res = 1;
00758             }
00759         }
00760         break;
00761     }
00762    
00763     return res;
00764 }
00765 
00766 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_t argv)
00767         /*@globals rpmioFtsOpts @*/
00768         /*@modifies rpmioFtsOpts @*/
00769 {
00770     rpmRC rpmrc = RPMRC_NOTFOUND;
00771     int ec = 0;
00772 
00773     switch (qva->qva_source) {
00774     case RPMQV_ALL:
00775         qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
00776         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, RPMGI_NONE);
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, (const char *) argv);
00786         /*@=nullpass@*/
00787         rpmtsEmpty(ts);
00788         break;
00789     case RPMQV_RPM:
00790         qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
00791         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
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, NULL);
00801         /*@=nullpass@*/
00802         rpmtsEmpty(ts);
00803         break;
00804     case RPMQV_HDLIST:
00805         qva->qva_gi = rpmgiNew(ts, RPMDBI_HDLIST, 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_FTSWALK:
00820         if (rpmioFtsOpts == 0)
00821             rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
00822         qva->qva_gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
00823         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
00824 
00825         if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD)   /* Load the ts with headers. */
00826         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
00827             {};
00828         if (rpmrc != RPMRC_NOTFOUND)
00829             return 1;   /* XXX should be no. of failures. */
00830         
00831         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
00832         ec = rpmQueryVerify(qva, ts, NULL);
00833         /*@=nullpass@*/
00834         rpmtsEmpty(ts);
00835         break;
00836     default:
00837       if (giFlags & RPMGI_TSADD) {
00838         qva->qva_gi = rpmgiNew(ts, RPMTAG_NVRA, NULL, 0);
00839         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
00840                 (giFlags | (RPMGI_NOGLOB               )));
00841         if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD)   /* Load the ts with headers. */
00842         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
00843             {};
00844         if (rpmrc != RPMRC_NOTFOUND)
00845             return 1;   /* XXX should be no. of failures. */
00846         qva->qva_source = RPMQV_ALL;
00847         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
00848         ec = rpmQueryVerify(qva, ts, NULL);
00849         /*@=nullpass@*/
00850         rpmtsEmpty(ts);
00851       } else {
00852         qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
00853         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
00854                 (giFlags | (RPMGI_NOGLOB|RPMGI_NOHEADER)));
00855         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK) {
00856             const char * path;
00857             path = rpmgiHdrPath(qva->qva_gi);
00858 assert(path != NULL);
00859             ec += rpmQueryVerify(qva, ts, path);
00860             rpmtsEmpty(ts);
00861         }
00862       }
00863         break;
00864     }
00865 
00866     qva->qva_gi = rpmgiFree(qva->qva_gi);
00867 
00868     return ec;
00869 }
00870 
00871 int rpmcliQuery(rpmts ts, QVA_t qva, const char ** argv)
00872 {
00873     rpmdepFlags depFlags = qva->depFlags, odepFlags;
00874     rpmtransFlags transFlags = qva->transFlags, otransFlags;
00875     rpmVSFlags vsflags, ovsflags;
00876     int ec = 0;
00877 
00878     if (qva->qva_showPackage == NULL)
00879         qva->qva_showPackage = showQueryPackage;
00880 
00881     /* If --queryformat unspecified, then set default now. */
00882     if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) {
00883         qva->qva_queryFormat = rpmExpand("%{?_query_all_fmt}\n", NULL);
00884         if (!(qva->qva_queryFormat != NULL && *qva->qva_queryFormat != '\0')) {
00885             qva->qva_queryFormat = _free(qva->qva_queryFormat);
00886             qva->qva_queryFormat = xstrdup("%{name}-%{version}-%{release}.%{arch}\n");
00887         }
00888     }
00889 
00890     vsflags = rpmExpandNumeric("%{?_vsflags_query}");
00891     if (qva->qva_flags & VERIFY_DIGEST)
00892         vsflags |= _RPMVSF_NODIGESTS;
00893     if (qva->qva_flags & VERIFY_SIGNATURE)
00894         vsflags |= _RPMVSF_NOSIGNATURES;
00895     if (qva->qva_flags & VERIFY_HDRCHK)
00896         vsflags |= RPMVSF_NOHDRCHK;
00897 
00898     odepFlags = rpmtsSetDFlags(ts, depFlags);
00899     otransFlags = rpmtsSetFlags(ts, transFlags);
00900     ovsflags = rpmtsSetVSFlags(ts, vsflags);
00901     ec = rpmcliArgIter(ts, qva, argv);
00902     vsflags = rpmtsSetVSFlags(ts, ovsflags);
00903     transFlags = rpmtsSetFlags(ts, otransFlags);
00904     depFlags = rpmtsSetDFlags(ts, odepFlags);
00905 
00906     if (qva->qva_showPackage == showQueryPackage)
00907         qva->qva_showPackage = NULL;
00908 
00909     return ec;
00910 }