rpm-build/lib/query.c
Ivan Zakharyaschev 6be20da468 headerNVR() replaced by the new header{NVRD,Name{,Version}}() in trivial cases
These are the cases where even the release was not needed (so, the
disttag is not needed, too), or one case where the filename is
contructed (and it doesn't include the disttag).

Now grep -Ee 'headerNVR[^D]' will show the remaining non-trivial
cases, where adapting to disttags may be needed.
2019-02-26 23:16:13 +03:00

1024 lines
26 KiB
C

/** \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, &ltt, (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) headerName(h, &pkgname);
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;
}