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