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

- File List
- Globals

# lib/query.c

Go to the documentation of this file.

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