rpm  4.5
query.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #ifndef PATH_MAX
9 /*@-incondefs@*/ /* FIX: long int? */
10 # define PATH_MAX 255
11 /*@=incondefs@*/
12 #endif
13 
14 #include <rpmcli.h>
15 
16 #include "rpmdb.h"
17 #include "rpmfi.h"
18 
19 #define _RPMGI_INTERNAL /* XXX for gi->flags */
20 #include "rpmgi.h"
21 #include "rpmts.h"
22 
23 #include "manifest.h"
24 #include "misc.h" /* XXX for rpmGlob() */
25 
26 #include "debug.h"
27 
28 /*@access rpmgi @*/
29 
32 static void printFileInfo(char * te, const char * name,
33  unsigned int size, unsigned short mode,
34  unsigned int mtime,
35  unsigned short rdev, unsigned int nlink,
36  const char * owner, const char * group,
37  const char * linkto)
38  /*@modifies *te @*/
39 {
40  char sizefield[15];
41  char ownerfield[8+1], groupfield[8+1];
42  char timefield[100];
43  time_t when = mtime; /* important if sizeof(int_32) ! sizeof(time_t) */
44  struct tm * tm;
45  static time_t now;
46  static struct tm nowtm;
47  const char * namefield = name;
48  char * perms = rpmPermsString(mode);
49 
50  /* On first call, grab snapshot of now */
51  if (now == 0) {
52  now = time(NULL);
53  tm = localtime(&now);
54 /*@-boundsread@*/
55  if (tm) nowtm = *tm; /* structure assignment */
56 /*@=boundsread@*/
57  }
58 
59  strncpy(ownerfield, owner, sizeof(ownerfield));
60  ownerfield[sizeof(ownerfield)-1] = '\0';
61 
62  strncpy(groupfield, group, sizeof(groupfield));
63  groupfield[sizeof(groupfield)-1] = '\0';
64 
65  /* this is normally right */
66  sprintf(sizefield, "%12u", size);
67 
68  /* this knows too much about dev_t */
69 
70  if (S_ISLNK(mode)) {
71  char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
72  sprintf(nf, "%s -> %s", name, linkto);
73  namefield = nf;
74  } else if (S_ISCHR(mode)) {
75  perms[0] = 'c';
76  sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
77  ((unsigned)rdev & 0xff));
78  } else if (S_ISBLK(mode)) {
79  perms[0] = 'b';
80  sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
81  ((unsigned)rdev & 0xff));
82  }
83 
84  /* Convert file mtime to display format */
85  tm = localtime(&when);
86  timefield[0] = '\0';
87  if (tm != NULL)
88  { const char *fmt;
89  if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
90  now < when - 60L * 60L) /* In the future. */
91  {
92  /* The file is fairly old or in the future.
93  * POSIX says the cutoff is 6 months old;
94  * approximate this by 6*30 days.
95  * Allow a 1 hour slop factor for what is considered "the future",
96  * to allow for NFS server/client clock disagreement.
97  * Show the year instead of the time of day.
98  */
99  fmt = "%b %e %Y";
100  } else {
101  fmt = "%b %e %H:%M";
102  }
103  (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
104  }
105 
106  sprintf(te, "%s %4d %-7s %-8s %10s %s %s", perms,
107  (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
108  perms = _free(perms);
109 }
110 
113 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
114  /*@*/
115 {
116  const char * errstr = "(unkown error)";
117  const char * str;
118 
119 /*@-modobserver@*/
120  str = headerSprintf(h, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
121 /*@=modobserver@*/
122  if (str == NULL)
123  rpmError(RPMERR_QFMT, _("incorrect format: %s\n"), errstr);
124  return str;
125 }
126 
129 static void flushBuffer(char ** tp, char ** tep, int nonewline)
130  /*@modifies *tp, **tp, *tep, **tep @*/
131 {
132  char *t, *te;
133 
134  t = *tp;
135  te = *tep;
136  if (te > t) {
137  if (!nonewline) {
138  *te++ = '\n';
139  *te = '\0';
140  }
141  rpmMessage(RPMMESS_NORMAL, "%s", t);
142  te = t;
143  *t = '\0';
144  }
145  *tp = t;
146  *tep = te;
147 }
148 
150 {
151  int scareMem = 0;
152  rpmfi fi = NULL;
153  size_t tb = 2 * BUFSIZ;
154  size_t sb;
155  char * t, * te;
156  char * prefix = NULL;
157  int rc = 0; /* XXX FIXME: need real return code */
158  int i;
159 
160  te = t = xmalloc(tb);
161 /*@-boundswrite@*/
162  *te = '\0';
163 /*@=boundswrite@*/
164 
165  if (qva->qva_queryFormat != NULL) {
166  const char * str = queryHeader(h, qva->qva_queryFormat);
167  /*@-branchstate@*/
168  if (str) {
169  size_t tx = (te - t);
170 
171  sb = strlen(str);
172  if (sb) {
173  tb += sb;
174  t = xrealloc(t, tb);
175  te = t + tx;
176  }
177 /*@-boundswrite@*/
178  /*@-usereleased@*/
179  te = stpcpy(te, str);
180  /*@=usereleased@*/
181 /*@=boundswrite@*/
182  str = _free(str);
183  flushBuffer(&t, &te, 1);
184  }
185  /*@=branchstate@*/
186  }
187 
188  if (!(qva->qva_flags & QUERY_FOR_LIST))
189  goto exit;
190 
191  fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
192  if (rpmfiFC(fi) <= 0) {
193 /*@-boundswrite@*/
194  te = stpcpy(te, _("(contains no files)"));
195 /*@=boundswrite@*/
196  goto exit;
197  }
198 
199  fi = rpmfiInit(fi, 0);
200  if (fi != NULL)
201  while ((i = rpmfiNext(fi)) >= 0) {
202  rpmfileAttrs fflags;
203  unsigned short fmode;
204  unsigned short frdev;
205  unsigned int fmtime;
206  rpmfileState fstate;
207  size_t fsize;
208  const char * fn;
209  const char * fdigest;
210  const char * fuser;
211  const char * fgroup;
212  const char * flink;
213  int_32 fnlink;
214 
215  fflags = rpmfiFFlags(fi);
216  fmode = rpmfiFMode(fi);
217  frdev = rpmfiFRdev(fi);
218  fmtime = rpmfiFMtime(fi);
219  fstate = rpmfiFState(fi);
220  fsize = rpmfiFSize(fi);
221  fn = rpmfiFN(fi);
222 /*@-bounds@*/
223  { static char hex[] = "0123456789abcdef";
224  int dalgo = 0;
225  size_t dlen = 0;
226  const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
227  char * p;
228  int j;
229  fdigest = p = xcalloc(1, ((2 * dlen) + 1));
230  for (j = 0; j < dlen; j++) {
231  unsigned k = *digest++;
232  *p++ = hex[ (k >> 4) & 0xf ];
233  *p++ = hex[ (k ) & 0xf ];
234  }
235  *p = '\0';
236  }
237 /*@=bounds@*/
238  fuser = rpmfiFUser(fi);
239  fgroup = rpmfiFGroup(fi);
240  flink = rpmfiFLink(fi);
241  fnlink = rpmfiFNlink(fi);
242 assert(fn != NULL);
243 assert(fdigest != NULL);
244 
245  /* If querying only docs, skip non-doc files. */
246  if ((qva->qva_flags & QUERY_FOR_DOCS) && !(fflags & RPMFILE_DOC))
247  continue;
248 
249  /* If querying only configs, skip non-config files. */
250  if ((qva->qva_flags & QUERY_FOR_CONFIG) && !(fflags & RPMFILE_CONFIG))
251  continue;
252 
253  /* If not querying %config, skip config files. */
254  if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG))
255  continue;
256 
257  /* If not querying %doc, skip doc files. */
258  if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC))
259  continue;
260 
261  /* If not querying %ghost, skip ghost files. */
262  if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
263  continue;
264 
265  /* Insure space for header derived data */
266  sb = 0;
267  if (fn) sb += strlen(fn);
268  if (fdigest) sb += strlen(fdigest);
269  if (fuser) sb += strlen(fuser);
270  if (fgroup) sb += strlen(fgroup);
271  if (flink) sb += strlen(flink);
272 /*@-branchstate@*/
273  if ((sb + BUFSIZ) > tb) {
274  size_t tx = (te - t);
275  tb += sb + BUFSIZ;
276  t = xrealloc(t, tb);
277  te = t + tx;
278  }
279 /*@=branchstate@*/
280 
281 /*@-boundswrite@*/
282  if (!rpmIsVerbose() && prefix)
283  te = stpcpy(te, prefix);
284 
285  if (qva->qva_flags & QUERY_FOR_STATE) {
286  switch (fstate) {
288  te = stpcpy(te, _("normal "));
289  /*@switchbreak@*/ break;
291  te = stpcpy(te, _("replaced "));
292  /*@switchbreak@*/ break;
294  te = stpcpy(te, _("not installed "));
295  /*@switchbreak@*/ break;
297  te = stpcpy(te, _("net shared "));
298  /*@switchbreak@*/ break;
300  te = stpcpy(te, _("wrong color "));
301  /*@switchbreak@*/ break;
303  te = stpcpy(te, _("(no state) "));
304  /*@switchbreak@*/ break;
305  default:
306  sprintf(te, _("(unknown %3d) "), fstate);
307  te += strlen(te);
308  /*@switchbreak@*/ break;
309  }
310  }
311 /*@=boundswrite@*/
312 
313  if (qva->qva_flags & QUERY_FOR_DUMPFILES) {
314  sprintf(te, "%s %d %d %s 0%o ",
315  fn, (int)fsize, fmtime, fdigest, fmode);
316  te += strlen(te);
317 
318  if (fuser && fgroup) {
319 /*@-nullpass@*/
320  sprintf(te, "%s %s", fuser, fgroup);
321 /*@=nullpass@*/
322  te += strlen(te);
323  } else {
325  _("package has not file owner/group lists\n"));
326  }
327 
328  sprintf(te, " %s %s %u ",
329  fflags & RPMFILE_CONFIG ? "1" : "0",
330  fflags & RPMFILE_DOC ? "1" : "0",
331  frdev);
332  te += strlen(te);
333 
334  sprintf(te, "%s", (flink && *flink ? flink : "X"));
335  te += strlen(te);
336  } else
337  if (!rpmIsVerbose()) {
338 /*@-boundswrite@*/
339  te = stpcpy(te, fn);
340 /*@=boundswrite@*/
341  }
342  else {
343 
344  /* XXX Adjust directory link count and size for display output. */
345  if (S_ISDIR(fmode)) {
346  fnlink++;
347  fsize = 0;
348  }
349 
350  if (fuser && fgroup) {
351 /*@-nullpass@*/
352  printFileInfo(te, fn, fsize, fmode, fmtime, frdev, fnlink,
353  fuser, fgroup, flink);
354 /*@=nullpass@*/
355  te += strlen(te);
356  } else {
358  _("package has neither file owner or id lists\n"));
359  }
360  }
361  flushBuffer(&t, &te, 0);
362  fdigest = _free(fdigest);
363  }
364 
365  rc = 0;
366 
367 exit:
368  flushBuffer(&t, &te, 0);
369  t = _free(t);
370 
371  fi = rpmfiFree(fi);
372  return rc;
373 }
374 
375 void rpmDisplayQueryTags(FILE * fp)
376 {
377  const struct headerTagTableEntry_s * t;
378  int i;
379  const struct headerSprintfExtension_s * ext = rpmHeaderFormats;
380 
381  for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
382  if (t->name == NULL)
383  continue;
384  fprintf(fp, "%-20s", t->name + 7);
385  if (rpmIsVerbose()) {
386  /*@observer@*/
387  static const char * tagtypes[] = {
388  "", "char", "int8", "int16", "int32", "int64",
389  "string", "blob", "argv", "i18nstring", "asn1", "openpgp"
390  };
391  fprintf(fp, " %6d", t->val);
392  if (t->type > RPM_NULL_TYPE && t->type <= RPM_MAX_TYPE)
393  fprintf(fp, " %s", tagtypes[t->type]);
394  }
395  fprintf(fp, "\n");
396  }
397 
398  while (ext->name != NULL) {
399  if (ext->type == HEADER_EXT_MORE) {
400  ext = ext->u.more;
401  continue;
402  }
403  /* XXX don't print query tags twice. */
404  for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
405  if (t->name == NULL) /* XXX programmer error. */
406  /*@innercontinue@*/ continue;
407  if (!strcmp(t->name, ext->name))
408  /*@innerbreak@*/ break;
409  }
410  if (i >= rpmTagTableSize && ext->type == HEADER_EXT_TAG)
411  fprintf(fp, "%s\n", ext->name + 7);
412  ext++;
413  }
414 }
415 
416 static int rpmgiShowMatches(QVA_t qva, rpmts ts)
417  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
418  /*@modifies qva, rpmGlobalMacroContext, h_errno, internalState @*/
419 {
420  rpmgi gi = qva->qva_gi;
421  int ec = 0;
422 
423  while (rpmgiNext(gi) == RPMRC_OK) {
424  Header h;
425  int rc;
426 
427  h = rpmgiHeader(gi);
428  if (h == NULL) /* XXX perhaps stricter break instead? */
429  continue;
430  if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
431  ec = rc;
432  if (qva->qva_source == RPMQV_DBOFFSET)
433  break;
434  }
435  return ec;
436 }
437 
439 {
440  Header h;
441  int ec = 1;
442 
443  qva->qva_showFAIL = qva->qva_showOK = 0;
444  while ((h = rpmdbNextIterator(qva->qva_mi)) != NULL) {
445  ec = qva->qva_showPackage(qva, ts, h);
446  if (ec)
447  qva->qva_showFAIL++;
448  else
449  qva->qva_showOK++;
450  if (qva->qva_source == RPMQV_DBOFFSET)
451  break;
452  }
453  qva->qva_mi = rpmdbFreeIterator(qva->qva_mi);
454  return ec;
455 }
456 
462 static inline unsigned char nibble(char c)
463  /*@*/
464 {
465  if (c >= '0' && c <= '9')
466  return (c - '0');
467  if (c >= 'A' && c <= 'F')
468  return (c - 'A') + 10;
469  if (c >= 'a' && c <= 'f')
470  return (c - 'a') + 10;
471  return 0;
472 }
473 
474 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
475 {
476  int res = 0;
477  const char * s;
478  int i;
479  int provides_checked = 0;
480 
481  (void) rpmdbCheckSignals();
482 
483  if (qva->qva_showPackage == NULL)
484  return 1;
485 
486  /*@-branchstate@*/
487  switch (qva->qva_source) {
488  case RPMQV_RPM:
489  res = rpmgiShowMatches(qva, ts);
490  break;
491 
492  case RPMQV_ALL:
493  res = rpmgiShowMatches(qva, ts);
494  break;
495 
496  case RPMQV_HDLIST:
497  res = rpmgiShowMatches(qva, ts);
498  break;
499 
500  case RPMQV_FTSWALK:
501  res = rpmgiShowMatches(qva, ts);
502  break;
503 
504  case RPMQV_SPECSRPM:
505  case RPMQV_SPECFILE:
506  res = ((qva->qva_specQuery != NULL)
507  ? qva->qva_specQuery(ts, qva, arg) : 1);
508  break;
509 
510  case RPMQV_GROUP:
511  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
512  if (qva->qva_mi == NULL) {
514  _("group %s does not contain any packages\n"), arg);
515  res = 1;
516  } else
517  res = rpmcliShowMatches(qva, ts);
518  break;
519 
520  case RPMQV_TRIGGEREDBY:
521  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
522  if (qva->qva_mi == NULL) {
523  rpmError(RPMERR_QUERYINFO, _("no package triggers %s\n"), arg);
524  res = 1;
525  } else
526  res = rpmcliShowMatches(qva, ts);
527  break;
528 
529  case RPMQV_PKGID:
530  { unsigned char MD5[16];
531  unsigned char * t;
532 
533  for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
534  {};
535  if (i != 32) {
536  rpmError(RPMERR_QUERYINFO, _("malformed %s: %s\n"), "pkgid", arg);
537  return 1;
538  }
539 
540  MD5[0] = '\0';
541  for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
542  *t = (nibble(s[0]) << 4) | nibble(s[1]);
543 
544  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SIGMD5, MD5, sizeof(MD5));
545  if (qva->qva_mi == NULL) {
546  rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
547  "pkgid", arg);
548  res = 1;
549  } else
550  res = rpmcliShowMatches(qva, ts);
551  } break;
552 
553  case RPMQV_HDRID:
554  for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
555  {};
556  if (i != 40) {
557  rpmError(RPMERR_QUERYINFO, _("malformed %s: %s\n"), "hdrid", arg);
558  return 1;
559  }
560 
561  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
562  if (qva->qva_mi == NULL) {
563  rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
564  "hdrid", arg);
565  res = 1;
566  } else
567  res = rpmcliShowMatches(qva, ts);
568  break;
569 
570  case RPMQV_FILEID:
571  { unsigned char * t;
572  unsigned char * digest;
573  size_t dlen;
574 
575  /* Insure even no. of digits and at least 8 digits. */
576  for (dlen = 0, s = arg; *s && isxdigit(*s); s++, dlen++)
577  {};
578  if ((dlen & 1) || dlen < 8) {
579  rpmError(RPMERR_QUERY, _("malformed %s: %s\n"), "fileid", arg);
580  return 1;
581  }
582 
583  dlen /= 2;
584  digest = memset(alloca(dlen), 0, dlen);
585  for (t = digest, s = arg; *s; t++, s += 2)
586  *t = (nibble(s[0]) << 4) | nibble(s[1]);
587 
588  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEDIGESTS, digest, dlen);
589  if (qva->qva_mi == NULL) {
590  rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
591  "fileid", arg);
592  res = 1;
593  } else
594  res = rpmcliShowMatches(qva, ts);
595  } break;
596 
597  case RPMQV_TID:
598  { int mybase = 10;
599  const char * myarg = arg;
600  char * end = NULL;
601  unsigned iid;
602 
603  /* XXX should be in strtoul */
604  if (*myarg == '0') {
605  myarg++;
606  mybase = 8;
607  if (*myarg == 'x') {
608  myarg++;
609  mybase = 16;
610  }
611  }
612  iid = (unsigned) strtoul(myarg, &end, mybase);
613  if ((*end) || (end == arg) || (iid == UINT_MAX)) {
614  rpmError(RPMERR_QUERY, _("malformed %s: %s\n"), "tid", arg);
615  return 1;
616  }
617  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
618  if (qva->qva_mi == NULL) {
619  rpmError(RPMERR_QUERYINFO, _("no package matches %s: %s\n"),
620  "tid", arg);
621  res = 1;
622  } else
623  res = rpmcliShowMatches(qva, ts);
624  } break;
625 
626  case RPMQV_WHATNEEDS:
627  case RPMQV_WHATREQUIRES:
628  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
629  if (qva->qva_mi == NULL) {
630  rpmError(RPMERR_QUERYINFO, _("no package requires %s\n"), arg);
631  res = 1;
632  } else
633  res = rpmcliShowMatches(qva, ts);
634  break;
635 
636  case RPMQV_WHATPROVIDES:
637  if (arg[0] != '/') {
638  provides_checked = 1;
639  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
640  if (qva->qva_mi == NULL) {
641  rpmError(RPMERR_QUERYINFO, _("no package provides %s\n"), arg);
642  res = 1;
643  } else
644  res = rpmcliShowMatches(qva, ts);
645  break;
646  }
647  /*@fallthrough@*/
648  case RPMQV_PATH:
649  { char * fn;
650 
651  for (s = arg; *s != '\0'; s++)
652  if (!(*s == '.' || *s == '/'))
653  /*@loopbreak@*/ break;
654 
655  if (*s == '\0') {
656  char fnbuf[PATH_MAX];
657  fn = realpath(arg, fnbuf);
658  fn = xstrdup( (fn != NULL ? fn : arg) );
659  } else if (*arg != '/') {
660  const char *curDir = currentDirectory();
661  fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
662  curDir = _free(curDir);
663  } else
664  fn = xstrdup(arg);
665 assert(fn != NULL);
666  (void) rpmCleanPath(fn);
667 
668  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
669  if (qva->qva_mi == NULL && !provides_checked)
670  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, fn, 0);
671 
672  if (qva->qva_mi == NULL) {
673  struct stat sb;
674  if (Lstat(fn, &sb) != 0)
675  rpmError(RPMERR_QUERY, _("file %s: %s\n"), fn, strerror(errno));
676  else
678  _("file %s is not owned by any package\n"), fn);
679  res = 1;
680  } else
681  res = rpmcliShowMatches(qva, ts);
682 
683  fn = _free(fn);
684  } break;
685 
686  case RPMQV_DBOFFSET:
687  { int mybase = 10;
688  const char * myarg = arg;
689  char * end = NULL;
690  unsigned recOffset;
691 
692  /* XXX should be in strtoul */
693  if (*myarg == '0') {
694  myarg++;
695  mybase = 8;
696  if (*myarg == 'x') {
697  myarg++;
698  mybase = 16;
699  }
700  }
701  recOffset = (unsigned) strtoul(myarg, &end, mybase);
702  if ((*end) || (end == arg) || (recOffset == UINT_MAX)) {
703  rpmError(RPMERR_QUERYINFO, _("invalid package number: %s\n"), arg);
704  return 1;
705  }
706  rpmMessage(RPMMESS_DEBUG, D_("package record number: %u\n"), recOffset);
707  qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
708  if (qva->qva_mi == NULL) {
710  _("record %u could not be read\n"), recOffset);
711  res = 1;
712  } else
713  res = rpmcliShowMatches(qva, ts);
714  } break;
715 
716  case RPMQV_PACKAGE:
717  /* XXX HACK to get rpmdbFindByLabel out of the API */
718  qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
719  if (qva->qva_mi == NULL) {
720  rpmError(RPMERR_QUERYINFO, _("package %s is not installed\n"), arg);
721  res = 1;
722  } else {
723  res = rpmcliShowMatches(qva, ts);
724  /* detect foo.bogusarch empty iterations. */
725  if (qva->qva_showOK == 0 && qva->qva_showFAIL == 0) {
726  rpmError(RPMERR_QUERYINFO, _("package %s is not installed\n"), arg);
727  res = 1;
728  }
729  }
730  break;
731  }
732  /*@=branchstate@*/
733 
734  return res;
735 }
736 
737 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_t argv)
738 {
739  rpmRC rpmrc = RPMRC_NOTFOUND;
740  int ec = 0;
741 
742  switch (qva->qva_source) {
743  case RPMQV_ALL:
744  qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
745  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, RPMGI_NONE);
746 
747  if (qva->qva_gi != NULL && (qva->qva_gi->flags & RPMGI_TSADD)) /* Load the ts with headers. */
748  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
749  {};
750  if (rpmrc != RPMRC_NOTFOUND)
751  return 1; /* XXX should be no. of failures. */
752 
753  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
754  ec = rpmQueryVerify(qva, ts, (const char *) argv);
755  /*@=nullpass@*/
756  rpmtsEmpty(ts);
757  break;
758  case RPMQV_RPM:
759  qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
760  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, giFlags);
761 
762  if (qva->qva_gi != NULL && (qva->qva_gi->flags & RPMGI_TSADD)) /* Load the ts with headers. */
763  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
764  {};
765  if (rpmrc != RPMRC_NOTFOUND)
766  return 1; /* XXX should be no. of failures. */
767 
768  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
769  ec = rpmQueryVerify(qva, ts, NULL);
770  /*@=nullpass@*/
771  rpmtsEmpty(ts);
772  break;
773  case RPMQV_HDLIST:
774  qva->qva_gi = rpmgiNew(ts, RPMDBI_HDLIST, NULL, 0);
775  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, giFlags);
776 
777  if (qva->qva_gi != NULL && (qva->qva_gi->flags & RPMGI_TSADD)) /* Load the ts with headers. */
778  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
779  {};
780  if (rpmrc != RPMRC_NOTFOUND)
781  return 1; /* XXX should be no. of failures. */
782 
783  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
784  ec = rpmQueryVerify(qva, ts, NULL);
785  /*@=nullpass@*/
786  rpmtsEmpty(ts);
787  break;
788  case RPMQV_FTSWALK:
789  if (ftsOpts == 0)
791  qva->qva_gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
792  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, giFlags);
793 
794  if (qva->qva_gi != NULL && (qva->qva_gi->flags & RPMGI_TSADD)) /* Load the ts with headers. */
795  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
796  {};
797  if (rpmrc != RPMRC_NOTFOUND)
798  return 1; /* XXX should be no. of failures. */
799 
800  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
801  ec = rpmQueryVerify(qva, ts, NULL);
802  /*@=nullpass@*/
803  rpmtsEmpty(ts);
804  break;
805  default:
806  if (giFlags & RPMGI_TSADD) {
807  qva->qva_gi = rpmgiNew(ts, RPMDBI_LABEL, NULL, 0);
808  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts,
809  (giFlags | (RPMGI_NOGLOB )));
810  if (qva->qva_gi != NULL && (qva->qva_gi->flags & RPMGI_TSADD)) /* Load the ts with headers. */
811  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
812  {};
813  if (rpmrc != RPMRC_NOTFOUND)
814  return 1; /* XXX should be no. of failures. */
815  qva->qva_source = RPMQV_ALL;
816  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
817  ec = rpmQueryVerify(qva, ts, NULL);
818  /*@=nullpass@*/
819  rpmtsEmpty(ts);
820  } else {
821  qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
822  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts,
824  while (rpmgiNext(qva->qva_gi) == RPMRC_OK) {
825  const char * path;
826  path = rpmgiHdrPath(qva->qva_gi);
827 assert(path != NULL);
828  ec += rpmQueryVerify(qva, ts, path);
829  rpmtsEmpty(ts);
830  }
831  }
832  break;
833  }
834 
835  qva->qva_gi = rpmgiFree(qva->qva_gi);
836 
837  return ec;
838 }
839 
840 int rpmcliQuery(rpmts ts, QVA_t qva, const char ** argv)
841 {
842  rpmdepFlags depFlags = qva->depFlags, odepFlags;
843  rpmtransFlags transFlags = qva->transFlags, otransFlags;
844  rpmVSFlags vsflags, ovsflags;
845  int ec = 0;
846 
847  if (qva->qva_showPackage == NULL)
849 
850  /* If --queryformat unspecified, then set default now. */
851  if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) {
852  qva->qva_queryFormat = rpmExpand("%{?_query_all_fmt}\n", NULL);
853  if (!(qva->qva_queryFormat != NULL && *qva->qva_queryFormat != '\0')) {
855  qva->qva_queryFormat = xstrdup("%{name}-%{version}-%{release}\n");
856  }
857  }
858 
859  vsflags = rpmExpandNumeric("%{?_vsflags_query}");
860  if (qva->qva_flags & VERIFY_DIGEST)
861  vsflags |= _RPMVSF_NODIGESTS;
862  if (qva->qva_flags & VERIFY_SIGNATURE)
863  vsflags |= _RPMVSF_NOSIGNATURES;
864  if (qva->qva_flags & VERIFY_HDRCHK)
865  vsflags |= RPMVSF_NOHDRCHK;
866 
867  odepFlags = rpmtsSetDFlags(ts, depFlags);
868  otransFlags = rpmtsSetFlags(ts, transFlags);
869  ovsflags = rpmtsSetVSFlags(ts, vsflags);
870  ec = rpmcliArgIter(ts, qva, argv);
871  vsflags = rpmtsSetVSFlags(ts, ovsflags);
872  transFlags = rpmtsSetFlags(ts, otransFlags);
873  depFlags = rpmtsSetDFlags(ts, odepFlags);
874 
875  if (qva->qva_showPackage == showQueryPackage)
876  qva->qva_showPackage = NULL;
877 
878  return ec;
879 }