rpm  5.4.10
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 <rpmio.h>
15 #include <rpmiotypes.h>
16 #include <poptIO.h>
17 
18 #include <rpmtag.h>
19 #include "rpmdb.h"
20 
21 #include "rpmfi.h"
22 #define _RPMTS_INTERNAL /* XXX for ts->rdb */
23 #include "rpmts.h"
24 #include "rpmgi.h"
25 
26 #include "manifest.h"
27 #include "misc.h" /* XXX for currentDirectory() */
28 
29 #include <rpmcli.h>
30 
31 #include "debug.h"
32 
33 static int _jbj;
34 #define JBJDEBUG(_list) if (_jbj) fprintf _list
35 
36 /*@access rpmts @*/ /* XXX cast */
37 
38 #ifdef __cplusplus
39 
40 #define FF_ISSET(_fflags, _FLAG) ((_fflags) & (RPMFILE_##_FLAG))
41 
42 #define QVA_ISSET(_qvaflags, _FLAG) ((_qvaflags) & (QUERY_##_FLAG))
43 
44 #define VSF_ISSET(_vsflags, _FLAG) ((_vsflags) & (RPMVSF_##_FLAG))
45 #define VSF_SET(_vsflags, _FLAG) \
46  (*((unsigned *)&(_vsflags)) |= (RPMVSF_##_FLAG))
47 #define VSF_CLR(_vsflags, _FLAG) \
48  (*((unsigned *)&(_vsflags)) &= ~(RPMVSF_##_FLAG))
49 
50 #else /* __cplusplus */
51 
52 #define FF_ISSET(_fflags, _FLAG) ((_fflags) & (RPMFILE_##_FLAG))
53 
54 #define QVA_ISSET(_qvaflags, _FLAG) ((_qvaflags) & (QUERY_##_FLAG))
55 
56 #define VSF_ISSET(_vsflags, _FLAG) ((_vsflags) & (RPMVSF_##_FLAG))
57 #define VSF_SET(_vsflags, _FLAG) (_vsflags) |= (RPMVSF_##_FLAG)
58 #define VSF_CLR(_vsflags, _FLAG) (_vsflags) &= ~(RPMVSF_##_FLAG)
59 
60 #endif /* __cplusplus */
61 
64 static void printFileInfo(char * te, const char * name,
65  size_t size, unsigned short mode,
66  unsigned int mtime,
67  unsigned short rdev, unsigned int nlink,
68  const char * owner, const char * group,
69  const char * linkto)
70  /*@modifies *te @*/
71 {
72  char sizefield[15];
73 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
74  /* In verbose file listing output, give the owner and group fields
75  more width and at the same time reduce the nlink and size fields
76  more to typical sizes within OpenPKG. */
77  char ownerfield[13+1], groupfield[13+1];
78 #else
79  char ownerfield[8+1], groupfield[8+1];
80 #endif
81  char timefield[100];
82  time_t when = mtime; /* important if sizeof(rpmuint32_t) ! sizeof(time_t) */
83  struct tm * tm;
84  static time_t now;
85  static struct tm nowtm;
86  const char * namefield = name;
87  char * perms = rpmPermsString(mode);
88 
89  /* On first call, grab snapshot of now */
90  if (now == 0) {
91  now = time(NULL);
92  tm = localtime(&now);
93  if (tm) nowtm = *tm; /* structure assignment */
94  }
95 
96  strncpy(ownerfield, owner, sizeof(ownerfield));
97  ownerfield[sizeof(ownerfield)-1] = '\0';
98 
99  strncpy(groupfield, group, sizeof(groupfield));
100  groupfield[sizeof(groupfield)-1] = '\0';
101 
102  /* this is normally right */
103 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
104  /* In verbose file listing output, give the owner and group fields
105  more width and at the same time reduce the nlink and size fields
106  more to typical sizes within OpenPKG. */
107  sprintf(sizefield, "%8u", (unsigned)size);
108 #else
109  sprintf(sizefield, "%12u", (unsigned)size);
110 #endif
111 
112  /* this knows too much about dev_t */
113 
114  if (S_ISLNK(mode)) {
115  char *nf = (char *)
116  alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
117  sprintf(nf, "%s -> %s", name, linkto);
118  namefield = nf;
119  } else if (S_ISCHR(mode)) {
120  perms[0] = 'c';
121  sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
122  ((unsigned)rdev & 0xff));
123  } else if (S_ISBLK(mode)) {
124  perms[0] = 'b';
125  sprintf(sizefield, "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
126  ((unsigned)rdev & 0xff));
127  }
128 
129  /* Convert file mtime to display format */
130  tm = localtime(&when);
131  timefield[0] = '\0';
132  if (tm != NULL)
133  { const char *fmt;
134  if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
135  now < when - 60L * 60L) /* In the future. */
136  {
137  /* The file is fairly old or in the future.
138  * POSIX says the cutoff is 6 months old;
139  * approximate this by 6*30 days.
140  * Allow a 1 hour slop factor for what is considered "the future",
141  * to allow for NFS server/client clock disagreement.
142  * Show the year instead of the time of day.
143  */
144  fmt = "%b %e %Y";
145  } else {
146  fmt = "%b %e %H:%M";
147  }
148  (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
149  }
150 
151 #if defined(RPM_VENDOR_OPENPKG) /* adjust-verbose-listing */
152  /* In verbose file listing output, give the owner and group fields
153  more width and at the same time reduce the nlink and size fields
154  more to typical sizes within OpenPKG. */
155  sprintf(te, "%s %d %-13s %-13s %8s %s %s", perms,
156  (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
157 #else
158  sprintf(te, "%s %4d %-7s %-8s %10s %s %s", perms,
159  (int)nlink, ownerfield, groupfield, sizefield, timefield, namefield);
160 #endif
161  perms = _free(perms);
162 }
163 
166 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
167  /*@globals internalState @*/
168  /*@modifies h, internalState @*/
169 {
170  const char * errstr = "(unkown error)";
171  const char * str;
172 
173 /*@-modobserver@*/
174  str = headerSprintf(h, qfmt, NULL, rpmHeaderFormats, &errstr);
175 /*@=modobserver@*/
176  if (str == NULL)
177  rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
178  return str;
179 }
180 
183 static void flushBuffer(char ** tp, char ** tep, int nonewline)
184  /*@modifies *tp, **tp, *tep, **tep @*/
185 {
186  char *t, *te;
187 
188  t = *tp;
189  te = *tep;
190  if (te > t) {
191  if (!nonewline) {
192  *te++ = '\n';
193  *te = '\0';
194  }
195  rpmlog(RPMLOG_NOTICE, "%s", t);
196  te = t;
197  *t = '\0';
198  }
199  *tp = t;
200  *tep = te;
201 }
202 
204 {
205  int scareMem = 0;
206  rpmfi fi = NULL;
207  size_t tb = 2 * BUFSIZ;
208  size_t sb;
209  char * t, * te;
210  char * prefix = NULL;
211  int rc = 0; /* XXX FIXME: need real return code */
212  int i;
213 
214 JBJDEBUG((stderr, "--> %s(%p,%p,%p)\n", __FUNCTION__, qva, ts, h));
215  te = t = (char *) xmalloc(tb);
216  *te = '\0';
217 
218  if (qva->qva_queryFormat != NULL) {
219  const char * str;
220 /*@-type@*/ /* FIX rpmtsGetRDB()? */
221  (void) headerSetRpmdb(h, ts->rdb);
222 /*@=type@*/
223  str = queryHeader(h, qva->qva_queryFormat);
224  (void) headerSetRpmdb(h, NULL);
225  if (str) {
226  size_t tx = (te - t);
227 
228  sb = strlen(str);
229  if (sb) {
230  tb += sb;
231  t = (char *) xrealloc(t, tb);
232  te = t + tx;
233  }
234  /*@-usereleased@*/
235  te = stpcpy(te, str);
236  /*@=usereleased@*/
237  str = _free(str);
238  flushBuffer(&t, &te, 1);
239  }
240  }
241 
242  if (!QVA_ISSET(qva->qva_flags, FOR_LIST))
243  goto exit;
244 
245  fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
246  if (rpmfiFC(fi) <= 0) {
247  te = stpcpy(te, _("(contains no files)"));
248  goto exit;
249  }
250 
251  fi = rpmfiInit(fi, 0);
252  if (fi != NULL)
253  while ((i = rpmfiNext(fi)) >= 0) {
254  rpmfileAttrs fflags;
255  unsigned short fmode;
256  unsigned short frdev;
257  unsigned int fmtime;
258  rpmfileState fstate;
259  size_t fsize;
260  const char * fn;
261  const char * fdigest;
262  const char * fuser;
263  const char * fgroup;
264  const char * flink;
265  rpmuint32_t fnlink;
266 
267  fflags = (rpmfileAttrs) rpmfiFFlags(fi);
268  fmode = rpmfiFMode(fi);
269  frdev = rpmfiFRdev(fi);
270  fmtime = rpmfiFMtime(fi);
271  fstate = rpmfiFState(fi);
272  fsize = rpmfiFSize(fi);
273  fn = rpmfiFN(fi);
274  { static char hex[] = "0123456789abcdef";
275  int dalgo = 0;
276  size_t dlen = 0;
277  const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
278  char * p;
279  size_t j;
280  fdigest = p = (char *) xcalloc(1, ((2 * dlen) + 1));
281  for (j = 0; j < dlen; j++) {
282  unsigned k = *digest++;
283  *p++ = hex[ (k >> 4) & 0xf ];
284  *p++ = hex[ (k ) & 0xf ];
285  }
286  *p = '\0';
287  }
288  fuser = rpmfiFUser(fi);
289  fgroup = rpmfiFGroup(fi);
290  flink = rpmfiFLink(fi);
291  fnlink = rpmfiFNlink(fi);
292 assert(fn != NULL);
293 assert(fdigest != NULL);
294 
295  /* If querying only docs, skip non-doc files. */
296  if (QVA_ISSET(qva->qva_flags, FOR_DOCS) && !FF_ISSET(fflags, DOC))
297  continue;
298 
299  /* If querying only configs, skip non-config files. */
300  if (QVA_ISSET(qva->qva_flags, FOR_CONFIG) && !FF_ISSET(fflags, CONFIG))
301  continue;
302 
303  /* If not querying %config, skip config files. */
304  if (FF_ISSET(qva->qva_fflags, CONFIG) && FF_ISSET(fflags, CONFIG))
305  continue;
306 
307  /* If not querying %doc, skip doc files. */
308  if (FF_ISSET(qva->qva_fflags, DOC) && FF_ISSET(fflags, DOC))
309  continue;
310 
311  /* If not querying %ghost, skip ghost files. */
312  if (FF_ISSET(qva->qva_fflags, GHOST) && FF_ISSET(fflags, GHOST))
313  continue;
314 
315  /* Insure space for header derived data */
316  sb = 0;
317  if (fn) sb += strlen(fn);
318  if (fdigest) sb += strlen(fdigest);
319  if (fuser) sb += strlen(fuser);
320  if (fgroup) sb += strlen(fgroup);
321  if (flink) sb += strlen(flink);
322  if ((sb + BUFSIZ) > tb) {
323  size_t tx = (te - t);
324  tb += sb + BUFSIZ;
325  t = (char *) xrealloc(t, tb);
326  te = t + tx;
327  }
328 
329  if (!rpmIsVerbose() && prefix)
330  te = stpcpy(te, prefix);
331 
332  if (QVA_ISSET(qva->qva_flags, FOR_STATE)) {
333  switch (fstate) {
335  te = stpcpy(te, _("normal "));
336  /*@switchbreak@*/ break;
338  te = stpcpy(te, _("replaced "));
339  /*@switchbreak@*/ break;
341  te = stpcpy(te, _("not installed "));
342  /*@switchbreak@*/ break;
344  te = stpcpy(te, _("net shared "));
345  /*@switchbreak@*/ break;
347  te = stpcpy(te, _("wrong color "));
348  /*@switchbreak@*/ break;
350  te = stpcpy(te, _("(no state) "));
351  /*@switchbreak@*/ break;
352  default:
353  sprintf(te, _("(unknown %3d) "), fstate);
354  te += strlen(te);
355  /*@switchbreak@*/ break;
356  }
357  }
358 
359  if (QVA_ISSET(qva->qva_flags, FOR_DUMPFILES)) {
360  sprintf(te, "%s %d %d %s 0%o ",
361  fn, (int)fsize, fmtime, fdigest, fmode);
362  te += strlen(te);
363 
364  if (fuser && fgroup) {
365 /*@-nullpass@*/
366  sprintf(te, "%s %s", fuser, fgroup);
367 /*@=nullpass@*/
368  te += strlen(te);
369  } else {
370  rpmlog(RPMLOG_CRIT, _("package without owner/group tags\n"));
371  }
372 
373  sprintf(te, " %s %s %u ",
374  FF_ISSET(fflags, CONFIG) ? "1" : "0",
375  FF_ISSET(fflags, DOC) ? "1" : "0",
376  frdev);
377  te += strlen(te);
378 
379  sprintf(te, "%s", (flink && *flink ? flink : "X"));
380  te += strlen(te);
381  } else
382  if (!rpmIsVerbose()) {
383  te = stpcpy(te, fn);
384  }
385  else {
386 
387  /* XXX Adjust directory link count and size for display output. */
388  if (S_ISDIR(fmode)) {
389  fnlink++;
390  fsize = 0;
391  }
392 
393  if (fuser && fgroup) {
394 /*@-nullpass@*/
395  printFileInfo(te, fn, fsize, fmode, fmtime, frdev, fnlink,
396  fuser, fgroup, flink);
397 /*@=nullpass@*/
398  te += strlen(te);
399  } else {
400  rpmlog(RPMLOG_CRIT, _("package without owner/group tags\n"));
401  }
402  }
403  flushBuffer(&t, &te, 0);
404  fdigest = _free(fdigest);
405  }
406 
407  rc = 0;
408 
409 exit:
410  flushBuffer(&t, &te, 0);
411  t = _free(t);
412 
413  fi = rpmfiFree(fi);
414 JBJDEBUG((stderr, "<-- %s(%p,%p,%p) rc %d\n", __FUNCTION__, qva, ts, h, rc));
415  return rc;
416 }
417 
418 static int rpmgiShowMatches(QVA_t qva, rpmts ts)
419  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
420  /*@modifies qva, rpmGlobalMacroContext, h_errno, internalState @*/
421 {
422  rpmgi gi = qva->qva_gi;
423  rpmRC rpmrc = RPMRC_NOTFOUND;
424  int ec = 0;
425 
426 JBJDEBUG((stderr, "--> %s(%p,%p)\n", __FUNCTION__, qva, ts));
427 
428  while ((rpmrc = rpmgiNext(gi)) == RPMRC_OK) {
429  Header h;
430  int rc;
431 
432 #ifdef NOTYET /* XXX exiting here will leave stale locks. */
433  (void) rpmdbCheckSignals();
434 #endif
435 
436  h = rpmgiHeader(gi);
437  if (h == NULL) /* XXX perhaps stricter break instead? */
438  continue;
439  if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
440  ec = rc;
441  if (qva->qva_source == RPMQV_DBOFFSET)
442  break;
443  }
444  if (ec == 0 && rpmrc == RPMRC_FAIL)
445  ec++;
446 
447 JBJDEBUG((stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, qva, ts, ec));
448  return ec;
449 }
450 
462 static int rpmcliShowMatches(QVA_t qva, rpmts ts)
463  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
464  /*@modifies qva, rpmGlobalMacroContext, fileSystem, internalState @*/
465 {
466  Header h;
467  int ec = 1;
468 
469 JBJDEBUG((stderr, "--> %s(%p,%p)\n", __FUNCTION__, qva, ts));
470  qva->qva_showFAIL = qva->qva_showOK = 0;
471  while ((h = rpmmiNext(qva->qva_mi)) != NULL) {
472  ec = qva->qva_showPackage(qva, ts, h);
473  if (ec)
474  qva->qva_showFAIL++;
475  else
476  qva->qva_showOK++;
477  if (qva->qva_source == RPMQV_DBOFFSET)
478  break;
479  }
480  qva->qva_mi = rpmmiFree(qva->qva_mi);
481 JBJDEBUG((stderr, "<-- %s(%p,%p) rc %d\n", __FUNCTION__, qva, ts, ec));
482  return ec;
483 }
484 
490 static inline unsigned char nibble(char c)
491  /*@*/
492 {
493  if (c >= '0' && c <= '9')
494  return (c - '0');
495  if (c >= 'A' && c <= 'F')
496  return (c - 'A') + 10;
497  if (c >= 'a' && c <= 'f')
498  return (c - 'a') + 10;
499  return 0;
500 }
501 
502 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
503 {
504  int res = 0;
505  const char * s;
506  int i;
507  int provides_checked = 0;
508 
509 JBJDEBUG((stderr, "--> %s(%p,%p,%p)\n", __FUNCTION__, qva, ts, arg));
510 
511  (void) rpmdbCheckSignals();
512 
513  if (qva->qva_showPackage == NULL)
514  return 1;
515 
516  switch (qva->qva_source) {
517 #ifdef NOTYET
518  default:
519 #endif
520  case RPMQV_GROUP:
521  case RPMQV_TRIGGEREDBY:
522  case RPMQV_WHATCONFLICTS:
523  case RPMQV_WHATOBSOLETES:
524  qva->qva_mi = rpmtsInitIterator(ts, (rpmTag) qva->qva_source, arg, 0);
525  if (qva->qva_mi == NULL) {
526  rpmlog(RPMLOG_NOTICE, _("key \"%s\" not found in %s table\n"),
527  arg, tagName((rpmTag)qva->qva_source));
528  res = 1;
529  } else
530  res = rpmcliShowMatches(qva, ts);
531  break;
532 
533  case RPMQV_RPM:
534  res = rpmgiShowMatches(qva, ts);
535  break;
536 
537  case RPMQV_ALL:
538  res = rpmgiShowMatches(qva, ts);
539  break;
540 
541  case RPMQV_HDLIST:
542  res = rpmgiShowMatches(qva, ts);
543  break;
544 
545  case RPMQV_FTSWALK:
546  res = rpmgiShowMatches(qva, ts);
547  break;
548 
549  case RPMQV_SPECSRPM:
550  case RPMQV_SPECFILE:
551  res = ((qva->qva_specQuery != NULL)
552  ? qva->qva_specQuery(ts, qva, arg) : 1);
553  break;
554 
555 #ifdef DYING
556  case RPMQV_GROUP:
557  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
558  if (qva->qva_mi == NULL) {
560  _("group %s does not contain any packages\n"), arg);
561  res = 1;
562  } else
563  res = rpmcliShowMatches(qva, ts);
564  break;
565 
566  case RPMQV_TRIGGEREDBY:
567  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
568  if (qva->qva_mi == NULL) {
569  rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg);
570  res = 1;
571  } else
572  res = rpmcliShowMatches(qva, ts);
573  break;
574 #endif
575 
576  case RPMQV_SOURCEPKGID:
577  case RPMQV_PKGID:
578  { unsigned char MD5[16];
579  unsigned char * t;
580  rpmuint32_t tag;
581 
582  for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
583  {};
584  if (i != 32) {
585  rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "pkgid", arg);
586  return 1;
587  }
588 
589  MD5[0] = '\0';
590  for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
591  *t = (nibble(s[0]) << 4) | nibble(s[1]);
592 
593  tag = (qva->qva_source == RPMQV_PKGID
595  qva->qva_mi = rpmtsInitIterator(ts, (rpmTag) tag, MD5, sizeof(MD5));
596  if (qva->qva_mi == NULL) {
597  rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
598  "pkgid", arg);
599  res = 1;
600  } else
601  res = rpmcliShowMatches(qva, ts);
602  } break;
603 
604  case RPMQV_HDRID:
605  for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
606  {};
607  if (i != 40) {
608  rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "hdrid", arg);
609  return 1;
610  }
611 
612  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
613  if (qva->qva_mi == NULL) {
614  rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
615  "hdrid", arg);
616  res = 1;
617  } else
618  res = rpmcliShowMatches(qva, ts);
619  break;
620 
621  case RPMQV_FILEID:
622  { unsigned char * t;
623  unsigned char * digest;
624  size_t dlen;
625 
626  /* Insure even no. of digits and at least 8 digits. */
627  for (dlen = 0, s = arg; *s && isxdigit(*s); s++, dlen++)
628  {};
629  if ((dlen & 1) || dlen < 8) {
630  rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "fileid", arg);
631  return 1;
632  }
633 
634  dlen /= 2;
635  digest = (unsigned char *) memset(alloca(dlen), 0, dlen);
636  for (t = digest, s = arg; *s; t++, s += 2)
637  *t = (nibble(s[0]) << 4) | nibble(s[1]);
638 
639  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEDIGESTS, digest, dlen);
640  if (qva->qva_mi == NULL) {
641  rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
642  "fileid", arg);
643  res = 1;
644  } else
645  res = rpmcliShowMatches(qva, ts);
646  } break;
647 
648  case RPMQV_TID:
649  { int mybase = 10;
650  const char * myarg = arg;
651  char * end = NULL;
652  unsigned iid;
653 
654  /* XXX should be in strtoul */
655  if (*myarg == '0') {
656  myarg++;
657  mybase = 8;
658  if (*myarg == 'x') {
659  myarg++;
660  mybase = 16;
661  }
662  }
663  iid = (unsigned) strtoul(myarg, &end, mybase);
664  if ((*end) || (end == arg) || (iid == UINT_MAX)) {
665  rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg);
666  return 1;
667  }
668  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
669  if (qva->qva_mi == NULL) {
670  rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
671  "tid", arg);
672  res = 1;
673  } else
674  res = rpmcliShowMatches(qva, ts);
675  } break;
676 
677  case RPMQV_WHATNEEDS:
678  case RPMQV_WHATREQUIRES:
679  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
680  if (qva->qva_mi == NULL) {
681  rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg);
682  res = 1;
683  } else
684  res = rpmcliShowMatches(qva, ts);
685  break;
686 
687  case RPMQV_WHATPROVIDES:
688  if (arg[0] != '/') {
689  provides_checked = 1;
690  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
691  if (qva->qva_mi == NULL) {
692  rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg);
693  res = 1;
694  } else
695  res = rpmcliShowMatches(qva, ts);
696  break;
697  }
698  /*@fallthrough@*/
699  case RPMQV_PATH:
700  { int gotpattern = 0;
701  char * fn;
702 
703  if (arg[0] == '^' || arg[strlen(arg)-1] == '$') {
704  fn = xstrdup(arg);
705  gotpattern++;
706  } else
707 #ifdef NOTYET
708  if (arg[0] == '/' && Glob_pattern_p(arg, 1)) {
709  fn = xstrdup(arg);
710  gotpattern++;
711  } else
712 #endif
713  {
714  for (s = arg; *s != '\0'; s++) {
715  if (!(*s == '.' || *s == '/'))
716  /*@loopbreak@*/ break;
717  }
718 
719  if (*s == '\0') {
720  char fnbuf[PATH_MAX];
721  fn = Realpath(arg, fnbuf);
722  fn = xstrdup( (fn != NULL ? fn : arg) );
723  } else if (*arg != '/') {
724  const char *curDir = currentDirectory();
725  fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
726  curDir = _free(curDir);
727  } else
728  fn = xstrdup(arg);
729  (void) rpmCleanPath(fn);
730  }
731 
732  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEPATHS, fn, 0);
733  if (qva->qva_mi == NULL && !provides_checked && !gotpattern) {
734  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, fn, 0);
735 #if defined(RPM_VENDOR_MANDRIVA)
736  if(rpmmiCount(qva->qva_mi) == 0)
737  qva->qva_mi = rpmmiFree(qva->qva_mi);
738 #endif
739  }
740 
741  if (qva->qva_mi == NULL) {
742  struct stat sb;
743  if (!gotpattern && Lstat(fn, &sb) != 0)
744  rpmlog(RPMLOG_NOTICE, _("file %s: %s\n"), fn, strerror(errno));
745  else
747  _("file %s is not owned by any package\n"), fn);
748  res = 1;
749  } else
750  res = rpmcliShowMatches(qva, ts);
751 
752  fn = _free(fn);
753  } break;
754 
755  case RPMQV_DBOFFSET:
756  { int mybase = 10;
757  const char * myarg = arg;
758  char * end = NULL;
759  uint32_t hdrNum;
760 
761  /* XXX should be in strtoul */
762  if (*myarg == '0') {
763  myarg++;
764  mybase = 8;
765  if (*myarg == 'x') {
766  myarg++;
767  mybase = 16;
768  }
769  }
770  hdrNum = (uint32_t) strtoul(myarg, &end, mybase);
771  if ((*end) || (end == arg) || (hdrNum == UINT_MAX)) {
772  rpmlog(RPMLOG_NOTICE, _("invalid package number: %s\n"), arg);
773  return 1;
774  }
775  rpmlog(RPMLOG_DEBUG, D_("package record number: %u\n"), (unsigned)hdrNum);
776  qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
777  if (qva->qva_mi == NULL) {
779  _("record %u could not be read\n"), (unsigned)hdrNum);
780  res = 1;
781  } else
782  res = rpmcliShowMatches(qva, ts);
783  } break;
784 
785  case RPMQV_PACKAGE:
786  qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_NVRA, arg, 0);
787  if (qva->qva_mi == NULL) {
788  rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
789  res = 1;
790  } else {
791  res = rpmcliShowMatches(qva, ts);
792  /* detect foo.bogusarch empty iterations. */
793  if (qva->qva_showOK == 0 && qva->qva_showFAIL == 0) {
794  rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
795  res = 1;
796  }
797  }
798  break;
799  }
800 
801 JBJDEBUG((stderr, "<-- %s(%p,%p,%p) rc %d\n", __FUNCTION__, qva, ts, arg, res));
802  return res;
803 }
804 
805 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_t argv)
806  /*@globals rpmioFtsOpts @*/
807  /*@modifies rpmioFtsOpts @*/
808 {
809  rpmRC rpmrc = RPMRC_NOTFOUND;
810  int ec = 0;
811 
812 JBJDEBUG((stderr, "--> %s(%p,%p,%p)\n", __FUNCTION__, ts, qva, argv));
813  switch (qva->qva_source) {
814  case RPMQV_ALL:
815  qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
816  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, RPMGI_NONE);
817 
818  if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
819  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
820  {};
821  if (rpmrc != RPMRC_NOTFOUND)
822  return 1; /* XXX should be no. of failures. */
823 
824  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
825  ec = rpmQueryVerify(qva, ts, (const char *) argv);
826  /*@=nullpass@*/
827  rpmtsEmpty(ts);
828  break;
829  case RPMQV_RPM:
830  qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
831  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
832 
833  if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
834  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
835  {};
836  if (rpmrc != RPMRC_NOTFOUND)
837  return 1; /* XXX should be no. of failures. */
838 
839  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
840  ec = rpmQueryVerify(qva, ts, NULL);
841  /*@=nullpass@*/
842  rpmtsEmpty(ts);
843  break;
844  case RPMQV_HDLIST:
845  qva->qva_gi = rpmgiNew(ts, RPMDBI_HDLIST, NULL, 0);
846  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
847 
848  if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
849  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
850  {};
851  if (rpmrc != RPMRC_NOTFOUND)
852  return 1; /* XXX should be no. of failures. */
853 
854  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
855  ec = rpmQueryVerify(qva, ts, NULL);
856  /*@=nullpass@*/
857  rpmtsEmpty(ts);
858  break;
859  case RPMQV_FTSWALK:
860  if (rpmioFtsOpts == 0)
862  qva->qva_gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
863  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts, giFlags);
864 
865  if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
866  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
867  {};
868  if (rpmrc != RPMRC_NOTFOUND)
869  return 1; /* XXX should be no. of failures. */
870 
871  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
872  ec = rpmQueryVerify(qva, ts, NULL);
873  /*@=nullpass@*/
874  rpmtsEmpty(ts);
875  break;
876  default:
877  if (giFlags & RPMGI_TSADD) {
878  qva->qva_gi = rpmgiNew(ts, RPMTAG_NVRA, NULL, 0);
879  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
880  (rpmgiFlags) (giFlags | (RPMGI_NOGLOB )));
881  if (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD) /* Load the ts with headers. */
882  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
883  {};
884  if (rpmrc != RPMRC_NOTFOUND)
885  return 1; /* XXX should be no. of failures. */
886  qva->qva_source = RPMQV_ALL;
887  /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
888  ec = rpmQueryVerify(qva, ts, NULL);
889  /*@=nullpass@*/
890  rpmtsEmpty(ts);
891  } else {
892  qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
893  qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, rpmioFtsOpts,
895  while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK) {
896  const char * path;
897  path = rpmgiHdrPath(qva->qva_gi);
898 assert(path != NULL);
899  ec += rpmQueryVerify(qva, ts, path);
900  rpmtsEmpty(ts);
901  }
902  }
903  break;
904  }
905 
906  qva->qva_gi = rpmgiFree(qva->qva_gi);
907 
908 JBJDEBUG((stderr, "<-- %s(%p,%p,%p) rc %d\n", __FUNCTION__, ts, qva, argv, ec));
909  return ec;
910 }
911 
912 int rpmcliQuery(rpmts ts, QVA_t qva, const char ** argv)
913 {
914  rpmdepFlags depFlags = qva->depFlags, odepFlags;
915  rpmtransFlags transFlags = qva->transFlags, otransFlags;
916  rpmVSFlags vsflags, ovsflags;
917  int ec = 0;
918 
919 JBJDEBUG((stderr, "--> %s(%p,%p,%p)\n", __FUNCTION__, ts, qva, argv));
920  if (qva->qva_showPackage == NULL)
922 
923  /* If --queryformat unspecified, then set default now. */
924  if (qva->qva_queryFormat == NULL
925  && !QVA_ISSET(qva->qva_flags, FOR_LIST)
926  && !QVA_ISSET(qva->qva_flags, FOR_STATE)
927  && !QVA_ISSET(qva->qva_flags, FOR_DOCS)
928  && !QVA_ISSET(qva->qva_flags, FOR_CONFIG)
929  && !QVA_ISSET(qva->qva_flags, FOR_DUMPFILES)
930  ) {
931  qva->qva_queryFormat = rpmExpand("%{?_query_all_fmt}\n", NULL);
932  if (!(qva->qva_queryFormat != NULL && *qva->qva_queryFormat != '\0')) {
934  qva->qva_queryFormat = xstrdup("%{name}-%{version}-%{release}.%{arch}\n");
935  }
936  }
937 
938  vsflags = (rpmVSFlags) rpmExpandNumeric("%{?_vsflags_query}");
939  vsflags = (rpmVSFlags) 0; /* XXX FIXME: ignore default disablers. */
940 #if defined(SUPPORT_NOSIGNATURES)
941  if (!QVA_ISSET(qva->qva_flags, DIGEST)) {
942  VSF_SET(vsflags, NOSHA1HEADER);
943  VSF_SET(vsflags, NOMD5HEADER);
944  VSF_SET(vsflags, NOSHA1);
945  VSF_SET(vsflags, NOMD5);
946  }
947  if (!QVA_ISSET(qva->qva_flags, SIGNATURE)) {
948  VSF_SET(vsflags, NODSAHEADER);
949  VSF_SET(vsflags, NORSAHEADER);
950  VSF_SET(vsflags, NODSA);
951  VSF_SET(vsflags, NORSA);
952  }
953  if (!QVA_ISSET(qva->qva_flags, HDRCHK)) {
954  VSF_SET(vsflags, NOHDRCHK);
955  }
956  VSF_CLR(vsflags, NEEDPAYLOAD); /* XXX needed? */
957 #endif
958 
959  odepFlags = rpmtsSetDFlags(ts, depFlags);
960  otransFlags = rpmtsSetFlags(ts, transFlags);
961  ovsflags = rpmtsSetVSFlags(ts, vsflags);
962  ec = rpmcliArgIter(ts, qva, argv);
963  vsflags = rpmtsSetVSFlags(ts, ovsflags);
964  transFlags = rpmtsSetFlags(ts, otransFlags);
965  depFlags = rpmtsSetDFlags(ts, odepFlags);
966 
967  if (qva->qva_showPackage == showQueryPackage)
968  qva->qva_showPackage = NULL;
969 
970 JBJDEBUG((stderr, "<-- %s(%p,%p,%p) rc %d\n", __FUNCTION__, ts, qva, argv, ec));
971  return ec;
972 }