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

Generated on Fri Aug 31 11:16:07 2007 for rpm by  doxygen 1.4.6