Main Page Modules Data Structures File List Data Fields Globals Related Pages

# 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 #include <rpmbuild.h>
    00016
    00017 #include "rpmdb.h"
    00018 #include "rpmfi.h"
    00019 #include "rpmts.h"
    00020
    00021 #include "manifest.h"
    00022
    00023 #include "debug.h"
    00024
    00025 /*@access rpmdbMatchIterator@*/         /* XXX compared with NULL */
    00026 /*@access Header@*/                     /* XXX compared with NULL */
    00027 /*@access FD_t@*/                       /* XXX compared with NULL */
    00028
    00031 static void printFileInfo(char * te, const char * name,
    00032                           unsigned int size, unsigned short mode,
    00033                           unsigned int mtime,
    00034                           unsigned short rdev, unsigned int nlink,
    00035                           const char * owner, const char * group,
    00036                           const char * linkto)
    00037         /*@modifies *te @*/
    00038 {
    00039     char sizefield[15];
    00040     char ownerfield[8+1], groupfield[8+1];
    00041     char timefield[100];
    00042     time_t when = mtime;  /* important if sizeof(int_32) ! sizeof(time_t) */
    00043     struct tm * tm;
    00044     static time_t now;
    00045     static struct tm nowtm;
    00046     const char * namefield = name;
    00047     char * perms = rpmPermsString(mode);
    00048
    00049     /* On first call, grab snapshot of now */
    00050     if (now == 0) {
    00051         now = time(NULL);
    00052         tm = localtime(&now);
    00053 /*@-boundsread@*/
    00054         if (tm) nowtm = *tm;    /* structure assignment */
    00055 /*@=boundsread@*/
    00056     }
    00057
    00058     strncpy(ownerfield, owner, sizeof(ownerfield));
    00059     ownerfield[sizeof(ownerfield)-1] = '\0';
    00060
    00061     strncpy(groupfield, group, sizeof(groupfield));
    00062     groupfield[sizeof(groupfield)-1] = '\0';
    00063
    00064     /* this is normally right */
    00065     sprintf(sizefield, "%12u", size);
    00066
    00067     /* this knows too much about dev_t */
    00068
    00069     if (S_ISLNK(mode)) {
    00070         char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
    00071         sprintf(nf, "%s -> %s", name, linkto);
    00072         namefield = nf;
    00073     } else if (S_ISCHR(mode)) {
    00074         perms[0] = 'c';
    00075         sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
    00076                         ((unsigned)rdev & 0xff));
    00077     } else if (S_ISBLK(mode)) {
    00078         perms[0] = 'b';
    00079         sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
    00080                         ((unsigned)rdev & 0xff));
    00081     }
    00082
    00083     /* Convert file mtime to display format */
    00084     tm = localtime(&when);
    00085     timefield[0] = '\0';
    00086     if (tm != NULL)
    00087     {   const char *fmt;
    00088         if (now > when + 6L * 30L * 24L * 60L * 60L ||  /* Old. */
    00089             now < when - 60L * 60L)                     /* In the future.  */
    00090         {
    00091         /* The file is fairly old or in the future.
    00092          * POSIX says the cutoff is 6 months old;
    00093          * approximate this by 6*30 days.
    00094          * Allow a 1 hour slop factor for what is considered "the future",
    00095          * to allow for NFS server/client clock disagreement.
    00096          * Show the year instead of the time of day.
    00097          */
    00098             fmt = "%b %e  %Y";
    00099         } else {
    00100             fmt = "%b %e %H:%M";
    00101         }
    00102         (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
    00103     }
    00104
    00105     sprintf(te, "%s %4d %-8s%-8s %10s %s %s", perms,
    00106         (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
    00107     perms = _free(perms);
    00108 }
    00109
    00112 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
    00113         /*@*/
    00114 {
    00115     const char * errstr = "(unkown error)";
    00116     const char * str;
    00117
    00118 /*@-modobserver@*/
    00119     str = headerSprintf(h, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
    00120 /*@=modobserver@*/
    00121     if (str == NULL)
    00122         rpmError(RPMERR_QFMT, _("incorrect format: %s\n"), errstr);
    00123     return str;
    00124 }
    00125
    00126 int showQueryPackage(QVA_t qva, /*@unused@*/ rpmts ts, Header h)
    00127 {
    00128     int scareMem = 1;
    00129     rpmfi fi = NULL;
    00130     char * t, * te;
    00131     char * prefix = NULL;
    00132     int rc = 0;         /* XXX FIXME: need real return code */
    00133     int nonewline = 0;
    00134     int i;
    00135
    00136     te = t = xmalloc(BUFSIZ);
    00137 /*@-boundswrite@*/
    00138     *te = '\0';
    00139 /*@=boundswrite@*/
    00140
    00141     if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL)
    00142     {
    00143         const char * name, * version, * release;
    00144         (void) headerNVR(h, &name, &version, &release);
    00145 /*@-boundswrite@*/
    00146         te = stpcpy(te, name);
    00147         te = stpcpy( stpcpy(te, "-"), version);
    00148         te = stpcpy( stpcpy(te, "-"), release);
    00149 /*@=boundswrite@*/
    00150         goto exit;
    00151     }
    00152
    00153     if (qva->qva_queryFormat != NULL) {
    00154         const char * str = queryHeader(h, qva->qva_queryFormat);
    00155         nonewline = 1;
    00156         /*@-branchstate@*/
    00157         if (str) {
    00158             size_t tb = (te - t);
    00159             size_t sb = strlen(str);
    00160
    00161             if (sb >= (BUFSIZ - tb)) {
    00162                 t = xrealloc(t, BUFSIZ+sb);
    00163                 te = t + tb;
    00164             }
    00165 /*@-boundswrite@*/
    00166             /*@-usereleased@*/
    00167             te = stpcpy(te, str);
    00168             /*@=usereleased@*/
    00169 /*@=boundswrite@*/
    00170             str = _free(str);
    00171         }
    00172         /*@=branchstate@*/
    00173     }
    00174
    00175     if (!(qva->qva_flags & QUERY_FOR_LIST))
    00176         goto exit;
    00177
    00178     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
    00179     if (rpmfiFC(fi) <= 0) {
    00180 /*@-boundswrite@*/
    00181         te = stpcpy(te, _("(contains no files)"));
    00182 /*@=boundswrite@*/
    00183         goto exit;
    00184     }
    00185
    00186     fi = rpmfiInit(fi, 0);
    00187     if (fi != NULL)
    00188     while ((i = rpmfiNext(fi)) >= 0) {
    00189         rpmfileAttrs fflags;
    00190         unsigned short fmode;
    00191         unsigned short frdev;
    00192         unsigned int fmtime;
    00193         rpmfileState fstate;
    00194         size_t fsize;
    00195         const char * fn;
    00196         char fmd5[32+1];
    00197         const char * fuser;
    00198         const char * fgroup;
    00199         const char * flink;
    00200         int_32 fnlink;
    00201
    00202         fflags = rpmfiFFlags(fi);
    00203         fmode = rpmfiFMode(fi);
    00204         frdev = rpmfiFRdev(fi);
    00205         fmtime = rpmfiFMtime(fi);
    00206         fstate = rpmfiFState(fi);
    00207         fsize = rpmfiFSize(fi);
    00208         fn = rpmfiFN(fi);
    00209 /*@-bounds@*/
    00210         {   static char hex[] = "0123456789abcdef";
    00211             const char * s = rpmfiMD5(fi);
    00212             char * p = fmd5;
    00213             int j;
    00214             for (j = 0; j < 16; j++) {
    00215                 unsigned k = *s++;
    00216                 *p++ = hex[ (k >> 4) & 0xf ];
    00217                 *p++ = hex[ (k     ) & 0xf ];
    00218             }
    00219             *p = '\0';
    00220         }
    00221 /*@=bounds@*/
    00222         fuser = rpmfiFUser(fi);
    00223         fgroup = rpmfiFGroup(fi);
    00224         flink = rpmfiFLink(fi);
    00225         fnlink = rpmfiFNlink(fi);
    00226
    00227         /* If querying only docs, skip non-doc files. */
    00228         if ((qva->qva_flags & QUERY_FOR_DOCS) && !(fflags & RPMFILE_DOC))
    00229             continue;
    00230
    00231         /* If querying only configs, skip non-config files. */
    00232         if ((qva->qva_flags & QUERY_FOR_CONFIG) && !(fflags & RPMFILE_CONFIG))
    00233             continue;
    00234
    00235         /* If not querying %ghost, skip ghost files. */
    00236         if (!(qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
    00237             continue;
    00238
    00239 /*@-boundswrite@*/
    00240         if (!rpmIsVerbose() && prefix)
    00241             te = stpcpy(te, prefix);
    00242
    00243         if (qva->qva_flags & QUERY_FOR_STATE) {
    00244             switch (fstate) {
    00245             case RPMFILE_STATE_NORMAL:
    00246                 te = stpcpy(te, _("normal        "));
    00247                 /*@switchbreak@*/ break;
    00248             case RPMFILE_STATE_REPLACED:
    00249                 te = stpcpy(te, _("replaced      "));
    00250                 /*@switchbreak@*/ break;
    00251             case RPMFILE_STATE_NOTINSTALLED:
    00252                 te = stpcpy(te, _("not installed "));
    00253                 /*@switchbreak@*/ break;
    00254             case RPMFILE_STATE_NETSHARED:
    00255                 te = stpcpy(te, _("net shared    "));
    00256                 /*@switchbreak@*/ break;
    00257             case RPMFILE_STATE_MISSING:
    00258                 te = stpcpy(te, _("(no state)    "));
    00259                 /*@switchbreak@*/ break;
    00260             default:
    00261                 sprintf(te, _("(unknown %3d) "), fstate);
    00262                 te += strlen(te);
    00263                 /*@switchbreak@*/ break;
    00264             }
    00265         }
    00266 /*@=boundswrite@*/
    00267
    00268         if (qva->qva_flags & QUERY_FOR_DUMPFILES) {
    00269             sprintf(te, "%s %d %d %s 0%o ", fn, fsize, fmtime, fmd5, fmode);
    00270             te += strlen(te);
    00271
    00272             if (fuser && fgroup) {
    00273 /*@-nullpass@*/
    00274                 sprintf(te, "%s %s", fuser, fgroup);
    00275 /*@=nullpass@*/
    00276                 te += strlen(te);
    00277             } else {
    00278                 rpmError(RPMERR_INTERNAL,
    00279                         _("package has not file owner/group lists\n"));
    00280             }
    00281
    00282             sprintf(te, " %s %s %u ",
    00283                                  fflags & RPMFILE_CONFIG ? "1" : "0",
    00284                                  fflags & RPMFILE_DOC ? "1" : "0",
    00285                                  frdev);
    00286             te += strlen(te);
    00287
    00288             sprintf(te, "%s", (flink && *flink ? flink : "X"));
    00289             te += strlen(te);
    00290         } else
    00291         if (!rpmIsVerbose()) {
    00292 /*@-boundswrite@*/
    00293             te = stpcpy(te, fn);
    00294 /*@=boundswrite@*/
    00295         }
    00296         else {
    00297
    00298             /* XXX Adjust directory link count and size for display output. */
    00299             if (S_ISDIR(fmode)) {
    00300                 fnlink++;
    00301                 fsize = 0;
    00302             }
    00303
    00304             if (fuser && fgroup) {
    00305 /*@-nullpass@*/
    00306                 printFileInfo(te, fn, fsize, fmode, fmtime, frdev, fnlink,
    00307                                         fuser, fgroup, flink);
    00308 /*@=nullpass@*/
    00309                 te += strlen(te);
    00310             } else {
    00311                 rpmError(RPMERR_INTERNAL,
    00312                         _("package has neither file owner or id lists\n"));
    00313             }
    00314         }
    00315         if (te > t) {
    00316 /*@-boundswrite@*/
    00317             *te++ = '\n';
    00318             *te = '\0';
    00319             rpmMessage(RPMMESS_NORMAL, "%s", t);
    00320             te = t;
    00321             *t = '\0';
    00322 /*@=boundswrite@*/
    00323         }
    00324     }
    00325
    00326     rc = 0;
    00327
    00328 exit:
    00329     if (te > t) {
    00330         if (!nonewline) {
    00331 /*@-boundswrite@*/
    00332             *te++ = '\n';
    00333             *te = '\0';
    00334 /*@=boundswrite@*/
    00335         }
    00336         rpmMessage(RPMMESS_NORMAL, "%s", t);
    00337     }
    00338     t = _free(t);
    00339
    00340     fi = rpmfiFree(fi);
    00341     return rc;
    00342 }
    00343
    00348 static void
    00349 printNewSpecfile(Spec spec)
    00350         /*@globals fileSystem @*/
    00351         /*@modifies spec->sl->sl_lines[], fileSystem @*/
    00352 {
    00353     Header h;
    00354     speclines sl = spec->sl;
    00355     spectags st = spec->st;
    00356     const char * msgstr = NULL;
    00357     int i, j;
    00358
    00359     if (sl == NULL || st == NULL)
    00360         return;
    00361
    00362     /*@-branchstate@*/
    00363     for (i = 0; i < st->st_ntags; i++) {
    00364         spectag t = st->st_t + i;
    00365         const char * tn = tagName(t->t_tag);
    00366         const char * errstr;
    00367         char fmt[1024];
    00368
    00369         fmt[0] = '\0';
    00370         if (t->t_msgid == NULL)
    00371             h = spec->packages->header;
    00372         else {
    00373             Package pkg;
    00374             char *fe;
    00375
    00376 /*@-bounds@*/
    00377             strcpy(fmt, t->t_msgid);
    00378             for (fe = fmt; *fe && *fe != '('; fe++)
    00379                 {} ;
    00380             if (*fe == '(') *fe = '\0';
    00381 /*@=bounds@*/
    00382             h = NULL;
    00383             for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
    00384                 const char *pkgname;
    00385                 h = pkg->header;
    00386                 (void) headerNVR(h, &pkgname, NULL, NULL);
    00387                 if (!strcmp(pkgname, fmt))
    00388                     /*@innerbreak@*/ break;
    00389             }
    00390             if (pkg == NULL || h == NULL)
    00391                 h = spec->packages->header;
    00392         }
    00393
    00394         if (h == NULL)
    00395             continue;
    00396
    00397         fmt[0] = '\0';
    00398 /*@-boundswrite@*/
    00399         (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}");
    00400 /*@=boundswrite@*/
    00401         msgstr = _free(msgstr);
    00402
    00403         /* XXX this should use queryHeader(), but prints out tn as well. */
    00404         msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
    00405         if (msgstr == NULL) {
    00406             rpmError(RPMERR_QFMT, _("can't query %s: %s\n"), tn, errstr);
    00407             return;
    00408         }
    00409
    00410 /*@-boundswrite@*/
    00411         switch(t->t_tag) {
    00412         case RPMTAG_SUMMARY:
    00413         case RPMTAG_GROUP:
    00414             /*@-unqualifiedtrans@*/
    00415             sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
    00416             /*@=unqualifiedtrans@*/
    00417             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
    00418                 continue;
    00419             {   char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
    00420                 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
    00421                 sl->sl_lines[t->t_startx] = buf;
    00422             }
    00423             /*@switchbreak@*/ break;
    00424         case RPMTAG_DESCRIPTION:
    00425             for (j = 1; j < t->t_nlines; j++) {
    00426                 if (*sl->sl_lines[t->t_startx + j] == '%')
    00427                     /*@innercontinue@*/ continue;
    00428                 /*@-unqualifiedtrans@*/
    00429                 sl->sl_lines[t->t_startx + j] =
    00430                         _free(sl->sl_lines[t->t_startx + j]);
    00431                 /*@=unqualifiedtrans@*/
    00432             }
    00433             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
    00434                 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
    00435                 continue;
    00436             }
    00437             sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
    00438             if (t->t_nlines > 2)
    00439                 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
    00440             /*@switchbreak@*/ break;
    00441         }
    00442 /*@=boundswrite@*/
    00443     }
    00444     /*@=branchstate@*/
    00445     msgstr = _free(msgstr);
    00446
    00447 /*@-boundsread@*/
    00448     for (i = 0; i < sl->sl_nlines; i++) {
    00449         const char * s = sl->sl_lines[i];
    00450         if (s == NULL)
    00451             continue;
    00452         printf("%s", s);
    00453         if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n')
    00454             printf("\n");
    00455     }
    00456 /*@=boundsread@*/
    00457 }
    00458
    00459 void rpmDisplayQueryTags(FILE * fp)
    00460 {
    00461     const struct headerTagTableEntry_s * t;
    00462     int i;
    00463     const struct headerSprintfExtension_s * ext = rpmHeaderFormats;
    00464
    00465     for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++)
    00466         if (t->name) fprintf(fp, "%s\n", t->name + 7);
    00467
    00468     while (ext->name != NULL) {
    00469         if (ext->type == HEADER_EXT_MORE) {
    00470             ext = ext->u.more;
    00471             continue;
    00472         }
    00473         /* XXX don't print query tags twice. */
    00474         for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
    00475             if (t->name == NULL)        /* XXX programmer error. */
    00476                 /*@innercontinue@*/ continue;
    00477             if (!strcmp(t->name, ext->name))
    00478                 /*@innerbreak@*/ break;
    00479         }
    00480         if (i >= rpmTagTableSize && ext->type == HEADER_EXT_TAG)
    00481             fprintf(fp, "%s\n", ext->name + 7);
    00482         ext++;
    00483     }
    00484 }
    00485
    00486 int rpmcliShowMatches(QVA_t qva, rpmts ts)
    00487 {
    00488     Header h;
    00489     int ec = 0;
    00490
    00491     while ((h = rpmdbNextIterator(qva->qva_mi)) != NULL) {
    00492         int rc;
    00493         if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
    00494             ec = rc;
    00495     }
    00496     qva->qva_mi = rpmdbFreeIterator(qva->qva_mi);
    00497     return ec;
    00498 }
    00499
    00505 static inline unsigned char nibble(char c)
    00506         /*@*/
    00507 {
    00508     if (c >= '0' && c <= '9')
    00509         return (c - '0');
    00510     if (c >= 'A' && c <= 'F')
    00511         return (c - 'A') + 10;
    00512     if (c >= 'a' && c <= 'f')
    00513         return (c - 'a') + 10;
    00514     return 0;
    00515 }
    00516
    00517 /*@-redecl@*/
    00521 int     (*parseSpecVec) (Spec *specp, const char *specFile, const char *rootdir,
    00522                 const char *buildRoot, int recursing, const char *passPhrase,
    00523                 char *cookie, int anyarch, int force) = NULL;
    00527 /*@null@*/ Spec (*freeSpecVec) (Spec spec) = NULL;
    00528 /*@=redecl@*/
    00529
    00530 /*@-bounds@*/ /* LCL: segfault (realpath annotation?) */
    00531 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
    00532 {
    00533     const char ** av = NULL;
    00534     int res = 0;
    00535     Header h;
    00536     int rc;
    00537     int xx;
    00538     const char * s;
    00539     int i;
    00540
    00541     (void) rpmdbCheckSignals();
    00542
    00543     if (qva->qva_showPackage == NULL)
    00544         return 1;
    00545
    00546     /*@-branchstate@*/
    00547     switch (qva->qva_source) {
    00548     case RPMQV_RPM:
    00549     {   int ac = 0;
    00550         const char * fileURL = NULL;
    00551         rpmRC rpmrc;
    00552
    00553         rc = rpmGlob(arg, &ac, &av);
    00554         if (rc) return 1;
    00555
    00556 restart:
    00557         for (i = 0; i < ac; i++) {
    00558             FD_t fd;
    00559
    00560             fileURL = _free(fileURL);
    00561             fileURL = av[i];
    00562             av[i] = NULL;
    00563
    00564             /* Try to read the header from a package file. */
    00565             fd = Fopen(fileURL, "r.ufdio");
    00566             if (fd == NULL || Ferror(fd)) {
    00567                 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL,
    00568                         Fstrerror(fd));
    00569                 if (fd) (void) Fclose(fd);
    00570                 res = 1;
    00571                 /*@loopbreak@*/ break;
    00572             }
    00573
    00574             rpmrc = rpmReadPackageFile(ts, fd, fileURL, &h);
    00575
    00576             (void) Fclose(fd);
    00577
    00578             res = 0;
    00579             switch (rpmrc) {
    00580             default:
    00581                 rpmError(RPMERR_QUERY, _("query of %s failed\n"), fileURL);
    00582                 res = 1;
    00583                 /*@switchbreak@*/ break;
    00584             case RPMRC_NOTTRUSTED:
    00585             case RPMRC_NOKEY:
    00586             case RPMRC_OK:
    00587                 if (h == NULL) {
    00588                     rpmError(RPMERR_QUERY,
    00589                         _("old format source packages cannot be queried\n"));
    00590                     res = 1;
    00591                     /*@switchbreak@*/ break;
    00592                 }
    00593
    00594                 /* Query a package file. */
    00595                 res = qva->qva_showPackage(qva, ts, h);
    00596                 h = headerFree(h);
    00597                 rpmtsEmpty(ts);
    00598                 continue;
    00599                 /*@notreached@*/ /*@switchbreak@*/ break;
    00600             case RPMRC_NOTFOUND:
    00601                 res = 0;
    00602                 /*@switchbreak@*/ break;
    00603             }
    00604             if (res)
    00605                 /*@loopbreak@*/ break;
    00606
    00607             /* Try to read a package manifest. */
    00608             fd = Fopen(fileURL, "r.fpio");
    00609             if (fd == NULL || Ferror(fd)) {
    00610                 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL,
    00611                         Fstrerror(fd));
    00612                 if (fd) (void) Fclose(fd);
    00613                 res = 1;
    00614                 /*@loopbreak@*/ break;
    00615             }
    00616
    00617             /* Read list of packages from manifest. */
    00618             res = rpmReadPackageManifest(fd, &ac, &av);
    00619             if (res != RPMRC_OK) {
    00620                 rpmError(RPMERR_MANIFEST, _("%s: not an rpm package (or package manifest): %s\n"),
    00621                         fileURL, Fstrerror(fd));
    00622                 res = 1;
    00623             }
    00624             (void) Fclose(fd);
    00625
    00626             /* If successful, restart the query loop. */
    00627             if (res == 0)
    00628                 goto restart;
    00629
    00630             /*@loopbreak@*/ break;
    00631         }
    00632
    00633         fileURL = _free(fileURL);
    00634         if (av) {
    00635             for (i = 0; i < ac; i++)
    00636                 av[i] = _free(av[i]);
    00637             av = _free(av);
    00638         }
    00639     }   break;
    00640
    00641     case RPMQV_SPECFILE:
    00642         if (qva->qva_showPackage != showQueryPackage)
    00643             return 1;
    00644
    00645         /* XXX Eliminate linkage dependency loop */
    00646         if (parseSpecVec == NULL || freeSpecVec == NULL)
    00647             return 1;
    00648
    00649       { Spec spec = NULL;
    00650         Package pkg;
    00651         char * buildRoot = NULL;
    00652         int recursing = 0;
    00653         char * passPhrase = "";
    00654         char *cookie = NULL;
    00655         int anyarch = 1;
    00656         int force = 1;
    00657
    00658         /*@-mods@*/ /* FIX: make spec abstract */
    00659         rc = parseSpecVec(&spec, arg, "/", buildRoot, recursing, passPhrase,
    00660                 cookie, anyarch, force);
    00661         /*@=mods@*/
    00662         if (rc || spec == NULL) {
    00663             rpmError(RPMERR_QUERY,
    00664                         _("query of specfile %s failed, can't parse\n"), arg);
    00665             spec = freeSpecVec(spec);
    00666             res = 1;
    00667             break;
    00668         }
    00669
    00670         if (specedit) {
    00671             printNewSpecfile(spec);
    00672             spec = freeSpecVec(spec);
    00673             res = 0;
    00674             break;
    00675         }
    00676
    00677         for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
    00678             xx = qva->qva_showPackage(qva, ts, pkg->header);
    00679         spec = freeSpecVec(spec);
    00680       } break;
    00681
    00682     case RPMQV_ALL:
    00683         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
    00684         if (qva->qva_mi == NULL) {
    00685             rpmError(RPMERR_QUERYINFO, _("no packages\n"));
    00686             res = 1;
    00687         } else {
    00688             if (arg != NULL)
    00689             for (av = (const char **) arg; *av; av++) {
    00690                 if (!rpmdbSetIteratorRE(qva->qva_mi, RPMTAG_NAME, RPMMIRE_DEFAULT, *av))
    00691                     continue;
    00692                 qva->qva_mi = rpmdbFreeIterator(qva->qva_mi);
    00693                 res = 1;
    00694                 /*@loopbreak@*/ break;
    00695             }
    00696             if (!res)
    00697                 res = rpmcliShowMatches(qva, ts);
    00698         }
    00699         break;
    00700
    00701     case RPMQV_GROUP:
    00702         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
    00703         if (qva->qva_mi == NULL) {
    00704             rpmError(RPMERR_QUERYINFO,
    00705                 _("group %s does not contain any packages\n"), arg);
    00706             res = 1;
    00707         } else {
    00708             res = rpmcliShowMatches(qva, ts);
    00709         }
    00710         break;
    00711
    00712     case RPMQV_TRIGGEREDBY:
    00713         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
    00714         if (qva->qva_mi == NULL) {
    00715             rpmError(RPMERR_QUERYINFO, _("no package triggers %s\n"), arg);
    00716             res = 1;
    00717         } else {
    00718             res = rpmcliShowMatches(qva, ts);
    00719         }
    00720         break;
    00721
    00722     case RPMQV_PKGID:
    00723     {   unsigned char MD5[16];
    00724         unsigned char * t;
    00725
    00726         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
    00727             {};
    00728         if (i != 32) {
    00729             rpmError(RPMERR_QUERYINFO, _("malformed %s: %s\n"), "pkgid", arg);
    00730             return 1;
    00731         }
    00732
    00733         MD5[0] = '\0';
    00734         for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
    00735             *t = (nibble(s[0]) << 4) | nibble(s[1]);
    00736
    00737         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SIGMD5, MD5, sizeof(MD5));
    00738         if (qva->qva_mi == NULL) {
    00739             rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
    00740                         "pkgid", arg);
    00741             res = 1;
    00742         } else {
    00743             res = rpmcliShowMatches(qva, ts);
    00744         }
    00745     }   break;
    00746
    00747     case RPMQV_HDRID:
    00748         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
    00749             {};
    00750         if (i != 40) {
    00751             rpmError(RPMERR_QUERYINFO, _("malformed %s: %s\n"), "hdrid", arg);
    00752             return 1;
    00753         }
    00754
    00755         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
    00756         if (qva->qva_mi == NULL) {
    00757             rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
    00758                         "hdrid", arg);
    00759             res = 1;
    00760         } else {
    00761             res = rpmcliShowMatches(qva, ts);
    00762         }
    00763         break;
    00764
    00765     case RPMQV_FILEID:
    00766     {   unsigned char MD5[16];
    00767         unsigned char * t;
    00768
    00769         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
    00770             {};
    00771         if (i != 32) {
    00772             rpmError(RPMERR_QUERY, _("malformed %s: %s\n"), "fileid", arg);
    00773             return 1;
    00774         }
    00775
    00776         MD5[0] = '\0';
    00777         for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
    00778             *t = (nibble(s[0]) << 4) | nibble(s[1]);
    00779
    00780         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEMD5S, MD5, sizeof(MD5));
    00781         if (qva->qva_mi == NULL) {
    00782             rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
    00783                         "fileid", arg);
    00784             res = 1;
    00785         } else {
    00786             res = rpmcliShowMatches(qva, ts);
    00787         }
    00788     }   break;
    00789
    00790     case RPMQV_TID:
    00791     {   int mybase = 10;
    00792         const char * myarg = arg;
    00793         char * end = NULL;
    00794         unsigned iid;
    00795
    00796         /* XXX should be in strtoul */
    00797         if (*myarg == '0') {
    00798             myarg++;
    00799             mybase = 8;
    00800             if (*myarg == 'x') {
    00801                 myarg++;
    00802                 mybase = 16;
    00803             }
    00804         }
    00805         iid = strtoul(myarg, &end, mybase);
    00806         if ((*end) || (end == arg) || (iid == ULONG_MAX)) {
    00807             rpmError(RPMERR_QUERY, _("malformed %s: %s\n"), "tid", arg);
    00808             return 1;
    00809         }
    00810         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
    00811         if (qva->qva_mi == NULL) {
    00812             rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
    00813                         "tid", arg);
    00814             res = 1;
    00815         } else {
    00816             res = rpmcliShowMatches(qva, ts);
    00817         }
    00818     }   break;
    00819
    00820     case RPMQV_WHATREQUIRES:
    00821         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
    00822         if (qva->qva_mi == NULL) {
    00823             rpmError(RPMERR_QUERYINFO, _("no package requires %s\n"), arg);
    00824             res = 1;
    00825         } else {
    00826             res = rpmcliShowMatches(qva, ts);
    00827         }
    00828         break;
    00829
    00830     case RPMQV_WHATPROVIDES:
    00831         if (arg[0] != '/') {
    00832             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
    00833             if (qva->qva_mi == NULL) {
    00834                 rpmError(RPMERR_QUERYINFO, _("no package provides %s\n"), arg);
    00835                 res = 1;
    00836             } else {
    00837                 res = rpmcliShowMatches(qva, ts);
    00838             }
    00839             break;
    00840         }
    00841         /*@fallthrough@*/
    00842     case RPMQV_PATH:
    00843     {   char * fn;
    00844
    00845         for (s = arg; *s != '\0'; s++)
    00846             if (!(*s == '.' || *s == '/'))
    00847                 /*@loopbreak@*/ break;
    00848
    00849         if (*s == '\0') {
    00850             char fnbuf[PATH_MAX];
    00851             fn = realpath(arg, fnbuf);
    00852             if (fn)
    00853                 fn = xstrdup(fn);
    00854             else
    00855                 fn = xstrdup(arg);
    00856         } else
    00857             fn = xstrdup(arg);
    00858         (void) rpmCleanPath(fn);
    00859
    00860         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
    00861         if (qva->qva_mi == NULL) {
    00862             int myerrno = 0;
    00863             if (access(fn, F_OK) != 0)
    00864                 myerrno = errno;
    00865             switch (myerrno) {
    00866             default:
    00867                 rpmError(RPMERR_QUERY,
    00868                         _("file %s: %s\n"), fn, strerror(myerrno));
    00869                 /*@innerbreak@*/ break;
    00870             case 0:
    00871                 rpmError(RPMERR_QUERYINFO,
    00872                         _("file %s is not owned by any package\n"), fn);
    00873                 /*@innerbreak@*/ break;
    00874             }
    00875             res = 1;
    00876         } else {
    00877             res = rpmcliShowMatches(qva, ts);
    00878         }
    00879         fn = _free(fn);
    00880     }   break;
    00881
    00882     case RPMQV_DBOFFSET:
    00883     {   int mybase = 10;
    00884         const char * myarg = arg;
    00885         char * end = NULL;
    00886         unsigned recOffset;
    00887
    00888         /* XXX should be in strtoul */
    00889         if (*myarg == '0') {
    00890             myarg++;
    00891             mybase = 8;
    00892             if (*myarg == 'x') {
    00893                 myarg++;
    00894                 mybase = 16;
    00895             }
    00896         }
    00897         recOffset = strtoul(myarg, &end, mybase);
    00898         if ((*end) || (end == arg) || (recOffset == ULONG_MAX)) {
    00899             rpmError(RPMERR_QUERYINFO, _("invalid package number: %s\n"), arg);
    00900             return 1;
    00901         }
    00902         rpmMessage(RPMMESS_DEBUG, _("package record number: %u\n"), recOffset);
    00903         /* RPMDBI_PACKAGES */
    00904         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
    00905         if (qva->qva_mi == NULL) {
    00906             rpmError(RPMERR_QUERYINFO,
    00907                 _("record %u could not be read\n"), recOffset);
    00908             res = 1;
    00909         } else {
    00910             res = rpmcliShowMatches(qva, ts);
    00911         }
    00912     }   break;
    00913
    00914     case RPMQV_PACKAGE:
    00915         /* XXX HACK to get rpmdbFindByLabel out of the API */
    00916         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
    00917         if (qva->qva_mi == NULL) {
    00918             rpmError(RPMERR_QUERYINFO, _("package %s is not installed\n"), arg);
    00919             res = 1;
    00920         } else {
    00921             res = rpmcliShowMatches(qva, ts);
    00922         }
    00923         break;
    00924     }
    00925     /*@=branchstate@*/
    00926
    00927     return res;
    00928 }
    00929 /*@=bounds@*/
    00930
    00931 int rpmcliQuery(rpmts ts, QVA_t qva, const char ** argv)
    00932 {
    00933     const char * arg;
    00934     rpmVSFlags vsflags, ovsflags;
    00935     int ec = 0;
    00936
    00937     if (qva->qva_showPackage == NULL)
    00938         qva->qva_showPackage = showQueryPackage;
    00939
    00940     vsflags = rpmExpandNumeric("%{?_vsflags_query}");
    00941     if (qva->qva_flags & VERIFY_DIGEST)
    00942         vsflags |= _RPMVSF_NODIGESTS;
    00943     if (qva->qva_flags & VERIFY_SIGNATURE)
    00944         vsflags |= _RPMVSF_NOSIGNATURES;
    00945     if (qva->qva_flags & VERIFY_HDRCHK)
    00946         vsflags |= RPMVSF_NOHDRCHK;
    00947
    00948     ovsflags = rpmtsSetVSFlags(ts, vsflags);
    00949     if (qva->qva_source == RPMQV_ALL) {
    00950         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
    00951         ec = rpmQueryVerify(qva, ts, (const char *) argv);
    00952         /*@=nullpass@*/
    00953     } else {
    00954 /*@-boundsread@*/
    00955         if (argv != NULL)
    00956         while ((arg = *argv++) != NULL) {
    00957             ec += rpmQueryVerify(qva, ts, arg);
    00958             rpmtsEmpty(ts);
    00959         }
    00960 /*@=boundsread@*/
    00961     }
    00962     vsflags = rpmtsSetVSFlags(ts, ovsflags);
    00963
    00964     if (qva->qva_showPackage == showQueryPackage)
    00965         qva->qva_showPackage = NULL;
    00966
    00967     return ec;
    00968 }