3 * Display tag values from package metadata.
12 #include <rpm/rpmcli.h>
13 #include <rpm/header.h>
14 #include <rpm/rpmdb.h>
15 #include <rpm/rpmfi.h>
16 #include <rpm/rpmts.h>
17 #include <rpm/rpmlog.h>
18 #include <rpm/rpmfileutil.h> /* rpmCleanPath */
20 #include "lib/rpmgi.h"
21 #include "lib/manifest.h"
28 static void printFileInfo(const char * name,
29 rpm_loff_t size, unsigned short mode,
31 unsigned short rdev, unsigned int nlink,
32 const char * owner, const char * group,
36 char ownerfield[8+1], groupfield[8+1];
38 time_t when = mtime; /* important if sizeof(int32_t) ! sizeof(time_t) */
41 char * perms = rpmPermsString(mode);
44 /* On first call, grab snapshot of now */
48 rstrlcpy(ownerfield, owner, sizeof(ownerfield));
49 rstrlcpy(groupfield, group, sizeof(groupfield));
51 /* this is normally right */
52 snprintf(sizefield, sizeof(sizefield), "%20" PRIu64, size);
54 /* this knows too much about dev_t */
57 rasprintf(&link, "%s -> %s", name, linkto);
58 } else if (S_ISCHR(mode)) {
60 snprintf(sizefield, sizeof(sizefield), "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
61 ((unsigned)rdev & 0xff));
62 } else if (S_ISBLK(mode)) {
64 snprintf(sizefield, sizeof(sizefield), "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
65 ((unsigned)rdev & 0xff));
68 /* Convert file mtime to display format */
69 tm = localtime(&when);
73 if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
74 now < when - 60L * 60L) /* In the future. */
76 /* The file is fairly old or in the future.
77 * POSIX says the cutoff is 6 months old;
78 * approximate this by 6*30 days.
79 * Allow a 1 hour slop factor for what is considered "the future",
80 * to allow for NFS server/client clock disagreement.
81 * Show the year instead of the time of day.
87 (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
90 rpmlog(RPMLOG_NOTICE, "%s %4d %-8s%-8s %10s %s %s\n", perms,
91 (int)nlink, ownerfield, groupfield, sizefield, timefield,
97 int showQueryPackage(QVA_t qva, rpmts ts, Header h)
100 rpmfiFlags fiflags = (RPMFI_NOHEADER | RPMFI_FLAGS_QUERY);
101 int rc = 0; /* XXX FIXME: need real return code */
103 if (qva->qva_queryFormat != NULL) {
105 char *str = headerFormat(h, qva->qva_queryFormat, &errstr);
108 rpmlog(RPMLOG_NOTICE, "%s", str);
111 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
115 if (!(qva->qva_flags & QUERY_FOR_LIST))
118 if (!(qva->qva_flags & QUERY_FOR_DUMPFILES))
119 fiflags |= RPMFI_NOFILEDIGESTS;
121 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, fiflags);
122 if (rpmfiFC(fi) <= 0) {
123 rpmlog(RPMLOG_NOTICE, _("(contains no files)\n"));
127 fi = rpmfiInit(fi, 0);
128 while (rpmfiNext(fi) >= 0) {
129 rpmfileAttrs fflags = rpmfiFFlags(fi);
130 rpm_mode_t fmode = rpmfiFMode(fi);
131 rpm_rdev_t frdev = rpmfiFRdev(fi);
132 rpm_time_t fmtime = rpmfiFMtime(fi);
133 rpmfileState fstate = rpmfiFState(fi);
134 rpm_loff_t fsize = rpmfiFSize(fi);
135 const char *fn = rpmfiFN(fi);
136 const char *fuser = rpmfiFUser(fi);
137 const char *fgroup = rpmfiFGroup(fi);
138 const char *flink = rpmfiFLink(fi);
141 /* If querying only docs, skip non-doc files. */
142 if ((qva->qva_flags & QUERY_FOR_DOCS) && !(fflags & RPMFILE_DOC))
145 /* If querying only configs, skip non-config files. */
146 if ((qva->qva_flags & QUERY_FOR_CONFIG) && !(fflags & RPMFILE_CONFIG))
149 /* If querying only licenses, skip non-license files. */
150 if ((qva->qva_flags & QUERY_FOR_LICENSE) && !(fflags & RPMFILE_LICENSE))
153 /* If not querying %ghost, skip ghost files. */
154 if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
157 if (qva->qva_flags & QUERY_FOR_STATE) {
159 case RPMFILE_STATE_NORMAL:
160 rstrcat(&buf, _("normal "));
162 case RPMFILE_STATE_REPLACED:
163 rstrcat(&buf, _("replaced "));
165 case RPMFILE_STATE_NOTINSTALLED:
166 rstrcat(&buf, _("not installed "));
168 case RPMFILE_STATE_NETSHARED:
169 rstrcat(&buf, _("net shared "));
171 case RPMFILE_STATE_WRONGCOLOR:
172 rstrcat(&buf, _("wrong color "));
174 case RPMFILE_STATE_MISSING:
175 rstrcat(&buf, _("(no state) "));
178 rasprintf(&buf, _("(unknown %3d) "), fstate);
183 if (qva->qva_flags & QUERY_FOR_DUMPFILES) {
185 fdigest = rpmfiFDigestHex(fi, NULL);
186 rasprintf(&add, "%s %" PRIu64 " %d %s 0%o ",
187 fn, fsize, fmtime, fdigest ? fdigest : "", fmode);
192 if (fuser && fgroup) {
193 rasprintf(&add, "%s %s", fuser, fgroup);
198 _("package has not file owner/group lists\n"));
201 rasprintf(&add, " %s %s %u %s",
202 fflags & RPMFILE_CONFIG ? "1" : "0",
203 fflags & RPMFILE_DOC ? "1" : "0",
205 (flink && *flink ? flink : "X"));
206 rpmlog(RPMLOG_NOTICE, "%s%s\n", buf, add);
209 if (!rpmIsVerbose()) {
210 rpmlog(RPMLOG_NOTICE, "%s%s\n", buf ? buf : "", fn);
213 uint32_t fnlink = rpmfiFNlink(fi);
215 /* XXX Adjust directory link count and size for display output. */
216 if (S_ISDIR(fmode)) {
221 if (fuser && fgroup) {
223 rpmlog(RPMLOG_NOTICE, "%s", buf);
225 printFileInfo(fn, fsize, fmode, fmtime, frdev, fnlink,
226 fuser, fgroup, flink);
229 _("package has neither file owner or id lists\n"));
242 void rpmDisplayQueryTags(FILE * fp)
244 static const char * const tagTypeNames[] = {
245 "", "char", "int8", "int16", "int32", "int64",
246 "string", "blob", "argv", "i18nstring"
248 const char *tname, *sname;
249 rpmtd names = rpmtdNew();
250 (void) rpmTagGetNames(names, 1);
252 while ((tname = rpmtdNextString(names))) {
253 sname = tname + strlen("RPMTAG_");
254 if (rpmIsVerbose()) {
255 rpmTagVal tag = rpmTagGetValue(sname);
256 rpmTagType type = rpmTagGetTagType(tag);
257 fprintf(fp, "%-20s %6d", sname, tag);
258 if (type > RPM_NULL_TYPE && type <= RPM_MAX_TYPE)
259 fprintf(fp, " %s", tagTypeNames[type]);
261 fprintf(fp, "%s", sname);
265 rpmtdFreeData(names);
269 static int rpmgiShowMatches(QVA_t qva, rpmts ts, rpmgi gi)
274 while ((h = rpmgiNext(gi)) != NULL) {
278 if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
282 return ec + rpmgiNumErrors(gi);
285 static int rpmcliShowMatches(QVA_t qva, rpmts ts, rpmdbMatchIterator mi)
293 while ((h = rpmdbNextIterator(mi)) != NULL) {
296 if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
302 static rpmdbMatchIterator initQueryIterator(QVA_t qva, rpmts ts, const char * arg)
306 rpmdbMatchIterator mi = NULL;
308 (void) rpmdbCheckSignals();
310 if (qva->qva_showPackage == NULL)
313 switch (qva->qva_source) {
315 mi = rpmtsInitIterator(ts, RPMDBI_GROUP, arg, 0);
317 rpmlog(RPMLOG_NOTICE,
318 _("group %s does not contain any packages\n"), arg);
322 case RPMQV_TRIGGEREDBY:
323 mi = rpmtsInitIterator(ts, RPMDBI_TRIGGERNAME, arg, 0);
325 rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg);
330 { unsigned char MD5[16];
333 for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
336 rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "pkgid", arg);
341 for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
342 *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
344 mi = rpmtsInitIterator(ts, RPMDBI_SIGMD5, MD5, sizeof(MD5));
346 rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
352 for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
355 rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "hdrid", arg);
359 mi = rpmtsInitIterator(ts, RPMDBI_SHA1HEADER, arg, 0);
361 rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
368 rpm_tid_t iid = strtoul(arg, &end, 0);
370 if ((*end) || (end == arg) || (iid == UINT_MAX)) {
371 rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg);
374 mi = rpmtsInitIterator(ts, RPMDBI_INSTALLTID, &iid, sizeof(iid));
376 rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
381 case RPMQV_WHATREQUIRES:
382 mi = rpmtsInitIterator(ts, RPMDBI_REQUIRENAME, arg, 0);
384 rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg);
388 case RPMQV_WHATPROVIDES:
389 if (arg[0] != '/' && arg[0] != '.') {
390 mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, arg, 0);
392 rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg);
396 /* fallthrough on absolute and relative paths */
400 for (s = arg; *s != '\0'; s++)
401 if (!(*s == '.' || *s == '/'))
405 char fnbuf[PATH_MAX];
406 fn = realpath(arg, fnbuf);
407 fn = xstrdup( (fn != NULL ? fn : arg) );
408 } else if (*arg != '/') {
409 char *curDir = rpmGetCwd();
410 fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
414 (void) rpmCleanPath(fn);
416 /* XXX Add a switch to enable former BASENAMES behavior? */
417 mi = rpmtsInitIterator(ts, RPMDBI_INSTFILENAMES, fn, 0);
419 mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, fn, 0);
423 if (lstat(fn, &sb) != 0)
424 rpmlog(RPMLOG_ERR, _("file %s: %s\n"), fn, strerror(errno));
426 rpmlog(RPMLOG_NOTICE,
427 _("file %s is not owned by any package\n"), fn);
435 unsigned int recOffset = strtoul(arg, &end, 0);
437 if ((*end) || (end == arg) || (recOffset == UINT_MAX)) {
438 rpmlog(RPMLOG_ERR, _("invalid package number: %s\n"), arg);
441 rpmlog(RPMLOG_DEBUG, "package record number: %u\n", recOffset);
442 /* RPMDBI_PACKAGES */
443 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
445 rpmlog(RPMLOG_ERR, _("record %u could not be read\n"), recOffset);
452 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
453 while (rpmdbNextIterator(mi) != NULL) {
456 mi = rpmdbFreeIterator(mi);
458 rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
460 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
473 * Initialize db iterator with optional filters. By default patterns
474 * applied to package name, others can be specified with <tagname>=<pattern>
476 static rpmdbMatchIterator initFilterIterator(rpmts ts, ARGV_const_t argv)
478 rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
480 for (ARGV_const_t arg = argv; arg && *arg != NULL; arg++) {
481 rpmTagVal tag = RPMTAG_NAME;
482 char a[strlen(*arg)+1], *ae;
487 /* Parse for "tag=pattern" args. */
488 if ((ae = strchr(a, '=')) != NULL) {
490 tag = rpmTagGetValue(a);
491 if (tag == RPMTAG_NOT_FOUND) {
492 rpmlog(RPMLOG_ERR, _("unknown tag: \"%s\"\n"), a);
493 mi = rpmdbFreeIterator(mi);
499 rpmdbSetIteratorRE(mi, tag, RPMMIRE_DEFAULT, pat);
505 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv)
509 switch (qva->qva_source) {
511 rpmdbMatchIterator mi = initFilterIterator(ts, argv);
512 ec = rpmcliShowMatches(qva, ts, mi);
513 rpmdbFreeIterator(mi);
517 rpmgi gi = rpmgiNew(ts, giFlags, argv);
518 ec = rpmgiShowMatches(qva, ts, gi);
524 for (ARGV_const_t arg = argv; arg && *arg; arg++) {
525 ec += ((qva->qva_specQuery != NULL)
526 ? qva->qva_specQuery(ts, qva, *arg) : 1);
530 for (ARGV_const_t arg = argv; arg && *arg; arg++) {
531 rpmdbMatchIterator mi = initQueryIterator(qva, ts, *arg);
532 ec += rpmcliShowMatches(qva, ts, mi);
533 rpmdbFreeIterator(mi);
541 int rpmcliQuery(rpmts ts, QVA_t qva, char * const * argv)
543 rpmVSFlags vsflags, ovsflags;
546 if (qva->qva_showPackage == NULL)
547 qva->qva_showPackage = showQueryPackage;
549 /* If --queryformat unspecified, then set default now. */
550 if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) {
551 char * fmt = rpmExpand("%{?_query_all_fmt}\n", NULL);
552 if (fmt == NULL || strlen(fmt) <= 1) {
554 fmt = xstrdup("%{nvra}\n");
556 qva->qva_queryFormat = fmt;
559 vsflags = rpmExpandNumeric("%{?_vsflags_query}");
560 if (rpmcliQueryFlags & VERIFY_DIGEST)
561 vsflags |= _RPMVSF_NODIGESTS;
562 if (rpmcliQueryFlags & VERIFY_SIGNATURE)
563 vsflags |= _RPMVSF_NOSIGNATURES;
564 if (rpmcliQueryFlags & VERIFY_HDRCHK)
565 vsflags |= RPMVSF_NOHDRCHK;
567 ovsflags = rpmtsSetVSFlags(ts, vsflags);
568 ec = rpmcliArgIter(ts, qva, argv);
569 rpmtsSetVSFlags(ts, ovsflags);
571 if (qva->qva_showPackage == showQueryPackage)
572 qva->qva_showPackage = NULL;