3 * Display tag values from package metadata.
17 /*@access Header@*/ /* XXX compared with NULL */
18 /*@access rpmdbMatchIterator@*/ /* XXX compared with NULL */
21 * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
22 * @param this memory to free
25 static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
26 if (this) free((void *)this);
32 static void printFileInfo(char * te, const char * name,
33 unsigned int size, unsigned short mode,
35 unsigned short rdev, unsigned int nlink,
36 const char * owner, const char * group,
37 int uid, int gid, const char * linkto)
40 char ownerfield[9], groupfield[9];
41 char timefield[100] = "";
42 time_t when = mtime; /* important if sizeof(int_32) ! sizeof(time_t) */
45 static struct tm nowtm;
46 const char * namefield = name;
47 char * perms = rpmPermsString(mode);
49 /* On first call, grab snapshot of now */
53 nowtm = *tm; /* structure assignment */
57 strncpy(ownerfield, owner, 8);
59 sprintf(ownerfield, "%-8d", uid);
63 strncpy(groupfield, group, 8);
65 sprintf(groupfield, "%-8d", gid);
68 /* this is normally right */
69 sprintf(sizefield, "%12u", size);
71 /* this knows too much about dev_t */
74 char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
75 sprintf(nf, "%s -> %s", name, linkto);
77 } else if (S_ISCHR(mode)) {
79 sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
80 ((unsigned)rdev & 0xff));
81 } else if (S_ISBLK(mode)) {
83 sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
84 ((unsigned)rdev & 0xff));
87 /* Convert file mtime to display format */
88 tm = localtime(&when);
90 if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
91 now < when - 60L * 60L) /* In the future. */
93 /* The file is fairly old or in the future.
94 * POSIX says the cutoff is 6 months old;
95 * approximate this by 6*30 days.
96 * Allow a 1 hour slop factor for what is considered "the future",
97 * to allow for NFS server/client clock disagreement.
98 * Show the year instead of the time of day.
104 (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
107 sprintf(te, "%s %4d %-8s%-8s %10s %s %s", perms,
108 (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
109 perms = _free(perms);
114 static inline const char * queryHeader(Header h, const char * qfmt)
119 str = headerSprintf(h, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
121 rpmError(RPMERR_QFMT, _("incorrect format: %s\n"), errstr);
127 static int countLinks(int_16 * fileRdevList, int_32 * fileInodeList, int nfiles,
132 /* XXX rpm-3.3.12 has not RPMTAG_FILEINODES */
133 if (!(fileRdevList && fileInodeList && nfiles > 0))
135 while (nfiles-- > 0) {
136 if (fileRdevList[nfiles] != fileRdevList[xfile])
138 if (fileInodeList[nfiles] != fileInodeList[xfile])
145 int showQueryPackage(QVA_t *qva, /*@unused@*/rpmdb rpmdb, Header h)
149 int queryFlags = qva->qva_flags;
150 const char *queryFormat = qva->qva_queryFormat;
153 char * prefix = NULL;
154 const char ** dirNames = NULL;
155 const char ** baseNames = NULL;
156 const char ** fileMD5List = NULL;
157 const char ** fileOwnerList = NULL;
158 const char ** fileGroupList = NULL;
159 const char ** fileLinktoList = NULL;
160 const char * fileStatesList;
161 int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
162 int_32 * fileUIDList = NULL;
163 int_32 * fileGIDList = NULL;
164 int_32 * fileInodeList = NULL;
165 uint_16 * fileModeList;
166 uint_16 * fileRdevList;
168 int rc = 0; /* XXX FIXME: need real return code */
172 te = t = xmalloc(BUFSIZ);
175 if (!queryFormat && !queryFlags) {
176 const char * name, * version, * release;
177 headerNVR(h, &name, &version, &release);
178 te = stpcpy(te, name);
179 te = stpcpy( stpcpy(te, "-"), version);
180 te = stpcpy( stpcpy(te, "-"), release);
185 const char * str = queryHeader(h, queryFormat);
188 size_t tb = (te - t);
189 size_t sb = strlen(str);
191 if (sb >= (BUFSIZ - tb)) {
192 t = xrealloc(t, BUFSIZ+sb);
195 te = stpcpy(te, str);
200 if (!(queryFlags & QUERY_FOR_LIST))
203 if (!headerGetEntry(h, RPMTAG_BASENAMES, &type,
204 (void **) &baseNames, &count)) {
205 te = stpcpy(te, _("(contains no files)"));
208 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
209 (void **) &fileStatesList, &count)) {
210 fileStatesList = NULL;
212 headerGetEntry(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, NULL);
213 headerGetEntry(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
214 headerGetEntry(h, RPMTAG_FILEFLAGS, &type, (void **)&fileFlagsList, &count);
215 headerGetEntry(h, RPMTAG_FILESIZES, &type, (void **) &fileSizeList, &count);
216 headerGetEntry(h, RPMTAG_FILEMODES, &type, (void **) &fileModeList, &count);
217 headerGetEntry(h, RPMTAG_FILEMTIMES, &type, (void **)&fileMTimeList,&count);
218 headerGetEntry(h, RPMTAG_FILERDEVS, &type, (void **) &fileRdevList, &count);
219 headerGetEntry(h, RPMTAG_FILEINODES, &type, (void **)&fileInodeList,&count);
220 headerGetEntry(h, RPMTAG_FILELINKTOS,&type,(void **)&fileLinktoList,&count);
221 headerGetEntry(h, RPMTAG_FILEMD5S, &type, (void **) &fileMD5List, &count);
223 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
224 (void **) &fileUIDList, &count)) {
226 } else if (!headerGetEntry(h, RPMTAG_FILEGIDS, &type,
227 (void **) &fileGIDList, &count)) {
231 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
232 (void **) &fileOwnerList, &count)) {
233 fileOwnerList = NULL;
234 } else if (!headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
235 (void **) &fileGroupList, &count)) {
236 fileGroupList = NULL;
239 for (i = 0; i < count; i++) {
240 /* If querying only docs, skip non-doc files. */
241 if ((queryFlags & QUERY_FOR_DOCS)
242 && !(fileFlagsList[i] & RPMFILE_DOC))
244 /* If querying only configs, skip non-config files. */
245 if ((queryFlags & QUERY_FOR_CONFIG)
246 && !(fileFlagsList[i] & RPMFILE_CONFIG))
249 if (!rpmIsVerbose() && prefix)
250 te = stpcpy(te, prefix);
252 if (queryFlags & QUERY_FOR_STATE) {
253 if (fileStatesList) {
254 switch (fileStatesList[i]) {
255 case RPMFILE_STATE_NORMAL:
256 te = stpcpy(te, _("normal ")); break;
257 case RPMFILE_STATE_REPLACED:
258 te = stpcpy(te, _("replaced ")); break;
259 case RPMFILE_STATE_NOTINSTALLED:
260 te = stpcpy(te, _("not installed ")); break;
261 case RPMFILE_STATE_NETSHARED:
262 te = stpcpy(te, _("net shared ")); break;
264 sprintf(te, _("(unknown %3d) "), (int)fileStatesList[i]);
269 te = stpcpy(te, _("(no state) "));
273 if (queryFlags & QUERY_FOR_DUMPFILES) {
274 sprintf(te, "%s%s %d %d %s 0%o ",
275 dirNames[dirIndexes[i]], baseNames[i],
276 fileSizeList[i], fileMTimeList[i],
277 fileMD5List[i], fileModeList[i]);
280 if (fileOwnerList && fileGroupList) {
281 sprintf(te, "%s %s", fileOwnerList[i], fileGroupList[i]);
283 } else if (fileUIDList && fileGIDList) {
284 sprintf(te, "%d %d", fileUIDList[i], fileGIDList[i]);
287 rpmError(RPMERR_INTERNAL,
288 _("package has neither file owner or id lists\n"));
291 sprintf(te, " %s %s %u ",
292 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
293 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
294 (unsigned)fileRdevList[i]);
297 if (strlen(fileLinktoList[i]))
298 sprintf(te, "%s", fileLinktoList[i]);
302 } else if (!rpmIsVerbose()) {
303 te = stpcpy(te, dirNames[dirIndexes[i]]);
304 te = stpcpy(te, baseNames[i]);
309 filespec = xmalloc(strlen(dirNames[dirIndexes[i]])
310 + strlen(baseNames[i]) + 1);
311 strcpy(filespec, dirNames[dirIndexes[i]]);
312 strcat(filespec, baseNames[i]);
314 nlink = countLinks(fileRdevList, fileInodeList, count, i);
315 if (fileOwnerList && fileGroupList) {
316 printFileInfo(te, filespec, fileSizeList[i],
317 fileModeList[i], fileMTimeList[i],
318 fileRdevList[i], nlink,
320 fileGroupList[i], -1,
321 -1, fileLinktoList[i]);
323 } else if (fileUIDList && fileGIDList) {
324 printFileInfo(te, filespec, fileSizeList[i],
325 fileModeList[i], fileMTimeList[i],
326 fileRdevList[i], nlink,
327 NULL, NULL, fileUIDList[i],
332 rpmError(RPMERR_INTERNAL,
333 _("package has neither file owner or id lists\n"));
336 filespec = _free(filespec);
341 rpmMessage(RPMMESS_NORMAL, "%s", t);
355 rpmMessage(RPMMESS_NORMAL, "%s", t);
358 dirNames = headerFreeData(dirNames, -1);
359 baseNames = headerFreeData(baseNames, -1);
360 fileLinktoList = headerFreeData(fileLinktoList, -1);
361 fileMD5List = headerFreeData(fileMD5List, -1);
362 fileOwnerList = headerFreeData(fileOwnerList, -1);
363 fileGroupList = headerFreeData(fileGroupList, -1);
370 printNewSpecfile(Spec spec)
372 Header h = spec->packages->header;
373 struct speclines *sl = spec->sl;
374 struct spectags *st = spec->st;
375 const char * msgstr = NULL;
378 if (sl == NULL || st == NULL)
381 for (i = 0; i < st->st_ntags; i++) {
382 struct spectag * t = st->st_t + i;
383 const char * tn = tagName(t->t_tag);
388 (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}\n");
389 msgstr = _free(msgstr);
390 msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
391 if (msgstr == NULL) {
392 rpmError(RPMERR_QFMT, _("can't query %s: %s\n"), tn, errstr);
399 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
400 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
402 { char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
403 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
404 sl->sl_lines[t->t_startx] = buf;
407 case RPMTAG_DESCRIPTION:
408 for (j = 1; j < t->t_nlines; j++) {
409 sl->sl_lines[t->t_startx + j] =
410 _free(sl->sl_lines[t->t_startx + j]);
412 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
413 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
416 sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
418 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
422 msgstr = _free(msgstr);
424 for (i = 0; i < sl->sl_nlines; i++) {
425 if (sl->sl_lines[i] == NULL)
427 printf("%s", sl->sl_lines[i]);
431 void rpmDisplayQueryTags(FILE * f)
433 const struct headerTagTableEntry * t;
435 const struct headerSprintfExtension * ext = rpmHeaderFormats;
437 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
438 fprintf(f, "%s\n", t->name + 7);
442 if (ext->type == HEADER_EXT_MORE) {
446 /* XXX don't print query tags twice. */
447 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
448 if (!strcmp(t->name, ext->name))
451 if (i >= rpmTagTableSize && ext->type == HEADER_EXT_TAG)
452 fprintf(f, "%s\n", ext->name + 7);
457 int showMatches(QVA_t *qva, rpmdbMatchIterator mi, QVF_t showPackage)
462 while ((h = rpmdbNextIterator(mi)) != NULL) {
464 if ((rc = showPackage(qva, rpmdbGetIteratorRpmDB(mi), h)) != 0)
467 rpmdbFreeIterator(mi);
472 * @todo Eliminate linkage loop into librpmbuild.a
474 int (*parseSpecVec) (Spec *specp, const char *specFile, const char *rootdir,
475 const char *buildRoot, int inBuildArch, const char *passPhrase,
476 char *cookie, int anyarch, int force) = NULL;
478 * @todo Eliminate linkage loop into librpmbuild.a
480 void (*freeSpecVec) (Spec spec) = NULL;
482 int rpmQueryVerify(QVA_t *qva, rpmQVSources source, const char * arg,
483 rpmdb rpmdb, QVF_t showPackage)
485 rpmdbMatchIterator mi = NULL;
495 const char ** av = NULL;
496 const char * fileURL = NULL;
500 rc = rpmGlob(arg, &ac, &av);
504 for (i = 0; i < ac; i++) {
507 fileURL = _free(fileURL);
511 /* Try to read the header from a package file. */
512 fd = Fopen(fileURL, "r.ufdio");
513 if (fd == NULL || Ferror(fd)) {
514 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL,
521 rpmrc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
524 if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADMAGIC)) {
525 rpmError(RPMERR_QUERY, _("query of %s failed\n"), fileURL);
529 if (rpmrc == RPMRC_OK && h == NULL) {
530 rpmError(RPMERR_QUERY,
531 _("old format source packages cannot be queried\n"));
536 /* Query a package file. */
537 if (rpmrc == RPMRC_OK) {
538 retcode = showPackage(qva, rpmdb, h);
543 /* Try to read a package manifest. */
544 fd = Fopen(fileURL, "r.fpio");
546 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL,
553 /* Read list of packages from manifest. */
554 retcode = rpmReadPackageManifest(fd, &ac, &av);
556 rpmError(RPMERR_QUERY, _("%s: Fread failed: %s\n"), fileURL,
562 /* If successful, restart the query loop. */
569 fileURL = _free(fileURL);
571 for (i = 0; i < ac; i++)
572 av[i] = _free(av[i]);
578 if (showPackage != showQueryPackage)
581 /* XXX Eliminate linkage dependency loop */
582 if (parseSpecVec == NULL || freeSpecVec == NULL)
587 char * buildRoot = NULL;
589 char * passPhrase = "";
594 rc = parseSpecVec(&spec, arg, "/", buildRoot, inBuildArch, passPhrase,
595 cookie, anyarch, force);
596 if (rc || spec == NULL) {
598 rpmError(RPMERR_QUERY,
599 _("query of specfile %s failed, can't parse\n"), arg);
600 if (spec != NULL) freeSpecVec(spec);
606 printNewSpecfile(spec);
612 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
613 showPackage(qva, NULL, pkg->header);
619 /* RPMDBI_PACKAGES */
620 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, NULL, 0);
622 rpmError(RPMERR_QUERYINFO, _("no packages\n"));
625 retcode = showMatches(qva, mi, showPackage);
630 mi = rpmdbInitIterator(rpmdb, RPMTAG_GROUP, arg, 0);
632 rpmError(RPMERR_QUERYINFO,
633 _("group %s does not contain any packages\n"), arg);
636 retcode = showMatches(qva, mi, showPackage);
640 case RPMQV_TRIGGEREDBY:
641 mi = rpmdbInitIterator(rpmdb, RPMTAG_TRIGGERNAME, arg, 0);
643 rpmError(RPMERR_QUERYINFO, _("no package triggers %s\n"), arg);
646 retcode = showMatches(qva, mi, showPackage);
650 case RPMQV_WHATREQUIRES:
651 mi = rpmdbInitIterator(rpmdb, RPMTAG_REQUIRENAME, arg, 0);
653 rpmError(RPMERR_QUERYINFO, _("no package requires %s\n"), arg);
656 retcode = showMatches(qva, mi, showPackage);
660 case RPMQV_WHATPROVIDES:
662 mi = rpmdbInitIterator(rpmdb, RPMTAG_PROVIDENAME, arg, 0);
664 rpmError(RPMERR_QUERYINFO, _("no package provides %s\n"), arg);
667 retcode = showMatches(qva, mi, showPackage);
676 for (s = arg; *s; s++)
677 if (!(*s == '.' || *s == '/')) break;
680 char fnbuf[PATH_MAX];
681 fn = /*@-unrecog@*/ realpath(arg, fnbuf) /*@=unrecog@*/;
682 fn = xstrdup( (fn ? fn : arg) );
685 (void) rpmCleanPath(fn);
687 mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, fn, 0);
690 if (access(fn, F_OK) != 0)
694 rpmError(RPMERR_QUERY,
695 _("file %s: %s\n"), fn, strerror(myerrno));
698 rpmError(RPMERR_QUERYINFO,
699 _("file %s is not owned by any package\n"), fn);
704 retcode = showMatches(qva, mi, showPackage);
711 const char * myarg = arg;
714 /* XXX should be in strtoul */
723 recOffset = strtoul(myarg, &end, mybase);
724 if ((*end) || (end == arg) || (recOffset == ULONG_MAX)) {
725 rpmError(RPMERR_QUERY, _("invalid package number: %s\n"), arg);
728 rpmMessage(RPMMESS_DEBUG, _("package record number: %u\n"), recOffset);
729 /* RPMDBI_PACKAGES */
730 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
732 rpmError(RPMERR_QUERY,
733 _("record %d could not be read\n"), recOffset);
736 retcode = showMatches(qva, mi, showPackage);
741 /* XXX HACK to get rpmdbFindByLabel out of the API */
742 mi = rpmdbInitIterator(rpmdb, RPMDBI_LABEL, arg, 0);
744 rpmError(RPMERR_QUERYINFO, _("package %s is not installed\n"), arg);
747 retcode = showMatches(qva, mi, showPackage);
755 int rpmQuery(QVA_t *qva, rpmQVSources source, const char * arg)
765 if (rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644))
770 rc = rpmQueryVerify(qva, source, arg, rpmdb, showQueryPackage);