/** \ingroup rpmcli * \file lib/query.c * Display tag values from package metadata. */ #include "system.h" #ifndef PATH_MAX /*@-incondefs@*/ /* FIX: long int? */ # define PATH_MAX 255 /*@=incondefs@*/ #endif #include "rpmcli.h" #include "rpmbuild.h" #include "manifest.h" #include "debug.h" /*@access rpmdbMatchIterator@*/ /* XXX compared with NULL */ /*@access Header@*/ /* XXX compared with NULL */ /*@access rpmdb@*/ /* XXX compared with NULL */ /*@access FD_t@*/ /* XXX compared with NULL */ /** */ static void printFileInfo(char * te, const char * name, unsigned int size, unsigned short mode, unsigned int mtime, unsigned short rdev, unsigned int nlink, const char * owner, const char * group, int uid, int gid, const char * linkto) /*@modifies *te @*/ { char sizefield[15]; char ownerfield[9], groupfield[9]; char timefield[100]; time_t when = mtime; /* important if sizeof(int_32) ! sizeof(time_t) */ struct tm * tm; static time_t now; static struct tm nowtm; const char * namefield = name; char * perms = rpmPermsString(mode); /* On first call, grab snapshot of now */ if (now == 0) { now = time(NULL); tm = localtime(&now); if (tm) nowtm = *tm; /* structure assignment */ } if (owner) strncpy(ownerfield, owner, 8); else sprintf(ownerfield, "%-8d", uid); ownerfield[8] = '\0'; if (group) strncpy(groupfield, group, 8); else sprintf(groupfield, "%-8d", gid); groupfield[8] = '\0'; /* this is normally right */ sprintf(sizefield, "%12u", size); /* this knows too much about dev_t */ if (S_ISLNK(mode)) { char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto)); sprintf(nf, "%s -> %s", name, linkto); namefield = nf; } else if (S_ISCHR(mode)) { perms[0] = 'c'; sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff), ((unsigned)rdev & 0xff)); } else if (S_ISBLK(mode)) { perms[0] = 'b'; sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff), ((unsigned)rdev & 0xff)); } /* Convert file mtime to display format */ tm = localtime(&when); timefield[0] = '\0'; if (tm != NULL) { const char *fmt; if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */ now < when - 60L * 60L) /* In the future. */ { /* The file is fairly old or in the future. * POSIX says the cutoff is 6 months old; * approximate this by 6*30 days. * Allow a 1 hour slop factor for what is considered "the future", * to allow for NFS server/client clock disagreement. * Show the year instead of the time of day. */ fmt = "%b %e %Y"; } else { fmt = "%b %e %H:%M"; } (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm); } sprintf(te, "%s %4d %-8s%-8s %10s %s %s", perms, (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield); perms = _free(perms); } /** */ static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt) /*@*/ { const char * errstr = "(unknown error)"; const char * str; str = headerSprintf(h, qfmt, rpmTagTable, rpmHeaderFormats, &errstr); if (str == NULL) rpmError(RPMERR_QFMT, _("incorrect format: %s\n"), errstr); return str; } /** */ static int countLinks(int_16 * fileRdevList, int_32 * fileInodeList, int nfiles, int xfile) /*@*/ { int nlink = 0; /* XXX rpm-3.3.12 has not RPMTAG_FILEINODES */ if (!(fileRdevList[xfile] != 0 && fileRdevList && fileInodeList[xfile] != 0 && fileInodeList && nfiles > 0)) return 1; while (nfiles-- > 0) { if (fileRdevList[nfiles] == 0) continue; if (fileRdevList[nfiles] != fileRdevList[xfile]) continue; if (fileInodeList[nfiles] == 0) continue; if (fileInodeList[nfiles] != fileInodeList[xfile]) continue; nlink++; } if (nlink == 0) nlink = 1; return nlink; } /** */ static void flushBuffer(char ** tp, char ** tep, int nonewline) /*@ modifies *tp, *tep @*/ { char *t, *te; t = *tp; te = *tep; if (te > t) { if (!nonewline) { *te++ = '\n'; *te = '\0'; } rpmMessage(RPMMESS_NORMAL, "%s", t); te = t; *t = '\0'; *tp = t; *tep = te; } } int showQueryPackage(QVA_t qva, /*@unused@*/rpmdb rpmdb, Header h) { HGE_t hge = (HGE_t)headerGetEntryMinMemory; HFD_t hfd = headerFreeData; size_t tb = 2 * BUFSIZ; size_t sb; char * t, * te; rpmQueryFlags queryFlags = qva->qva_flags; const char * queryFormat = qva->qva_queryFormat; rpmTagType type; int_32 count; char * prefix = NULL; const char ** dirNames = NULL; const char ** baseNames = NULL; rpmTagType bnt, dnt; const char ** fileMD5List = NULL; const char ** fileOwnerList = NULL; const char ** fileGroupList = NULL; const char ** fileLinktoList = NULL; rpmTagType m5t, fot, fgt, ltt; const char * fileStatesList; int_32 * fileFlagsList, * fileMTimeList, * fileSizeList; int_32 * fileUIDList = NULL; int_32 * fileGIDList = NULL; int_32 * fileInodeList = NULL; uint_16 * fileModeList; uint_16 * fileRdevList; int_32 * dirIndexes; int rc = 0; /* XXX FIXME: need real return code */ int i; te = t = xmalloc(tb); *te = '\0'; if (queryFormat == NULL && queryFlags == QUERY_FOR_DEFAULT) { queryFormat = "%{name}-%{version}-%{release}\n"; } if (queryFormat) { const char * str = queryHeader(h, queryFormat); /*@-branchstate@*/ if (str) { size_t tx = (te - t); sb = strlen(str); if (sb) { tb += sb; t = xrealloc(t, tb); te = t + tx; } /*@-usereleased@*/ te = stpcpy(te, str); /*@=usereleased@*/ str = _free(str); flushBuffer(&t, &te, 1); } /*@=branchstate@*/ } if (!(queryFlags & QUERY_FOR_LIST)) goto exit; if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &count)) { te = stpcpy(te, _("(contains no files)")); goto exit; } if (!hge(h, RPMTAG_FILESTATES, &type, (void **) &fileStatesList, NULL)) fileStatesList = NULL; if (!hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL)) dirNames = NULL; if (!hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL)) dirIndexes = NULL; if (!hge(h, RPMTAG_FILEFLAGS, &type, (void **) &fileFlagsList, NULL)) fileFlagsList = NULL; if (!hge(h, RPMTAG_FILESIZES, &type, (void **) &fileSizeList, NULL)) fileSizeList = NULL; if (!hge(h, RPMTAG_FILEMODES, &type, (void **) &fileModeList, NULL)) fileModeList = NULL; if (!hge(h, RPMTAG_FILEMTIMES, &type, (void **) &fileMTimeList, NULL)) fileMTimeList = NULL; if (!hge(h, RPMTAG_FILERDEVS, &type, (void **) &fileRdevList, NULL)) fileRdevList = NULL; if (!hge(h, RPMTAG_FILEINODES, &type, (void **) &fileInodeList, NULL)) fileInodeList = NULL; if (!hge(h, RPMTAG_FILELINKTOS, <t, (void **) &fileLinktoList, NULL)) fileLinktoList = NULL; if (!hge(h, RPMTAG_FILEMD5S, &m5t, (void **) &fileMD5List, NULL)) fileMD5List = NULL; if (!hge(h, RPMTAG_FILEUIDS, &type, (void **) &fileUIDList, NULL)) fileUIDList = NULL; if (!hge(h, RPMTAG_FILEGIDS, &type, (void **) &fileGIDList, NULL)) fileGIDList = NULL; if (!hge(h, RPMTAG_FILEUSERNAME, &fot, (void **) &fileOwnerList, NULL)) fileOwnerList = NULL; if (!hge(h, RPMTAG_FILEGROUPNAME, &fgt, (void **) &fileGroupList, NULL)) fileGroupList = NULL; for (i = 0; i < count; i++) { /* If querying only docs, skip non-doc files. */ if ((queryFlags & QUERY_FOR_DOCS) && !(fileFlagsList[i] & RPMFILE_DOC)) continue; /* If querying only configs, skip non-config files. */ if ((queryFlags & QUERY_FOR_CONFIG) && !(fileFlagsList[i] & RPMFILE_CONFIG)) continue; /* If not querying %ghost, skip ghost files. */ if (!(qva->qva_fflags & RPMFILE_GHOST) && (fileFlagsList[i] & RPMFILE_GHOST)) continue; /*@-internalglobs@*/ /* FIX: shrug */ if (!rpmIsVerbose() && prefix) te = stpcpy(te, prefix); /*@=internalglobs@*/ if (queryFlags & QUERY_FOR_STATE) { if (fileStatesList) { rpmfileState fstate = fileStatesList[i]; switch (fstate) { case RPMFILE_STATE_NORMAL: te = stpcpy(te, _("normal ")); /*@switchbreak@*/ break; case RPMFILE_STATE_REPLACED: te = stpcpy(te, _("replaced ")); /*@switchbreak@*/ break; case RPMFILE_STATE_NOTINSTALLED: te = stpcpy(te, _("not installed ")); /*@switchbreak@*/ break; case RPMFILE_STATE_NETSHARED: te = stpcpy(te, _("net shared ")); /*@switchbreak@*/ break; default: sprintf(te, _("(unknown %3d) "), (int)fileStatesList[i]); te += strlen(te); /*@switchbreak@*/ break; } } else { te = stpcpy(te, _("(no state) ")); } } if (queryFlags & QUERY_FOR_DUMPFILES) { sprintf(te, "%s%s %d %d %s 0%o ", dirNames[dirIndexes[i]], baseNames[i], fileSizeList[i], fileMTimeList[i], fileMD5List[i], (unsigned) fileModeList[i]); te += strlen(te); if (fileOwnerList && fileGroupList) { sprintf(te, "%s %s", fileOwnerList[i], fileGroupList[i]); te += strlen(te); } else if (fileUIDList && fileGIDList) { sprintf(te, "%d %d", fileUIDList[i], fileGIDList[i]); te += strlen(te); } else { rpmError(RPMERR_INTERNAL, _("package has neither file owner or id lists\n")); } sprintf(te, " %s %s %u ", fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0", fileFlagsList[i] & RPMFILE_DOC ? "1" : "0", (unsigned) fileRdevList[i]); te += strlen(te); if (strlen(fileLinktoList[i])) sprintf(te, "%s", fileLinktoList[i]); else sprintf(te, "X"); te += strlen(te); } else /*@-internalglobs@*/ /* FIX: shrug */ if (!rpmIsVerbose()) { te = stpcpy(te, dirNames[dirIndexes[i]]); te = stpcpy(te, baseNames[i]); } /*@=internalglobs@*/ else { char * filespec; int nlink; size_t fileSize; filespec = xmalloc(strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1); strcpy(filespec, dirNames[dirIndexes[i]]); strcat(filespec, baseNames[i]); fileSize = fileSizeList[i]; nlink = countLinks(fileRdevList, fileInodeList, count, i); if (S_ISDIR(fileModeList[i])) { nlink++; fileSize = 0; } if (fileOwnerList && fileGroupList) { printFileInfo(te, filespec, fileSize, fileModeList[i], fileMTimeList[i], fileRdevList[i], nlink, fileOwnerList[i], fileGroupList[i], -1, -1, fileLinktoList[i]); te += strlen(te); } else if (fileUIDList && fileGIDList) { printFileInfo(te, filespec, fileSize, fileModeList[i], fileMTimeList[i], fileRdevList[i], nlink, NULL, NULL, fileUIDList[i], fileGIDList[i], fileLinktoList[i]); te += strlen(te); } else { rpmError(RPMERR_INTERNAL, _("package has neither file owner or id lists\n")); } filespec = _free(filespec); } flushBuffer(&t, &te, 0); } rc = 0; exit: flushBuffer(&t, &te, 0); t = _free(t); dirNames = hfd(dirNames, dnt); baseNames = hfd(baseNames, bnt); fileLinktoList = hfd(fileLinktoList, ltt); fileMD5List = hfd(fileMD5List, m5t); fileOwnerList = hfd(fileOwnerList, fot); fileGroupList = hfd(fileGroupList, fgt); return rc; } /** */ static void printNewSpecfile(Spec spec) /*@globals fileSystem @*/ /*@modifies spec->sl->sl_lines[], fileSystem @*/ { Header h; speclines sl = spec->sl; spectags st = spec->st; const char * msgstr = NULL; int i, j; if (sl == NULL || st == NULL) return; /*@-branchstate@*/ for (i = 0; i < st->st_ntags; i++) { spectag t = st->st_t + i; const char * tn = tagName(t->t_tag); const char * errstr; char fmt[1024]; fmt[0] = '\0'; if (t->t_msgid == NULL) h = spec->packages->header; else { Package pkg; char *fe; strcpy(fmt, t->t_msgid); for (fe = fmt; *fe && *fe != '('; fe++) {} ; if (*fe == '(') *fe = '\0'; h = NULL; for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) { const char *pkgname; h = pkg->header; (void) headerNVR(h, &pkgname, NULL, NULL); if (!strcmp(pkgname, fmt)) /*@innerbreak@*/ break; } if (pkg == NULL || h == NULL) h = spec->packages->header; } if (h == NULL) continue; fmt[0] = '\0'; (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}"); msgstr = _free(msgstr); /* XXX this should use queryHeader(), but prints out tn as well. */ msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr); if (msgstr == NULL) { rpmError(RPMERR_QFMT, _("can't query %s: %s\n"), tn, errstr); return; } switch(t->t_tag) { case RPMTAG_SUMMARY: case RPMTAG_GROUP: /*@-unqualifiedtrans@*/ sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]); /*@=unqualifiedtrans@*/ if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) continue; { char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr)); (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr); sl->sl_lines[t->t_startx] = buf; } /*@switchbreak@*/ break; case RPMTAG_DESCRIPTION: for (j = 1; j < t->t_nlines; j++) { if (*sl->sl_lines[t->t_startx + j] == '%') /*@innercontinue@*/ continue; /*@-unqualifiedtrans@*/ sl->sl_lines[t->t_startx + j] = _free(sl->sl_lines[t->t_startx + j]); /*@=unqualifiedtrans@*/ } if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) { sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]); continue; } sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr); if (t->t_nlines > 2) sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n"); /*@switchbreak@*/ break; } } /*@=branchstate@*/ msgstr = _free(msgstr); for (i = 0; i < sl->sl_nlines; i++) { const char * s = sl->sl_lines[i]; if (s == NULL) continue; printf("%s", s); if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n') printf("\n"); } } void rpmDisplayQueryTags(FILE * fp) { const struct headerTagTableEntry_s * t; int i; const struct headerSprintfExtension_s * ext = rpmHeaderFormats; for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) if (t->name) fprintf(fp, "%s\n", t->name + 7); while (ext->name != NULL) { if (ext->type == HEADER_EXT_MORE) { ext = ext->u.more; continue; } /* XXX don't print query tags twice. */ for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) { if (t->name == NULL) /* XXX programmer error. */ /*@innercontinue@*/ continue; if (!strcmp(t->name, ext->name)) /*@innerbreak@*/ break; } if (i >= rpmTagTableSize && ext->type == HEADER_EXT_TAG) fprintf(fp, "%s\n", ext->name + 7); ext++; } } int showMatches(QVA_t qva, rpmdbMatchIterator mi, QVF_t showPackage) { Header h; int ec = 0; while ((h = rpmdbNextIterator(mi)) != NULL) { int rc; /*@-nullpass@*/ if ((rc = showPackage(qva, rpmdbGetIteratorRpmDB(mi), h)) != 0) ec = rc; if (qva->qva_source == RPMQV_DBOFFSET) break; /*@=nullpass@*/ } mi = rpmdbFreeIterator(mi); return ec; } /** * Convert hex to binary nibble. * @param c hex character * @return binary nibble */ static inline unsigned char nibble(char c) /*@*/ { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'A' && c <= 'F') return (c - 'A') + 10; if (c >= 'a' && c <= 'f') return (c - 'a') + 10; return 0; } /*@-redecl@*/ /** * @todo Eliminate linkage loop into librpmbuild.a */ int (*parseSpecVec) (Spec *specp, const char *specFile, const char *rootdir, const char *buildRoot, int recursing, const char *passPhrase, char *cookie, int anyarch, int force, int preprocess) = NULL; /** * @todo Eliminate linkage loop into librpmbuild.a */ /*@null@*/ Spec (*freeSpecVec) (Spec spec) = NULL; /*@=redecl@*/ int rpmQueryVerify(QVA_t qva, rpmQVSources source, const char * arg, rpmdb rpmdb, QVF_t showPackage) { rpmdbMatchIterator mi = NULL; Header h; int rc; int isSource; int retcode = 0; const char ** av = NULL; char * end = NULL; const char * s; int i; switch (source) { case RPMQV_RPM: if (rpmExpandNumeric("%{!?_disable_glob_query:%{?_enable_glob_query:1}}")) { int ac = 0; const char * fileURL = NULL; rpmRC rpmrc; rc = rpmGlob(arg, &ac, &av); if (rc) return 1; restart: for (i = 0; i < ac; i++) { FD_t fd; fileURL = _free(fileURL); fileURL = av[i]; av[i] = NULL; /* Try to read the header from a package file. */ fd = Fopen(fileURL, "r.ufdio"); if (fd == NULL || Ferror(fd)) { rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL, Fstrerror(fd)); if (fd) (void) Fclose(fd); retcode = 1; /*@loopbreak@*/ break; } /*@-mustmod@*/ /* LCL: segfault. */ rpmrc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL); /*@=mustmod@*/ (void) Fclose(fd); if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADMAGIC)) { rpmError(RPMERR_QUERY, _("query of %s failed\n"), fileURL); retcode = 1; /*@loopbreak@*/ break; } if (rpmrc == RPMRC_OK && h == NULL) { rpmError(RPMERR_QUERY, _("old format source packages cannot be queried\n")); retcode = 1; /*@loopbreak@*/ break; } /* Query a package file. */ if (rpmrc == RPMRC_OK) { retcode = showPackage(qva, rpmdb, h); h = headerFree(h); continue; } /* Try to read a package manifest. */ fd = Fopen(fileURL, "r.fpio"); if (fd == NULL || Ferror(fd)) { rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL, Fstrerror(fd)); if (fd) (void) Fclose(fd); retcode = 1; /*@loopbreak@*/ break; } /* Read list of packages from manifest. */ retcode = rpmReadPackageManifest(fd, &ac, &av); if (retcode) { rpmError(RPMERR_MANIFEST, _("%s: read manifest failed: %s\n"), fileURL, Fstrerror(fd)); retcode = 1; } (void) Fclose(fd); /* If successful, restart the query loop. */ if (retcode == 0) goto restart; /*@loopbreak@*/ break; } fileURL = _free(fileURL); if (av) { for (i = 0; i < ac; i++) av[i] = _free(av[i]); av = _free(av); } } else { const char * fileURL = arg; rpmRC rpmrc; /* Try to read the header from a package file. */ FD_t fd = Fopen(fileURL, "r.ufdio"); if (fd == NULL || Ferror(fd)) { rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL, Fstrerror(fd)); if (fd) (void) Fclose(fd); retcode = 1; break; } /*@-mustmod@*/ /* LCL: segfault. */ rpmrc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL); /*@=mustmod@*/ (void) Fclose(fd); if (rpmrc == RPMRC_BADMAGIC) { rpmError(RPMERR_QUERY, _("%s is not an RPM package\n"), fileURL); retcode = 1; break; } if (rpmrc != RPMRC_OK) { rpmError(RPMERR_QUERY, _("query of %s failed\n"), fileURL); retcode = 1; break; } if (h == NULL) { rpmError(RPMERR_QUERY, _("old format source packages cannot be queried\n")); retcode = 1; break; } /* Query a package file. */ if (rpmrc == RPMRC_OK) { retcode = showPackage(qva, rpmdb, h); h = headerFree(h); break; } } break; case RPMQV_SPECFILE: if (showPackage != showQueryPackage) return 1; /* XXX Eliminate linkage dependency loop */ if (parseSpecVec == NULL || freeSpecVec == NULL) return 1; { Spec spec = NULL; Package pkg; char * buildRoot = NULL; int recursing = 0; char * passPhrase = ""; char *cookie = NULL; int anyarch = 1; int force = 1; int preprocess = 0; rc = parseSpecVec(&spec, arg, "/", buildRoot, recursing, passPhrase, cookie, anyarch, force, preprocess); if (rc || spec == NULL) { rpmError(RPMERR_QUERY, _("query of specfile %s failed, can't parse\n"), arg); spec = freeSpecVec(spec); retcode = 1; break; } if (specedit) { printNewSpecfile(spec); spec = freeSpecVec(spec); retcode = 0; break; } for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) (void) showPackage(qva, NULL, pkg->header); spec = freeSpecVec(spec); } break; case RPMQV_ALL: /* RPMDBI_PACKAGES */ mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, NULL, 0); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("no packages\n")); retcode = 1; } else { for (av = (const char **) arg; av && *av; av++) { if (!rpmdbSetIteratorRE(mi, RPMTAG_NAME, RPMMIRE_DEFAULT, *av)) continue; mi = rpmdbFreeIterator(mi); retcode = 1; /*@loopbreak@*/ break; } if (!retcode) retcode = showMatches(qva, mi, showPackage); } break; case RPMQV_GROUP: mi = rpmdbInitIterator(rpmdb, RPMTAG_GROUP, arg, 0); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("group %s does not contain any packages\n"), arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } break; case RPMQV_TRIGGEREDBY: mi = rpmdbInitIterator(rpmdb, RPMTAG_TRIGGERNAME, arg, 0); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("no package triggers %s\n"), arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } break; case RPMQV_PKGID: { unsigned char md5[16]; unsigned char * t; for (i = 0, s = arg; *s && isxdigit(*s); s++, i++) {}; if (i != 32) { rpmError(RPMERR_QUERYINFO, _("malformed %s: %s\n"), "pkgid", arg); return 1; } md5[0] = '\0'; for (i = 0, t = md5, s = arg; i < 16; i++, t++, s += 2) *t = (nibble(s[0]) << 4) | nibble(s[1]); mi = rpmdbInitIterator(rpmdb, RPMTAG_SIGMD5, md5, sizeof(md5)); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"), "pkgid", arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } } break; case RPMQV_HDRID: for (i = 0, s = arg; *s && isxdigit(*s); s++, i++) {}; if (i != 40) { rpmError(RPMERR_QUERYINFO, _("malformed %s: %s\n"), "hdrid", arg); return 1; } mi = rpmdbInitIterator(rpmdb, RPMTAG_SHA1HEADER, arg, 0); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"), "hdrid", arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } break; case RPMQV_TID: { int mybase = 10; const char * myarg = arg; unsigned iid; /* XXX should be in strtoul */ if (*myarg == '0') { myarg++; mybase = 8; if (*myarg == 'x') { myarg++; mybase = 16; } } iid = strtoul(myarg, &end, mybase); if ((*end) || (end == arg) || (iid == ULONG_MAX)) { rpmError(RPMERR_QUERY, _("malformed %s: %s\n"), "tid", arg); return 1; } mi = rpmdbInitIterator(rpmdb, RPMTAG_INSTALLTID, &iid, sizeof(iid)); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"), "tid", arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } } break; case RPMQV_WHATREQUIRES: mi = rpmdbInitIterator(rpmdb, RPMTAG_REQUIRENAME, arg, 0); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("no package requires %s\n"), arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } break; case RPMQV_WHATPROVIDES: mi = rpmdbInitIterator(rpmdb, RPMTAG_PROVIDENAME, arg, 0); if (mi == NULL) { if (arg[0] != '/') rpmError(RPMERR_QUERYINFO, _("no package provides %s\n"), arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } if (arg[0] != '/') break; /*@fallthrough@*/ case RPMQV_PATH: { char * fn; for (s = arg; *s != '\0'; s++) if (!(*s == '.' || *s == '/')) /*@loopbreak@*/ break; if (*s == '\0') { char fnbuf[PATH_MAX]; fn = /*@-unrecog@*/ realpath(arg, fnbuf) /*@=unrecog@*/; if (fn) fn = xstrdup(fn); else fn = xstrdup(arg); } else fn = xstrdup(arg); (void) rpmCleanPath(fn); mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, fn, 0); if (mi == NULL) { int myerrno = 0; if (access(fn, F_OK) != 0) myerrno = errno; switch (myerrno) { default: rpmError(RPMERR_QUERY, _("file %s: %s\n"), fn, strerror(myerrno)); break; case 0: switch (source) { case RPMQV_PATH: rpmError(RPMERR_QUERYINFO, _("file %s is not owned by any package\n"), fn); break; default: if (retcode) rpmError(RPMERR_QUERYINFO, _("no package provides %s\n"), fn); break; } break; } if (RPMQV_PATH == source) retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } fn = _free(fn); } break; case RPMQV_DBOFFSET: { int mybase = 10; const char * myarg = arg; unsigned recOffset; /* XXX should be in strtoul */ if (*myarg == '0') { myarg++; mybase = 8; if (*myarg == 'x') { myarg++; mybase = 16; } } recOffset = strtoul(myarg, &end, mybase); if ((*end) || (end == arg) || (recOffset == ULONG_MAX)) { rpmError(RPMERR_QUERYINFO, _("invalid package number: %s\n"), arg); return 1; } rpmMessage(RPMMESS_DEBUG, _("package record number: %u\n"), recOffset); mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset)); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("record %u could not be read\n"), recOffset); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } } break; case RPMQV_PACKAGE: /* XXX HACK to get rpmdbFindByLabel out of the API */ mi = rpmdbInitIterator(rpmdb, RPMDBI_LABEL, arg, 0); if (mi == NULL) { rpmError(RPMERR_QUERYINFO, _("package %s is not installed\n"), arg); retcode = 1; } else { retcode = showMatches(qva, mi, showPackage); } break; } return retcode; } int rpmQuery(QVA_t qva, rpmQVSources source, const char * arg) { rpmdb rpmdb = NULL; int rc; switch (source) { case RPMQV_RPM: case RPMQV_SPECFILE: break; default: if (rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644)) return 1; break; } rc = rpmQueryVerify(qva, source, arg, rpmdb, showQueryPackage); if (rpmdb != NULL) (void) rpmdbClose(rpmdb); return rc; }