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 }
rpmuint32_t rpmfiFFlags(rpmfi fi)
Return current file flags from file info set.
Definition: rpmfi.c:217
rpmdepFlags depFlags
Definition: rpmcli.h:675
static void flushBuffer(char **tp, char **tep, int nonewline)
Definition: query.c:183
int rpmQueryVerify(QVA_t qva, rpmts ts, const char *arg)
Common query/verify source interface, called once for each CLI arg.
Definition: query.c:502
rpmgiFlags rpmgiGetFlags(rpmgi gi)
Return current iteration flags.
Definition: rpmgi.c:835
static void printFileInfo(char *te, const char *name, size_t size, unsigned short mode, unsigned int mtime, unsigned short rdev, unsigned int nlink, const char *owner, const char *group, const char *linkto)
Definition: query.c:64
int rpmcliQuery(rpmts ts, QVA_t qva, const char **argv)
Display package information.
Definition: query.c:912
rpmuint32_t rpmfiFNlink(rpmfi fi)
Return (calculated) current file nlink count from file info set.
Definition: rpmfi.c:427
char * xstrdup(const char *str)
Definition: rpmmalloc.c:322
char * rpmCleanPath(char *path)
Canonicalize file path.
Definition: macro.c:3218
rpmgi rpmgiFree(rpmgi gi)
Destroy a generalized iterator.
char * rpmGetPath(const char *path,...)
Return (malloc&#39;ed) expanded, canonicalized, file path.
Definition: macro.c:3310
Structure(s) used for file info tag sets.
int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_t argv)
Definition: query.c:805
The Header data structure.
rpmQueryFlags qva_flags
Definition: rpmcli.h:637
headerSprintfExtension rpmHeaderFormats
Table of query format extensions.
Definition: formats.c:305
static const char * queryHeader(Header h, const char *qfmt)
Definition: query.c:166
#define RPMTAG_PKGID
Definition: rpmtag.h:159
static rpmVSFlags vsflags
Definition: rpmcache.c:547
Header rpmgiHeader(rpmgi gi)
Return current iteration header.
Definition: rpmgi.c:845
rpmuint16_t rpmfiFRdev(rpmfi fi)
Return current file rdev from file info set.
Definition: rpmfi.c:339
#define S_ISLNK(mode)
Definition: system.h:610
int errno
static int rpmcliShowMatches(QVA_t qva, rpmts ts)
Display query/verify information for each header in iterator.
Definition: query.c:462
rpmfi rpmfiFree(rpmfi fi)
Destroy a file info set.
const char * rpmfiFN(rpmfi fi)
Return current file name from file info set.
Definition: rpmfi.c:163
int rpmdbCheckSignals(void)
Check for and exit on termination signals.
Definition: rpmdb.c:523
const char * rpmfiFUser(rpmfi fi)
Return current file owner from file info set.
Definition: rpmfi.c:458
static int _jbj
Definition: query.c:33
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
const char * rpmfiFGroup(rpmfi fi)
Return current file group from file info set.
Definition: rpmfi.c:470
rpmfi rpmfiNew(const void *_ts, Header h, rpmTag tagN, int flags)
Create and load a file info set.
Definition: rpmfi.c:1403
Command line option information.
Definition: rpmcli.h:634
char * headerSprintf(Header h, const char *fmt, headerTagTableEntry tags, headerSprintfExtension exts, errmsg_t *errmsg)
Return formatted output string from header tags.
Definition: hdrfmt.c:6700
int rpmfiFC(rpmfi fi)
Return file count from file info set.
Definition: rpmfi.c:87
rpmuint32_t rpmfiFSize(rpmfi fi)
Return current file size from file info set.
Definition: rpmfi.c:328
QSpecF_t qva_specQuery
Definition: rpmcli.h:650
#define RPMFILE_STATE_MISSING
Definition: rpmfi.h:41
char * alloca()
QVF_t qva_showPackage
Definition: rpmcli.h:646
rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
Set transaction flags, i.e.
Definition: rpmts.c:1357
unsigned int rpmuint32_t
Definition: rpmiotypes.h:25
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:301
rpmgi rpmgiNew(rpmts ts, int tag, const void *keyp, size_t keylen)
Return a generalized iterator.
Definition: rpmgi.c:543
char * currentDirectory(void)
Return (malloc&#39;d) current working directory.
Definition: misc.c:72
enum rpmgiFlags_e rpmgiFlags
struct rpmfi_s * rpmfi
File info tag sets from a header, so that a header can be discarded early.
Definition: rpmfi.h:78
static unsigned char nibble(char c)
Convert hex to binary nibble.
Definition: query.c:490
rpmuint16_t rpmfiFMode(rpmfi fi)
Return current file mode from file info set.
Definition: rpmfi.c:265
int showQueryPackage(QVA_t qva, rpmts ts, Header h)
Display results of package query.
Definition: query.c:203
rpmgiFlags giFlags
Definition: rpmgi.c:42
#define FTS_COMFOLLOW
Definition: fts.h:87
int Lstat(const char *path, struct stat *st)
lstat(2) clone.
Definition: rpmrpc.c:1401
enum rpmdepFlags_e rpmdepFlags
Bit(s) to control rpmtsCheck() and rpmtsOrder() operation.
char * rpmPermsString(int mode)
Return ls(1)-like formatted mode string.
Definition: manifest.c:15
static int rpmgiShowMatches(QVA_t qva, rpmts ts)
Definition: query.c:418
const char * tagName(rpmTag tag)
Return tag name from value.
Definition: tagname.c:436
rpmtransFlags transFlags
Definition: rpmcli.h:676
Routines to expand a manifest containing glob expressions into an argv list.
int Glob_pattern_p(const char *pattern, int quote)
glob_pattern_p(3) clone.
Definition: rpmrpc.c:2231
#define RPMDBI_FTSWALK
Definition: rpmtag.h:488
rpmRC rpmgiSetArgs(rpmgi gi, ARGV_t argv, int ftsOpts, rpmgiFlags flags)
Load iterator args.
Definition: rpmgi.c:864
rpmQVSources qva_source
Definition: rpmcli.h:635
rpmmi rpmtsInitIterator(const rpmts ts, rpmTag rpmtag, const void *keyp, size_t keylen)
Return transaction database iterator.
Definition: rpmts.c:212
const char * qva_queryFormat
Definition: rpmcli.h:654
#define QVA_ISSET(_qvaflags, _FLAG)
Definition: query.c:54
#define VSF_CLR(_vsflags, _FLAG)
Definition: query.c:58
pgpVSFlags rpmVSFlags
Bit(s) to control digest and signature verification.
Definition: rpmts.h:30
int rpmioFtsOpts
Definition: poptIO.c:526
char * rpmExpand(const char *arg,...)
Return (malloc&#39;ed) concatenated macro expansion(s).
Definition: macro.c:3117
rpmuint32_t rpmfiFMtime(rpmfi fi)
Return current file modify time from file info set.
Definition: rpmfi.c:447
rpmfileAttrs qva_fflags
Definition: rpmcli.h:638
rpmmi rpmmiFree(rpmmi mi)
Destroy rpm database iterator.
#define FF_ISSET(_fflags, _FLAG)
Definition: query.c:52
enum rpmfileAttrs_e rpmfileAttrs
File Attributes.
int rpmfiNext(rpmfi fi)
Return next file iterator index.
Definition: rpmfi.c:526
#define RPMDBI_HDLIST
Definition: rpmtag.h:486
struct rpmgi_s * rpmgi
Generalized iterator.
Definition: rpmtypes.h:53
enum rpmRC_e rpmRC
RPM return codes.
#define VSF_SET(_vsflags, _FLAG)
Definition: query.c:57
#define RPMDBI_ARGLIST
Definition: rpmtag.h:487
#define L(CS)
Definition: fnmatch.c:155
rpmfi rpmfiInit(rpmfi fi, int fx)
Initialize file iterator index.
Definition: rpmfi.c:548
enum rpmfileState_e rpmfileState
File States (when installed).
rpmdepFlags rpmtsSetDFlags(rpmts ts, rpmdepFlags depFlags)
Set dependency flags, i.e.
Definition: rpmts.c:1378
static const char * prefix[]
Tables for prefixing and suffixing patterns, according to the -w, -x, and -F options.
Definition: rpmgrep.c:183
const char * rpmfiFLink(rpmfi fi)
Return current file linkto (i.e.
Definition: rpmfi.c:317
enum rpmtransFlags_e rpmtransFlags
Bit(s) to control rpmtsRun() operation.
rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
Set verify signatures flag(s).
Definition: rpmts.c:843
char * stpcpy(char *dest, const char *src)
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:647
Structures and prototypes used for an "rpmts" transaction set.
Header rpmmiNext(rpmmi mi)
Return next package header from iteration.
Definition: rpmdb.c:2248
rpmfileState rpmfiFState(rpmfi fi)
Return current file state from file info set.
Definition: rpmfi.c:276
#define JBJDEBUG(_list)
Definition: query.c:34
const unsigned char * rpmfiDigest(rpmfi fi, int *algop, size_t *lenp)
Return current file (binary) digest from file info set.
Definition: rpmfi.c:300
#define FTS_LOGICAL
Definition: fts.h:88
#define rpmIsVerbose()
Definition: rpmcb.h:21
rpmRC rpmgiNext(rpmgi gi)
Perform next iteration step.
Definition: rpmgi.c:584
static const char * name
#define _(Text)
Definition: system.h:30
const char * rpmgiHdrPath(rpmgi gi)
Return current header path.
Definition: rpmgi.c:840
#define xmalloc
Definition: system.h:33
void * headerSetRpmdb(Header h, void *rpmdb)
Store rpmdb pointer.
Definition: header.c:1266
ARGstr_t * ARGV_t
Definition: argv.h:9
Access RPM indices using Berkeley DB interface(s).
enum rpmTag_e rpmTag
Definition: rpmtag.h:471
#define D_(Text)
Definition: system.h:485
#define PATH_MAX
Definition: query.c:10
unsigned int rpmmiCount(rpmmi mi)
Return number of elements in rpm database iterator.
Definition: rpmdb.c:1759
#define FTS_NOSTAT
Definition: fts.h:90
char * Realpath(const char *path, char *resolved_path)
realpath(3) clone.
Definition: rpmrpc.c:2330
int rpmExpandNumeric(const char *arg)
Return macro expansion as a numeric value.
Definition: macro.c:3191
#define RPMDBI_PACKAGES
Pseudo-tags used by the rpmdb and rpmgi iterator API&#39;s.
Definition: rpmtag.h:480
#define xrealloc
Definition: system.h:36
void rpmtsEmpty(rpmts ts)
Re-create an empty transaction set.
Definition: rpmts.c:623