rpm  5.4.15
rpmdb.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <sys/file.h>
8 
9 #include <rpmiotypes.h>
10 #include <rpmlog.h>
11 #include <rpmpgp.h>
12 #include <rpmurl.h>
13 #include <rpmhash.h> /* hashFunctionString */
14 #define _MIRE_INTERNAL
15 #include <rpmmacro.h>
16 #include <rpmsq.h>
17 #include <rpmsx.h>
18 #include <argv.h>
19 
20 #define _RPMBF_INTERNAL
21 #include <rpmbf.h>
22 
23 #include <rpmtypes.h>
24 #define _RPMTAG_INTERNAL
25 #include "header_internal.h" /* XXX for HEADERFLAG_MAPPED */
26 
27 #define _RPMDB_INTERNAL
28 #include "rpmdb.h"
29 
30 #include "pkgio.h"
31 #include "fprint.h"
32 #include "legacy.h"
33 
34 #include "debug.h"
35 
36 #if defined(__LCLINT__)
37 #define UINT32_T u_int32_t
38 #else
39 #define UINT32_T rpmuint32_t
40 #endif
41 
42 /* XXX retrofit the *BSD typedef for the deprived. */
43 #if defined(__QNXNTO__)
44 typedef rpmuint32_t u_int32_t;
45 #endif
46 
47 /*@access dbiIndexSet@*/
48 /*@access dbiIndexItem@*/
49 /*@access miRE@*/
50 /*@access Header@*/ /* XXX compared with NULL */
51 /*@access rpmmi@*/
52 /*@access rpmts@*/ /* XXX compared with NULL */
53 
54 #ifdef __cplusplus
55 GENfree(dbiIndex *)
56 GENfree(dbiIndexSet)
57 GENfree(dbiIndexItem)
58 #endif /* __cplusplus */
59 
60 /*@unchecked@*/
61 int _rpmdb_debug = 0;
62 
63 /*@unchecked@*/
64 int _rpmmi_debug = 0;
65 
66 #define _DBI_FLAGS 0
67 #define _DBI_PERMS 0644
68 #define _DBI_MAJOR -1
69 
76 static size_t dbiTagToDbix(rpmdb db, rpmTag tag)
77  /*@*/
78 {
79  size_t dbix;
80 
81  if (db->db_tags != NULL)
82  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
83  if (tag != db->db_tags[dbix].tag)
84  continue;
85  return dbix;
86  }
87  return 0xffffffff;
88 }
89 
93 /*@-exportheader@*/
94 static void dbiTagsInit(/*@null@*/ tagStore_t * dbiTagsP,
95  /*@null@*/ size_t * dbiNTagsP)
96  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
97  /*@modifies *dbiTagsP, *dbiNTagsP, rpmGlobalMacroContext, internalState @*/
98 {
99 /*@observer@*/
100  static const char * const _dbiTagStr_default =
101  "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filedigests:Depends:Pubkeys";
102  tagStore_t dbiTags = NULL;
103  size_t dbiNTags = 0;
104  char * dbiTagStr = NULL;
105  char * o, * oe;
106  rpmTag tag;
107  size_t dbix;
108  int bingo;
109 
110  dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL);
111  if (!(dbiTagStr && *dbiTagStr)) {
112  dbiTagStr = _free(dbiTagStr);
113  dbiTagStr = xstrdup(_dbiTagStr_default);
114  }
115 
116 #ifdef NOISY
117 if (_rpmdb_debug)
118 fprintf(stderr, "--> %s(%p, %p) dbiTagStr %s\n", __FUNCTION__, dbiTagsP, dbiNTagsP, dbiTagStr);
119 #endif
120  /* Always allocate package index */
121  dbiTags = (tagStore_t) xcalloc(1, sizeof(*dbiTags));
122  dbiTags[dbiNTags].str = xstrdup("Packages");
123  dbiTags[dbiNTags].tag = RPMDBI_PACKAGES;
124  dbiTags[dbiNTags].iob = NULL;
125  dbiNTags++;
126 
127  for (o = dbiTagStr; o && *o; o = oe) {
128  while (*o && xisspace((int)*o))
129  o++;
130  if (*o == '\0')
131  break;
132  for (oe = o; oe && *oe; oe++) {
133  if (xisspace((int)*oe))
134  /*@innerbreak@*/ break;
135  if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
136  /*@innerbreak@*/ break;
137  }
138  if (oe && *oe)
139  *oe++ = '\0';
140  tag = tagValue(o);
141 
142  bingo = 0;
143  if (dbiTags != NULL)
144  for (dbix = 0; dbix < dbiNTags; dbix++) {
145  if (tag == dbiTags[dbix].tag) {
146  bingo = 1;
147  /*@innerbreak@*/ break;
148  }
149  }
150  if (bingo)
151  continue;
152 
153  dbiTags = (tagStore_t) xrealloc(dbiTags, (dbiNTags + 1) * sizeof(*dbiTags));
154  dbiTags[dbiNTags].str = xstrdup(o);
155  dbiTags[dbiNTags].tag = tag;
156  dbiTags[dbiNTags].iob = NULL;
157 #ifdef NOISY
158 if (_rpmdb_debug) {
159 fprintf(stderr, "\t%u %s(", (unsigned)dbiNTags, o);
160 if (tag & 0x40000000)
161  fprintf(stderr, "0x%x)\n", tag);
162 else
163  fprintf(stderr, "%d)\n", tag);
164 }
165 #endif
166  dbiNTags++;
167  }
168 
169  if (dbiNTagsP != NULL)
170  *dbiNTagsP = dbiNTags;
171  if (dbiTagsP != NULL)
172  *dbiTagsP = dbiTags;
173  else
174  dbiTags = tagStoreFree(dbiTags, dbiNTags);
175  dbiTagStr = _free(dbiTagStr);
176 }
177 /*@=exportheader@*/
178 
179 /*@-redecl@*/
180 #define DB1vec NULL
181 #define DB2vec NULL
182 
183 #if defined(WITH_DB)
184 /*@-exportheadervar -declundef @*/
185 /*@observer@*/ /*@unchecked@*/
186 extern struct _dbiVec db3vec;
187 /*@=exportheadervar =declundef @*/
188 #define DB3vec &db3vec
189 /*@=redecl@*/
190 #else
191 #define DB3vec NULL
192 #endif
193 
194 #if defined(HAVE_SQLITE3_H) /* XXX test --with-sqlite=external */
195 /*@-exportheadervar -declundef @*/
196 /*@observer@*/ /*@unchecked@*/
197 extern struct _dbiVec sqlitevec;
198 /*@=exportheadervar =declundef @*/
199 #define SQLITEvec &sqlitevec
200 /*@=redecl@*/
201 #else
202 #define SQLITEvec NULL
203 #endif
204 
205 /*@-nullassign@*/
206 /*@observer@*/ /*@unchecked@*/
207 static struct _dbiVec *mydbvecs[] = {
209 };
210 /*@=nullassign@*/
211 
212 static inline int checkfd(const char * devnull, int fdno, int flags)
213  /*@*/
214 {
215  struct stat sb;
216  int ret = 0;
217 
218  if (fstat(fdno, &sb) == -1 && errno == EBADF)
219  ret = (open(devnull, flags) == fdno) ? 1 : 2;
220  return ret;
221 }
222 
223 dbiIndex dbiOpen(rpmdb db, rpmTag tag, /*@unused@*/ unsigned int flags)
224 {
225  static int _oneshot = 0;
226  size_t dbix;
227  dbiIndex dbi = NULL;
228  int _dbapi;
229  int rc = 0;
230 
231  /* Insure that stdin/stdout/stderr are open, lest stderr end up in rpmdb. */
232  if (!_oneshot) {
233  static const char _devnull[] = "/dev/null";
234 /*@-noeffect@*/
235 #if defined(STDIN_FILENO)
236  (void) checkfd(_devnull, STDIN_FILENO, O_RDONLY);
237 #endif
238 #if defined(STDOUT_FILENO)
239  (void) checkfd(_devnull, STDOUT_FILENO, O_WRONLY);
240 #endif
241 #if defined(STDERR_FILENO)
242  (void) checkfd(_devnull, STDERR_FILENO, O_WRONLY);
243 #endif
244 /*@=noeffect@*/
245  _oneshot++;
246  }
247 
248 assert(db != NULL); /* XXX sanity */
249 assert(db->_dbi != NULL); /* XXX sanity */
250 
251  /* Is this index configured? */
252  dbix = dbiTagToDbix(db, tag);
253  if (dbix >= db->db_ndbi)
254  goto exit;
255 
256  /* Is this index already open ? */
257  if ((dbi = db->_dbi[dbix]) != NULL)
258  goto exit;
259 
260  _dbapi = db->db_api;
261 assert(_dbapi == 3 || _dbapi == 4);
262 assert(mydbvecs[_dbapi] != NULL);
263 
264  rc = (*mydbvecs[_dbapi]->open) (db, tag, &dbi);
265  if (rc) {
266  static uint8_t _printed[128];
267  if (!_printed[dbix & 0x1f]++)
269  _("cannot open %s(%u) index: %s(%d)\n\tDB: %s\n"),
270  tagName(tag), tag,
271  (rc > 0 ? strerror(rc) : ""), rc,
272  ((mydbvecs[_dbapi]->dbv_version != NULL)
273  ? mydbvecs[_dbapi]->dbv_version : "unknown"));
274  dbi = db3Free(dbi);
275  goto exit;
276  }
277  db->_dbi[dbix] = dbi;
278 
279 exit:
280 
281 /*@-modfilesys@*/
282 if (_rpmdb_debug)
283 fprintf(stderr, "<== dbiOpen(%p, %s(%u), 0x%x) dbi %p = %p[%u:%u]\n", db, tagName(tag), tag, flags, dbi, db->_dbi, (unsigned)dbix, (unsigned)db->db_ndbi);
284 /*@=modfilesys@*/
285 
286 /*@-compdef -nullstate@*/ /* FIX: db->_dbi may be NULL */
287  return dbi;
288 /*@=compdef =nullstate@*/
289 }
290 
291 /*@-redef@*/
292 union _dbswap {
293  uint64_t ul;
294  uint32_t ui;
295  uint16_t us;
296  uint8_t uc[8];
297 };
298 /*@=redef@*/
299 
300 /*@unchecked@*/
301 static union _dbswap _endian = { 0x11223344 };
302 
303 static inline uint64_t _ntoh_ul(uint64_t ul)
304  /*@*/
305 {
306  union _dbswap _a;
307  _a.ul = ul;
308  if (_endian.uc[0] == 0x44) {
309  uint8_t _b, *_c = _a.uc; \
310  _b = _c[7]; _c[7] = _c[0]; _c[0] = _b; \
311  _b = _c[6]; _c[6] = _c[1]; _c[1] = _b; \
312  _b = _c[5]; _c[5] = _c[2]; _c[2] = _b; \
313  _b = _c[4]; _c[4] = _c[3]; _c[3] = _b; \
314  }
315  return _a.ul;
316 }
317 static inline uint64_t _hton_ul(uint64_t ul)
318  /*@*/
319 {
320  return _ntoh_ul(ul);
321 }
322 
323 static inline uint32_t _ntoh_ui(uint32_t ui)
324  /*@*/
325 {
326  union _dbswap _a;
327  _a.ui = ui;
328  if (_endian.uc[0] == 0x44) {
329  uint8_t _b, *_c = _a.uc; \
330  _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
331  _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
332  }
333  return _a.ui;
334 }
335 static inline uint32_t _hton_ui(uint32_t ui)
336  /*@*/
337 {
338  return _ntoh_ui(ui);
339 }
340 
341 static inline uint16_t _ntoh_us(uint16_t us)
342  /*@*/
343 {
344  union _dbswap _a;
345  _a.us = us;
346  if (_endian.uc[0] == 0x44) {
347  uint8_t _b, *_c = _a.uc; \
348  _b = _c[1]; _c[1] = _c[0]; _c[0] = _b; \
349  }
350  return _a.us;
351 }
352 static inline uint16_t _hton_us(uint16_t us)
353  /*@*/
354 {
355  return _ntoh_us(us);
356 }
357 
358 typedef struct _setSwap_s {
359  union _dbswap hdr;
360  union _dbswap tag;
361  uint32_t fp;
362 } * setSwap;
363 
364 /* XXX assumes hdrNum is first int in dbiIndexItem */
365 static int hdrNumCmp(const void * one, const void * two)
366  /*@*/
367 {
368  const int * a = (const int *) one;
369  const int * b = (const int *) two;
370  return (*a - *b);
371 }
372 
382 static int dbiAppendSet(dbiIndexSet set, const void * recs,
383  int nrecs, size_t recsize, int sortset)
384  /*@modifies *set @*/
385 {
386  const char * rptr = (const char *) recs;
387  size_t rlen = (recsize < sizeof(*(set->recs)))
388  ? recsize : sizeof(*(set->recs));
389 
390  if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
391  return 1;
392 
393  set->recs = (dbiIndexItem) xrealloc(set->recs,
394  (set->count + nrecs) * sizeof(*(set->recs)));
395 
396  memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
397 
398  while (nrecs-- > 0) {
399  /*@-mayaliasunique@*/
400  memcpy(set->recs + set->count, rptr, rlen);
401  /*@=mayaliasunique@*/
402  rptr += recsize;
403  set->count++;
404  }
405 
406  if (sortset && set->count > 1)
407  qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
408 
409  return 0;
410 }
411 
412 /* XXX transaction.c */
414  return set->count;
415 }
416 
417 /* XXX transaction.c */
418 uint32_t dbiIndexRecordOffset(dbiIndexSet set, unsigned int recno) {
419  return set->recs[recno].hdrNum;
420 }
421 
422 /* XXX transaction.c */
423 uint32_t dbiIndexRecordFileNumber(dbiIndexSet set, unsigned int recno) {
424  return set->recs[recno].tagNum;
425 }
426 
427 /* XXX transaction.c */
429  if (set) {
430  set->recs = _free(set->recs);
431  set = _free(set);
432  }
433  return set;
434 }
435 
436 struct rpmmi_s {
438 /*@dependent@*/ /*@null@*/
440 /*@refcounted@*/
445  unsigned int mi_count;
446  uint32_t mi_setx;
447  void * mi_keyp;
448  const char * mi_primary;
449  size_t mi_keylen;
450 /*@refcounted@*/ /*@null@*/
455  uint32_t mi_prevoffset; /* header instance (big endian) */
456  uint32_t mi_offset; /* header instance (big endian) */
457  uint32_t mi_bntag; /* base name tag (native endian) */
458 /*@refcounted@*/ /*@null@*/
459  rpmbf mi_bf; /* Iterator instance Bloom filter. */
460  int mi_nre;
461 /*@only@*/ /*@null@*/
463 
464 #if defined(__LCLINT__)
465 /*@refs@*/
466  int nrefs;
467 #endif
468 };
469 
470 /*@unchecked@*/
472 
473 /*@unchecked@*/ /*@exposed@*/ /*@null@*/
475 
476 int rpmdbCheckTerminate(int terminate)
477  /*@globals rpmdbRock, rpmmiRock @*/
478  /*@modifies rpmdbRock, rpmmiRock @*/
479 {
480  sigset_t newMask, oldMask;
481  static int terminating = 0;
482 
483  if (terminating) return 1;
484 
485  (void) sigfillset(&newMask); /* block all signals */
486  (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
487 
488  if (sigismember(&rpmsqCaught, SIGINT)
489  || sigismember(&rpmsqCaught, SIGQUIT)
490  || sigismember(&rpmsqCaught, SIGHUP)
491  || sigismember(&rpmsqCaught, SIGTERM)
492  || sigismember(&rpmsqCaught, SIGPIPE)
493 #ifdef NOTYET /* XXX todo++ */
494  || sigismember(&rpmsqCaught, SIGXCPU)
495  || sigismember(&rpmsqCaught, SIGXFSZ)
496 #endif
497  || terminate)
498  terminating = 1;
499 
500  if (terminating) {
501  rpmdb db;
502  rpmmi mi;
503 
504  while ((mi = rpmmiRock) != NULL) {
505 /*@i@*/ rpmmiRock = mi->mi_next;
506  mi->mi_next = NULL;
507 /*@i@*/ mi = rpmmiFree(mi);
508  }
509 
510 /*@-newreftrans@*/
511  while ((db = rpmdbRock) != NULL) {
512 /*@i@*/ rpmdbRock = db->db_next;
513  db->db_next = NULL;
514  (void) rpmdbClose(db);
515  }
516 /*@=newreftrans@*/
517  }
518 
519  (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
520  return terminating;
521 }
522 
524 {
525 
526  if (rpmdbCheckTerminate(0)) {
527 /*@-abstract@*/ /* sigset_t is abstract type */
528  rpmlog(RPMLOG_DEBUG, D_("Exiting on signal(0x%lx) ...\n"), *((unsigned long *)&rpmsqCaught));
529 /*@=abstract@*/
530  exit(EXIT_FAILURE);
531  }
532  return 0;
533 }
534 
541 static int blockSignals(/*@unused@*/ rpmdb db, /*@out@*/ sigset_t * oldMask)
542  /*@globals fileSystem @*/
543  /*@modifies *oldMask, fileSystem @*/
544 {
545  sigset_t newMask;
546 
547  (void) sigfillset(&newMask); /* block all signals */
548  (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
549  (void) sigdelset(&newMask, SIGINT);
550  (void) sigdelset(&newMask, SIGQUIT);
551  (void) sigdelset(&newMask, SIGHUP);
552  (void) sigdelset(&newMask, SIGTERM);
553  (void) sigdelset(&newMask, SIGPIPE);
554  return sigprocmask(SIG_BLOCK, &newMask, NULL);
555 }
556 
563 /*@mayexit@*/
564 static int unblockSignals(/*@unused@*/ rpmdb db, sigset_t * oldMask)
565  /*@globals fileSystem, internalState @*/
566  /*@modifies fileSystem, internalState @*/
567 {
568  (void) rpmdbCheckSignals();
569  return sigprocmask(SIG_SETMASK, oldMask, NULL);
570 }
571 
579 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
580  /*@globals headerCompoundFormats, fileSystem, internalState @*/
581  /*@modifies h, fileSystem, internalState @*/
582 {
583  const char * errstr = "(unkown error)";
584  const char * str;
585 
586 /*@-modobserver@*/
587  str = headerSprintf(h, qfmt, NULL, headerCompoundFormats, &errstr);
588 /*@=modobserver@*/
589  if (str == NULL)
590  rpmlog(RPMLOG_ERR, _("incorrect format: \"%s\": %s\n"), qfmt, errstr);
591  return str;
592 }
593 
601 static int rpmdbExportHR_MIB(/*@unused@*/ rpmdb db, Header h, int adding)
602  /*@globals headerCompoundFormats, rpmGlobalMacroContext, h_errno,
603  fileSystem, internalState @*/
604  /*@modifies h, rpmGlobalMacroContext,
605  fileSystem, internalState @*/
606 {
607  static int oneshot;
608  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
609  const char * fn = NULL;
610  int rc = -1;
611  int xx;
612 
613  { const char * fnfmt = rpmGetPath("%{?_hrmib_path}", NULL);
614  if (fnfmt && *fnfmt)
615  fn = queryHeader(h, fnfmt);
616  fnfmt = _free(fnfmt);
617  }
618 
619  if (fn == NULL)
620  goto exit;
621 
622  /* Lazily create the directory in chroot's if configured. */
623  if (!oneshot) {
624  char * _fn = xstrdup(fn);
625  char * dn = dirname(_fn);
626  mode_t _mode = 0755;
627  uid_t _uid = 0;
628  gid_t _gid = 0;
629  /* If not a directory, then disable, else don't retry. */
630  errno = 0;
631  oneshot = (rpmioMkpath(dn, _mode, _uid, _gid) ? -1 : 1);
632  _fn = _free(_fn);
633  }
634  /* If directory is AWOL, don't bother exporting info. */
635  if (oneshot < 0)
636  goto exit;
637 
638  if (adding) {
639  FD_t fd = Fopen(fn, "w.fdio");
640 
641  if (fd != NULL) {
642  xx = Fclose(fd);
643  fd = NULL;
644  he->tag = RPMTAG_INSTALLTID;
645  if (headerGet(h, he, 0)) {
646  struct utimbuf stamp;
647  stamp.actime = he->p.ui32p[0];
648  stamp.modtime = he->p.ui32p[0];
649  if (!Utime(fn, &stamp))
650  rpmlog(RPMLOG_DEBUG, " +++ %s\n", fn);
651  }
652  he->p.ptr = _free(he->p.ptr);
653  }
654  } else {
655  if (!Unlink(fn))
656  rpmlog(RPMLOG_DEBUG, " --- %s\n", fn);
657  }
658  rc = 0;
659 
660 exit:
661  fn = _free(fn);
662  return rc;
663 }
664 
665 #ifdef NOTYET /* XXX mixed {bdb,sqlite3} dbenv issues w db-6.1.19 */
666 static const char l10n_sql_init[] = "\
667 CREATE TABLE IF NOT EXISTS l10n (\n\
668  k TEXT UNIQUE PRIMARY KEY NOT NULL,\n\
669  v TEXT NOT NULL\n\
670 );\n\
671 ";
672 static const char l10n_sql_qfmt[] =
673 #include "wdj_l10n_sqlite"
674 ;
675 
683 static int rpmdbExportL10N_SQL(/*@unused@*/ rpmdb db, Header h, int adding)
684  /*@globals headerCompoundFormats, rpmGlobalMacroContext, h_errno,
685  fileSystem, internalState @*/
686  /*@modifies h, rpmGlobalMacroContext,
687  fileSystem, internalState @*/
688 {
689  static int oneshot;
690  char * fn = NULL;
691  char * t = NULL;
692  int rc = 0; /* XXX errors? */
693 
694  /* If directory isn't configured, don't bother. */
695  fn = rpmGetPath("%{?__l10ndir:%{__l10ndir}/sqldb}", NULL);
696  if (!(fn && *fn)) {
697  oneshot = -1;
698  goto exit;
699  }
700 
701  /* Lazily create the directory in chroot's if configured. */
702  if (!oneshot) {
703  char * _fn = xstrdup(fn);
704  char * dn = dirname(_fn);
705  static mode_t _mode = 0755;
706  static uid_t _uid = 0;
707  static gid_t _gid = 0;
708  /* If not a directory, then disable, else don't retry. */
709  errno = 0;
710  oneshot = (rpmioMkpath(dn, _mode, _uid, _gid) ? -1 : 1);
711  _fn = _free(_fn);
712  if (oneshot > 0) {
713  t = rpmExpand("%{sql -echo ", fn, ":\n", l10n_sql_init, "}", NULL);
714  t = _free(t);
715  }
716  }
717 
718  /* If directory is AWOL, don't bother. */
719  if (oneshot < 0)
720  goto exit;
721 
722  if (adding) {
723  /* XXX macro expand before headerSprintf? */
724  /* XXX skip gpg(...)? */
725  const char * SQL = queryHeader(h, (char *)l10n_sql_qfmt);
726  t = rpmExpand("%{sql -echo ", fn, ":\n",
727  "BEGIN TRANSACTION;\n",
728  SQL,
729  "COMMIT TRANSACTION;\n",
730  "}", NULL);
731  t = _free(t);
732  SQL = _free(SQL);
733  } else
734 assert(0); /* XXX remove on erase? */
735 
736 exit:
737  t = _free(t);
738  fn = _free(fn);
739  return rc;
740 }
741 #endif /* NOTYET */
742 
750 static int rpmdbExportInfo(/*@unused@*/ rpmdb db, Header h, int adding)
751  /*@globals headerCompoundFormats, rpmGlobalMacroContext, h_errno,
752  fileSystem, internalState @*/
753  /*@modifies h, rpmGlobalMacroContext,
754  fileSystem, internalState @*/
755 {
756  int rc = 0;
757  int xx;
758 
759  /* Add/remove stamp file in %{?_hrmib_path} (if configured). */
760  xx = rpmdbExportHR_MIB(db, h, adding);
761 
762 #ifdef NOTYET /* XXX mixed {bdb,sqlite3} dbenv issues w db-6.1.19 */
763  /* Add localization %{?__l10ndir} sqlite3 database (if configured). */
764  if (adding)
765  xx = rpmdbExportL10N_SQL(db, h, adding);
766 #endif
767 (void)xx;
768 
769  return rc;
770 }
771 
772 /*@unchecked@*/ /*@only@*/ /*@null@*/
774 
775 static rpmdb rpmdbGetPool(/*@null@*/ rpmioPool pool)
776  /*@globals _rpmdbPool, fileSystem @*/
777  /*@modifies pool, _rpmdbPool, fileSystem @*/
778 {
779  rpmdb db;
780 
781  if (_rpmdbPool == NULL) {
782  _rpmdbPool = rpmioNewPool("db", sizeof(*db), -1, _rpmdb_debug,
783  NULL, NULL, NULL);
784  pool = _rpmdbPool;
785  }
786  db = (rpmdb) rpmioGetPool(pool, sizeof(*db));
787  memset(((char *)db)+sizeof(db->_item), 0, sizeof(*db)-sizeof(db->_item));
788  return db;
789 }
790 
792 {
793  int rc = 0;
794 
795  if (db == NULL) return -2;
796 
797  if (db->db_tags != NULL && db->_dbi != NULL) {
798  size_t dbix;
799  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
800  if ((int)db->db_tags[dbix].tag < 0)
801  continue;
802  if (db->_dbi[dbix] != NULL)
803  continue;
804  switch (db->db_tags[dbix].tag) {
805  case RPMDBI_AVAILABLE:
806  case RPMDBI_ADDED:
807  case RPMDBI_REMOVED:
808  case RPMDBI_DEPCACHE:
809  case RPMDBI_BTREE:
810  case RPMDBI_HASH:
811  case RPMDBI_QUEUE:
812  case RPMDBI_RECNO:
813  case RPMDBI_HEAP:
814  continue;
815  /*@notreached@*/ /*@switchbreak@*/ break;
816  default:
817  /*@switchbreak@*/ break;
818  }
819  (void) dbiOpen(db, db->db_tags[dbix].tag, db->db_flags);
820  }
821  }
822  return rc;
823 }
824 
825 int rpmdbBlockDBI(rpmdb db, int tag)
826 {
827  rpmTag tagn = (rpmTag)(tag >= 0 ? tag : -tag);
828  size_t dbix;
829 
830  if (db == NULL || db->_dbi == NULL)
831  return 0;
832 
833  if (db->db_tags != NULL)
834  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
835  if (db->db_tags[dbix].tag != tagn)
836  continue;
837  db->db_tags[dbix].tag = (rpmTag) tag;
838  return 0;
839  }
840  return 0;
841 }
842 
843 int rpmdbCloseDBI(rpmdb db, int tag)
844 {
845  size_t dbix;
846  int rc = 0;
847 
848  if (db == NULL || db->_dbi == NULL)
849  return 0;
850 
851  if (db->db_tags != NULL)
852  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
853  if (db->db_tags[dbix].tag != (rpmTag)tag)
854  continue;
855  if (db->_dbi[dbix] != NULL) {
856  int xx;
857  /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
858  xx = dbiClose(db->_dbi[dbix], 0);
859  if (xx && rc == 0) rc = xx;
860  db->_dbi[dbix] = NULL;
861  /*@=unqualifiedtrans@*/
862  }
863  break;
864  }
865  return rc;
866 }
867 
868 /* XXX query.c, rpminstall.c, verify.c */
869 /*@-incondefs@*/
871  /*@globals rpmdbRock @*/
872  /*@modifies rpmdbRock @*/
873 {
874  static const char msg[] = "rpmdbClose";
875  rpmdb * prev, next;
876  size_t dbix;
877  int rc = 0;
878 
879  if (db == NULL)
880  return rc;
881 
882  yarnPossess(db->_item.use);
883 /*@-modfilesys@*/
884 if (_rpmdb_debug)
885 fprintf(stderr, "--> db %p -- %ld %s at %s:%u\n", db, yarnPeekLock(db->_item.use), msg, __FILE__, __LINE__);
886 
887  /*@-usereleased@*/
888  if (yarnPeekLock(db->_item.use) <= 1L) {
889 
890  if (db->_dbi)
891  for (dbix = db->db_ndbi; dbix;) {
892  int xx;
893  dbix--;
894  if (db->_dbi[dbix] == NULL)
895  continue;
896  /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
897  xx = dbiClose(db->_dbi[dbix], 0);
898  if (xx && rc == 0) rc = xx;
899  db->_dbi[dbix] = NULL;
900  /*@=unqualifiedtrans@*/
901  }
902  db->db_errpfx = _free(db->db_errpfx);
903  db->db_root = _free(db->db_root);
904  db->db_home = _free(db->db_home);
905  db->db_tags = tagStoreFree(db->db_tags, db->db_ndbi);
906  db->_dbi = _free(db->_dbi);
907  db->db_ndbi = 0;
908 
909 /*@-newreftrans@*/
910  prev = &rpmdbRock;
911  while ((next = *prev) != NULL && next != db)
912  prev = &next->db_next;
913  if (next) {
914 /*@i@*/ *prev = next->db_next;
915  next->db_next = NULL;
916  }
917 /*@=newreftrans@*/
918 
919  if (rpmdbRock == NULL && rpmmiRock == NULL) {
920  /* Last close uninstalls special signal handling. */
921  (void) rpmsqEnable(-SIGHUP, NULL);
922  (void) rpmsqEnable(-SIGINT, NULL);
923  (void) rpmsqEnable(-SIGTERM, NULL);
924  (void) rpmsqEnable(-SIGQUIT, NULL);
925  (void) rpmsqEnable(-SIGPIPE, NULL);
926  /* Pending signals strike here. */
927  (void) rpmdbCheckSignals();
928  }
929 
930  /*@=usereleased@*/
931  db = (rpmdb)rpmioPutPool((rpmioItem)db);
932  } else
933  yarnTwist(db->_item.use, BY, -1);
934 
935  return rc;
936 }
937 /*@=incondefs@*/
938 
944 static const char * rpmdbURIPath(const char *uri)
945  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
946  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
947 {
948  const char * s = rpmGetPath(uri, NULL);
949  ARGV_t av = NULL;
950  int xx = argvSplit(&av, s, ":");
951  const char * fn = NULL;
952  /* XXX av contains a colon separated path split, use the 1st path. */
953  urltype ut = urlPath(av[0], &fn);
954 
955 xx = xx;
956 
957  switch (ut) {
958  case URL_IS_PATH:
959  case URL_IS_UNKNOWN:
960  fn = xstrdup(av[0]);
961  break;
962  case URL_IS_DASH:
963  case URL_IS_HKP:
964  case URL_IS_FTP:
965  case URL_IS_HTTP:
966  case URL_IS_HTTPS:
967  case URL_IS_MONGO: /* XXX FIXME */
968  default:
969  /* HACK: strip the URI prefix for these schemes. */
970  fn = rpmGetPath(fn, NULL);
971  break;
972  }
973 
974  /* Convert relative to absolute paths. */
975  if (ut != URL_IS_PATH) /* XXX permit file:///... URI's */
976  if (fn && *fn && *fn != '/') {
977  char dn[PATH_MAX];
978  char *t;
979  dn[0] = '\0';
980  if ((t = Realpath(".", dn)) != NULL) {
981  t += strlen(dn);
982  if (t > dn && t[-1] != '/')
983  *t++ = '/';
984  t = stpncpy(t, fn, (sizeof(dn) - (t - dn)));
985  *t = '\0';
986  fn = _free(fn);
987  fn = rpmGetPath(dn, NULL);
988  }
989  }
990 
991  av = argvFree(av);
992  s = _free(s);
993 assert(fn != NULL);
994  return fn;
995 }
996 
997 #define _DB_ROOT "/"
998 #define _DB_HOME "%{?_dbpath}"
999 #define _DB_FLAGS 0
1000 #define _DB_MODE 0
1001 #define _DB_PERMS 0644
1002 
1003 #define _DB_MAJOR 3
1004 #define _DB_ERRPFX "rpmdb"
1005 
1006 /*@-exportheader -globs -mods @*/
1007 /*@only@*/ /*@null@*/
1008 rpmdb rpmdbNew(/*@kept@*/ /*@null@*/ const char * root,
1009  /*@kept@*/ /*@null@*/ const char * home,
1010  int mode, mode_t perms, int flags)
1011  /*@*/
1012 {
1013  rpmdb db = rpmdbGetPool(_rpmdbPool);
1014  const char * epfx = _DB_ERRPFX;
1015 
1016 /*@-modfilesys@*/ /*@-nullpass@*/
1017 if (_rpmdb_debug)
1018 fprintf(stderr, "==> rpmdbNew(%s, %s, 0x%x, 0%o, 0x%x) db %p\n", root, home, mode, perms, flags, db);
1019 /*@=modfilesys@*/ /*@=nullpass@*/
1020 
1021  if (!(perms & 0600)) perms = 0644; /* XXX sanity */
1022 
1023  db->db_root = rpmdbURIPath( (root && *root ? root : _DB_ROOT) );
1024  db->db_home = rpmdbURIPath( (home && *home ? home : _DB_HOME) );
1025 
1026  if (!(db->db_home && db->db_home[0] && db->db_home[0] != '%')) {
1027  rpmlog(RPMLOG_ERR, _("no dbpath has been set\n"));
1028  db->db_root = _free(db->db_root);
1029  db->db_home = _free(db->db_home);
1030  db = (rpmdb) rpmioPutPool((rpmioItem)db);
1031  /*@-globstate@*/ return NULL; /*@=globstate@*/
1032  }
1033 
1034  db->db_flags = (flags >= 0) ? flags : _DB_FLAGS;
1035  db->db_mode = (mode >= 0) ? mode : _DB_MODE;
1036  db->db_perms = (perms > 0) ? perms : _DB_PERMS;
1037 #if defined(WITH_DB)
1038  db->db_api = _DB_MAJOR;
1039 #else
1040  /* XXX FIXME: hotwired sqlite3 if %_dbapi isn't defined */
1041  db->db_api = rpmExpandNumeric("%{?_dbapi}%{!?_dbapi:4}");
1042 #endif
1043  db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
1044 
1045  db->db_remove_env = 0;
1046  db->db_chrootDone = 0;
1047  db->db_maxkey = 0;
1048  db->db_errcall = NULL;
1049  db->db_errfile = NULL;
1050  db->db_malloc = NULL;
1051  db->db_realloc = NULL;
1052  db->db_free = NULL;
1053  db->db_export = rpmdbExportInfo;
1054  db->db_h = NULL;
1055 
1056  db->db_next = NULL;
1057  db->db_opens = 0;
1058 
1059  db->db_dbenv = NULL;
1060  db->db_txn = NULL;
1061  db->db_logc = NULL;
1062  db->db_mpf = NULL;
1063 
1064  dbiTagsInit(&db->db_tags, &db->db_ndbi);
1065  db->_dbi = (dbiIndex *) xcalloc(db->db_ndbi, sizeof(*db->_dbi));
1066 
1067  memset(&db->db_getops, 0, sizeof(db->db_getops));
1068  memset(&db->db_putops, 0, sizeof(db->db_putops));
1069  memset(&db->db_delops, 0, sizeof(db->db_delops));
1070 
1071  /*@-globstate@*/
1072  return (rpmdb) rpmdbLink(db, __FUNCTION__);
1073  /*@=globstate@*/
1074 }
1075 /*@=exportheader =globs =mods @*/
1076 
1077 static int rpmdbOpenDatabase(/*@null@*/ const char * prefix,
1078  /*@null@*/ const char * dbpath,
1079  int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp,
1080  int mode, mode_t perms, int flags)
1081  /*@globals rpmdbRock, rpmGlobalMacroContext, h_errno,
1082  fileSystem, internalState @*/
1083  /*@modifies rpmdbRock, *dbp, rpmGlobalMacroContext,
1084  fileSystem, internalState @*/
1085 {
1086  rpmdb db;
1087  int rc;
1088  int xx;
1089 
1090  /* Insure that _dbapi has one of -1, 1, 2, or 3 */
1091  if (_dbapi < -1 || _dbapi > 4)
1092  _dbapi = -1;
1093  if (_dbapi == 0)
1094  _dbapi = 1;
1095 
1096  if (dbp)
1097  *dbp = NULL;
1098  if (mode & O_WRONLY)
1099  return 1;
1100 
1101  db = rpmdbNew(prefix, dbpath, mode, perms, flags);
1102  if (db == NULL)
1103  return 1;
1104 
1105  if (rpmdbRock == NULL && rpmmiRock == NULL) {
1106  /* First open installs special signal handling. */
1107  (void) rpmsqEnable(SIGHUP, NULL);
1108  (void) rpmsqEnable(SIGINT, NULL);
1109  (void) rpmsqEnable(SIGTERM, NULL);
1110  (void) rpmsqEnable(SIGQUIT, NULL);
1111  (void) rpmsqEnable(SIGPIPE, NULL);
1112  }
1113 
1114 /*@-assignexpose -newreftrans@*/
1115 /*@i@*/ db->db_next = rpmdbRock;
1116  rpmdbRock = db;
1117 /*@=assignexpose =newreftrans@*/
1118 
1119  db->db_api = _dbapi;
1120 
1121  { size_t dbix;
1122 
1123  rc = 0;
1124  if (db->db_tags != NULL)
1125  for (dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) {
1126  tagStore_t dbiTag = db->db_tags + dbix;
1127  rpmTag tag = dbiTag->tag;
1128  dbiIndex dbi;
1129 
1130  /* Filter out temporary databases */
1131  switch (tag) {
1132  case RPMDBI_AVAILABLE:
1133  case RPMDBI_ADDED:
1134  case RPMDBI_REMOVED:
1135  case RPMDBI_DEPCACHE:
1136  continue;
1137  /*@notreached@*/ /*@switchbreak@*/ break;
1138  default:
1139  /*@switchbreak@*/ break;
1140  }
1141 
1142  dbi = dbiOpen(db, tag, 0);
1143  if (dbi == NULL) {
1144  rc = -2;
1145  break;
1146  }
1147 
1148  switch (tag) {
1149  case RPMDBI_PACKAGES:
1150  if (dbi == NULL) rc |= 1;
1151 #if 0
1152  /* XXX open only Packages, indices created on the fly. */
1153  if (db->db_api == 3)
1154 #endif
1155  goto exit;
1156  /*@notreached@*/ /*@switchbreak@*/ break;
1157  case RPMTAG_NAME:
1158  if (dbi == NULL) rc |= 1;
1159  /*@switchbreak@*/ break;
1160  default:
1161  /*@switchbreak@*/ break;
1162  }
1163  }
1164  }
1165 
1166 exit:
1167  if (rc || dbp == NULL)
1168  xx = rpmdbClose(db);
1169  else {
1170 /*@-assignexpose -newreftrans@*/
1171 /*@i@*/ *dbp = db;
1172 /*@=assignexpose =newreftrans@*/
1173  }
1174 
1175  return rc;
1176 }
1177 
1178 /* XXX python/rpmmodule.c */
1179 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, mode_t perms)
1180 {
1181  int _dbapi;
1182 #if defined(WITH_DB)
1183  _dbapi = _DB_MAJOR;
1184 #elif defined(WITH_SQLITE)
1185  _dbapi = 4; /* XXX FIXME: hotwired sqlite3 */
1186 #else
1187  _dbapi = rpmExpandNumeric("%{?_dbapi}");
1188 #endif
1189  return rpmdbOpenDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
1190 }
1191 
1192 int rpmdbCount(rpmdb db, rpmTag tag, const void * keyp, size_t keylen)
1193 {
1194  unsigned int count = 0;
1195  DBC * dbcursor = NULL;
1196  DBT k = DBT_INIT;
1197  DBT v = DBT_INIT;
1198  dbiIndex dbi;
1199  int rc;
1200  int xx;
1201 
1202  if (db == NULL || keyp == NULL)
1203  return 0;
1204 
1205  dbi = dbiOpen(db, tag, 0);
1206  if (dbi == NULL)
1207  return 0;
1208 
1209  if (keylen == 0)
1210  keylen = strlen((char *)keyp);
1211 
1212 /*@-temptrans@*/
1213  k.data = (void *) keyp;
1214 /*@=temptrans@*/
1215  k.size = (UINT32_T) keylen;
1216 
1217  xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
1218  rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
1219  switch (rc) {
1220  case 0:
1221  rc = dbiCount(dbi, dbcursor, &count, 0);
1222  if (rc != 0)
1223  rc = -1;
1224  else
1225  rc = count;
1226  break;
1227  case DB_NOTFOUND:
1228  rc = 0;
1229  break;
1230  default:
1231  rpmlog(RPMLOG_ERR, _("error(%d) getting records from %s index\n"),
1232  rc, tagName(dbi->dbi_rpmtag));
1233  rc = -1;
1234  break;
1235  }
1236  xx = dbiCclose(dbi, dbcursor, 0);
1237  dbcursor = NULL;
1238  return rc;
1239 }
1240 
1241 /* XXX python/upgrade.c, install.c, uninstall.c */
1242 int rpmdbCountPackages(rpmdb db, const char * N)
1243 {
1244  return rpmdbCount(db, RPMTAG_NAME, N, strlen(N));
1245 }
1246 
1247 /* Return pointer to first RE character (or NUL terminator) */
1248 static const char * stemEnd(const char * s)
1249  /*@*/
1250 {
1251  int c;
1252 
1253  while ((c = (int)*s)) {
1254  switch (c) {
1255  case '.':
1256  case '^':
1257  case '$':
1258  case '?':
1259  case '*':
1260  case '+':
1261  case '|':
1262  case '[':
1263  case '(':
1264  case '{':
1265  case '\0':
1266  goto exit;
1267  /*@notreached@*/ /*@switchbreak@*/ break;
1268  case '\\':
1269  s++;
1270  if (*s == '\0') goto exit;
1271  /*@fallthrough@*/
1272  default:
1273  /*@switchbreak@*/ break;
1274  }
1275  s++;
1276  }
1277 exit:
1278  return s;
1279 }
1280 
1281 /*@only@*/
1282 static const char * _str2PCREpat(/*@null@*/ const char *_pre, const char *s,
1283  /*@null@*/ const char *_post)
1284  /*@*/
1285 {
1286  static const char _REchars[] = "^.*(|)[]+?{}$";
1287  size_t nt = 0;
1288  const char * se;
1289  char * t;
1290  char * te;
1291 
1292  /* Find the PCRE pattern length, including escapes. */
1293  for (se = s; *se != '\0'; se++, nt++)
1294  if (strchr(_REchars, *se)) nt++;
1295  nt += strlen(_pre) + strlen(_post);
1296 
1297  /* Build the PCRE pattern, escaping characters as needed. */
1298  te = t = (char *) xmalloc(nt + 1);
1299  te = stpcpy(te, _pre);
1300  for (se = s; *se != '\0'; *te++ = *se++)
1301  if (strchr(_REchars, *se)) *te++ = '\\';
1302  te = stpcpy(te, _post);
1303  *te = '\0';
1304 
1305 /*@-dependenttrans@*/
1306  return t;
1307 /*@=dependenttrans@*/
1308 }
1309 
1321  /*@null@*/ const char * pat,
1322  /*@null@*/ dbiIndexSet * matches,
1323  /*@null@*/ const char *** argvp)
1324  /*@globals internalState @*/
1325  /*@modifies *matches, *argvp, internalState @*/
1326 {
1327  DBC * dbcursor = NULL;
1328  DBT k = DBT_INIT;
1329  DBT p = DBT_INIT;
1330  DBT v = DBT_INIT;
1331  dbiIndex dbi;
1332  miRE mire = NULL;
1333  uint32_t _flags = DB_NEXT;
1334  ARGV_t av = NULL;
1335  dbiIndexSet set = NULL;
1336  const char * b = NULL;
1337  size_t nb = 0;
1338  int ret = 1; /* assume error */
1339  int rc;
1340  int xx;
1341 
1342  dbi = dbiOpen(db, tag, 0);
1343  if (dbi == NULL)
1344  goto exit;
1345 
1346 if (_rpmmi_debug || dbi->dbi_debug)
1347 fprintf(stderr, "--> %s(%p, %s(%u), %d, \"%s\", %p, %p)\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, matches, argvp);
1348 
1349  if (pat) {
1350 
1351  mire = mireNew(mode, 0);
1352  xx = mireRegcomp(mire, pat);
1353 
1354  /* Initialize the secondary retrieval key. */
1355  switch (mode) {
1356  default:
1357 assert(0); /* XXX sanity */
1358  /*@notreached@*/ break;
1359  case RPMMIRE_GLOB:
1360  break;
1361  case RPMMIRE_REGEX:
1362  case RPMMIRE_PCRE:
1363  if (*pat == '^') pat++;
1364 
1365  /* If partial match on stem won't help, just iterate. */
1366  nb = stemEnd(pat) - pat;
1367  if (nb == 0) {
1368  k.doff = 0;
1369  goto doit;
1370  }
1371 
1372  /* Remove the escapes in the stem. */
1373  { char *be;
1374  b = be = (char *) xmalloc(nb + 1);
1375  while (nb--) {
1376  if ((*be = *pat++) != '\\')
1377  be++;
1378  }
1379  *be = '\0';
1380  }
1381  nb = strlen(b);
1382 
1383  /* Set stem length for partial match retrieve. */
1384  k.flags = DB_DBT_PARTIAL;
1385  k.dlen = nb;
1386  k.size = nb;
1387  k.data = (void *) b;
1388  _flags = DB_SET_RANGE;
1389  break;
1390  case RPMMIRE_STRCMP:
1391  k.size = (UINT32_T) strlen(pat);
1392  k.data = (void *) pat;
1393  _flags = DB_SET;
1394  break;
1395  }
1396  }
1397 
1398 doit:
1399  v.flags |= DB_DBT_PARTIAL;
1400 
1401  xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
1402 
1403  /* Iterate over matches, collecting primary/secondary keys. */
1404  while ((rc = dbiPget(dbi, dbcursor, &k, &p, &v, _flags)) == 0) {
1405  uint32_t hdrNum;
1406  const char * s;
1407  size_t ns;
1408 
1409  if (_flags == DB_SET) _flags = DB_NEXT_DUP;
1410  if (b != NULL && nb > 0) {
1411 
1412  /* Exit if the stem doesn't match. */
1413  if (k.size < nb || memcmp(b, k.data, nb))
1414  break;
1415 
1416  /* Retrieve the full record after DB_SET_RANGE. */
1417  if (_flags == DB_SET_RANGE) {
1418  memset (&k, 0, sizeof(k));
1419  xx = dbiPget(dbi, dbcursor, &k, &p, &v, DB_CURRENT);
1420  _flags = DB_NEXT;
1421  }
1422  }
1423 
1424  /* Get the secondary key. */
1425  s = (const char * ) k.data;
1426  ns = k.size;
1427 
1428  /* Skip if not matched. */
1429  if (mire && mireRegexec(mire, s, ns) < 0)
1430  continue;
1431 
1432  /* Get a native endian copy of the primary package key. */
1433  memcpy(&hdrNum, p.data, sizeof(hdrNum));
1434  hdrNum = _ntoh_ui(hdrNum);
1435 
1436  /* Collect primary keys. */
1437  if (matches) {
1438  if (set == NULL)
1439  set = (dbiIndexSet) xcalloc(1, sizeof(*set));
1440  /* XXX TODO: sort/uniqify set? */
1441  (void) dbiAppendSet(set, &hdrNum, 1, sizeof(hdrNum), 0);
1442  }
1443 
1444  /* Collect secondary keys. */
1445  if (argvp) {
1446  char * a = (char *) memcpy(xmalloc(ns+1), s, ns);
1447  a[ns] = '\0';
1448  xx = argvAdd(&av, a);
1449  a = _free(a);
1450  }
1451  }
1452 
1453  xx = dbiCclose(dbi, dbcursor, 0);
1454  dbcursor = NULL;
1455 
1456  switch (rc) {
1457  case 0:
1458  case DB_NOTFOUND:
1459  ret = 0;
1460  break;
1461  default:
1462  rpmlog(RPMLOG_ERR, _("error(%d) getting keys from %s index\n"),
1463  rc, tagName(dbi->dbi_rpmtag));
1464  break;
1465  }
1466 
1467 exit:
1468  if (ret == 0) {
1469  if (matches) {
1470  /* XXX TODO: sort/uniqify set? */
1471  *matches = set;
1472  set = NULL;
1473  }
1474  if (argvp)
1475  xx = argvAppend(argvp, av);
1476  }
1477  set = dbiFreeIndexSet(set);
1478  av = argvFree(av);
1479  b = _free(b);
1480  mire = mireFree(mire);
1481 if (_rpmmi_debug || (dbi && dbi->dbi_debug))
1482 fprintf(stderr, "<-- %s(%p, %s(%u), %d, %p, %p, %p) rc %d %p[%u]\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, matches, argvp, ret, (matches && *matches ? (*matches)->recs : NULL), (matches && *matches ? (*matches)->count : 0));
1483  return ret;
1484 }
1485 
1486 int rpmdbMireApply(rpmdb db, rpmTag tag, rpmMireMode mode, const char * pat,
1487  const char *** argvp)
1488 {
1489  int rc = dbiMireKeys(db, tag, mode, pat, NULL, argvp);
1490 if (_rpmmi_debug)
1491 fprintf(stderr, "<-- %s(%p, %s(%u), %d, \"%s\", %p) rc %d\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, argvp, rc);
1492  return rc;
1493 }
1494 
1495 int rpmmiGrowBasename(rpmmi mi, const char * bn)
1496 {
1497  rpmTag _tag = RPMTAG_BASENAMES;
1498  rpmMireMode _mode = RPMMIRE_STRCMP;
1499  dbiIndexSet set = NULL;
1500  unsigned int i;
1501  int rc = 1; /* assume error */
1502 
1503  if (mi == NULL || mi->mi_db == NULL || bn == NULL || *bn == '\0')
1504  goto exit;
1505 
1506 #ifdef NOTYET
1507 assert(mi->mi_rpmtag == _tag);
1508 #endif
1509  /* Retrieve set of headers that contain the base name. */
1510  rc = dbiMireKeys(mi->mi_db, _tag, _mode, bn, &set, NULL);
1511  if (rc == 0 && set != NULL) {
1512  rpmuint32_t tagNum = hashFunctionString(0, bn, 0);
1513  /* Set tagNum to the hash of the basename. */
1514  for (i = 0; i < set->count; i++)
1515  set->recs[i].tagNum = tagNum;
1516  if (mi->mi_set == NULL)
1517  mi->mi_set = (dbiIndexSet) xcalloc(1, sizeof(*mi->mi_set));
1518  (void) dbiAppendSet(mi->mi_set, set->recs, set->count, sizeof(*set->recs), 0);
1519  }
1520  rc = 0;
1521 
1522 exit:
1523 if (_rpmmi_debug)
1524 fprintf(stderr, "<-- %s(%p, \"%s\")\trc %d set %p %p[%u]\n", __FUNCTION__, mi, bn, rc, set, (set ? set->recs : NULL), (unsigned)(set ? set->count : 0));
1525  set = dbiFreeIndexSet(set);
1526  return rc;
1527 }
1528 
1537  const char * pat, /*@out@*/ dbiIndexSet * matches)
1538  /*@*/
1539 {
1540  const char * s = pat;
1541  size_t ns = (s ? strlen(s) : 0);
1542  DBC * dbcursor = NULL;
1543  rpmRC rc = RPMRC_NOTFOUND;
1544  int ret;
1545  int xx;
1546 
1547  if (ns == 0) goto exit;
1548 
1549  xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
1550 
1551  /* Add ^...$ *RE anchors. Escape pattern characters. */
1552  { rpmTag tag = dbi->dbi_rpmtag;
1554  static const char _post_NVRA[] = "(-[^-]+-[^-]+\\.[^.]+|-[^-]+\\.[^.]+|\\.[^.]+|)$";
1555  const char * _pat;
1556 
1557  switch (tag) {
1558  default:
1559  mode = RPMMIRE_PCRE;
1560  _pat = _str2PCREpat("^", s, ".*$");
1561  break;
1562  case RPMTAG_NVRA:
1563  mode = RPMMIRE_PCRE;
1564  _pat = (s[0] == '^' || s[ns-1] == '$')
1565  ? xstrdup(s)
1566  : _str2PCREpat("^", s, _post_NVRA);
1567  break;
1568  case RPMTAG_FILEPATHS:
1569  if (s[0] == '^' || s[ns-1] == '$')
1570  mode = RPMMIRE_PCRE;
1571  else
1572 #ifdef NOTYET
1573  if (s[0] == '/' && Glob_pattern_p(s, 1))
1574  mode = RPMMIRE_GLOB;
1575  else
1576 #endif
1577  mode = RPMMIRE_STRCMP;
1578  _pat = xstrdup(s);
1579  break;
1580  }
1581 
1582  ret = dbiMireKeys(dbi->dbi_rpmdb, tag, mode, _pat, matches, NULL);
1583 
1584  _pat = _free(_pat);
1585  }
1586 
1587  switch (ret) {
1588  case 0: rc = RPMRC_OK; break;
1589  case DB_NOTFOUND: rc = RPMRC_NOTFOUND; break;
1590  default: rc = RPMRC_FAIL;
1591  rpmlog(RPMLOG_ERR, _("error(%d) getting records from %s index\n"),
1592  ret, tagName(dbi->dbi_rpmtag));
1593  break;
1594  }
1595 
1596  xx = dbiCclose(dbi, dbcursor, 0);
1597  dbcursor = NULL;
1598 
1599 exit:
1600 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1601  if (rc != RPMRC_OK && matches && *matches)
1602  *matches = dbiFreeIndexSet(*matches);
1603 /*@=unqualifiedtrans@*/
1604  return rc;
1605 }
1606 
1607 void * dbiStatsAccumulator(dbiIndex dbi, int opx)
1608 {
1609  void * sw = NULL;
1610  switch (opx) {
1611  case 14: /* RPMTS_OP_DBGET */
1612  sw = &dbi->dbi_rpmdb->db_getops;
1613  break;
1614  case 15: /* RPMTS_OP_DBPUT */
1615  sw = &dbi->dbi_rpmdb->db_putops;
1616  break;
1617  default: /* XXX wrong, but let's not return NULL. */
1618  case 16: /* RPMTS_OP_DBDEL */
1619  sw = &dbi->dbi_rpmdb->db_delops;
1620  break;
1621  }
1622  return sw;
1623 }
1624 
1633 static int miFreeHeader(rpmmi mi, dbiIndex dbi)
1634  /*@globals fileSystem, internalState @*/
1635  /*@modifies mi, dbi, fileSystem, internalState @*/
1636 {
1637  int rc = 0;
1638 
1639  if (mi == NULL || mi->mi_h == NULL)
1640  return 0;
1641 
1642  if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
1643  DBT k = DBT_INIT;
1644  DBT v = DBT_INIT;
1645  int xx;
1646 
1647 /*@i@*/ k.data = (void *) &mi->mi_prevoffset;
1648  k.size = (UINT32_T) sizeof(mi->mi_prevoffset);
1649  { size_t len = 0;
1650  v.data = headerUnload(mi->mi_h, &len);
1651  v.size = (UINT32_T) len;
1652  }
1653 
1654  if (v.data != NULL) {
1655  sigset_t signalMask;
1656  (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
1657  rc = dbiPut(dbi, mi->mi_dbc, &k, &v, DB_KEYLAST);
1658  if (rc) {
1660  _("error(%d) storing record h#%u into %s\n"),
1661  rc, (unsigned)_ntoh_ui(mi->mi_prevoffset),
1662  tagName(dbi->dbi_rpmtag));
1663  }
1664  xx = dbiSync(dbi, 0);
1665  (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
1666  }
1667  v.data = _free(v.data); /* headerUnload */
1668  v.size = 0;
1669  }
1670 
1671  (void)headerFree(mi->mi_h);
1672  mi->mi_h = NULL;
1673 
1674 /*@-nullstate@*/
1675  return rc;
1676 /*@=nullstate@*/
1677 }
1678 
1679 static void rpmmiFini(void * _mi)
1680  /*@globals rpmmiRock @*/
1681  /*@modifies _mi, rpmmiRock @*/
1682 {
1683  rpmmi mi = (rpmmi) _mi;
1684  rpmmi * prev, next;
1685  dbiIndex dbi;
1686  int xx;
1687 
1688  prev = &rpmmiRock;
1689  while ((next = *prev) != NULL && next != mi)
1690  prev = &next->mi_next;
1691  if (next) {
1692 /*@i@*/ *prev = next->mi_next;
1693  next->mi_next = NULL;
1694  }
1695 
1696  /* XXX NOTFOUND exits traverse here w mi->mi_db == NULL. b0rked imho. */
1697  if (mi->mi_db) {
1698  dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
1699 assert(dbi != NULL); /* XXX sanity */
1700 
1701  xx = miFreeHeader(mi, dbi);
1702 
1703  if (mi->mi_dbc)
1704  xx = dbiCclose(dbi, mi->mi_dbc, 0);
1705  mi->mi_dbc = NULL;
1706  /* XXX rpmdbUnlink will not do.
1707  * NB: must be called after rpmmiRock cleanup.
1708  */
1709  (void) rpmdbClose(mi->mi_db);
1710  mi->mi_db = NULL;
1711  }
1712 
1713  (void) mireFreeAll(mi->mi_re, mi->mi_nre);
1714  mi->mi_re = NULL;
1715 
1716  (void) rpmbfFree(mi->mi_bf);
1717  mi->mi_bf = NULL;
1718  mi->mi_set = dbiFreeIndexSet(mi->mi_set);
1719 
1720  mi->mi_keyp = _free(mi->mi_keyp);
1721  mi->mi_keylen = 0;
1722  mi->mi_primary = _free(mi->mi_primary);
1723 
1724  /* XXX this needs to be done elsewhere, not within destructor. */
1725  (void) rpmdbCheckSignals();
1726 }
1727 
1728 /*@unchecked@*/ /*@only@*/ /*@null@*/
1730 
1731 static rpmmi rpmmiGetPool(/*@null@*/ rpmioPool pool)
1732  /*@globals _rpmdbPool, fileSystem @*/
1733  /*@modifies pool, _rpmdbPool, fileSystem @*/
1734 {
1735  rpmmi mi;
1736 
1737  if (_rpmmiPool == NULL) {
1738  _rpmmiPool = rpmioNewPool("mi", sizeof(*mi), -1, _rpmmi_debug,
1739  NULL, NULL, rpmmiFini);
1740  pool = _rpmmiPool;
1741  }
1742  mi = (rpmmi) rpmioGetPool(pool, sizeof(*mi));
1743  memset(((char *)mi)+sizeof(mi->_item), 0, sizeof(*mi)-sizeof(mi->_item));
1744  return mi;
1745 }
1746 
1747 uint32_t rpmmiInstance(rpmmi mi)
1748 {
1749  /* Get a native endian copy of the primary package key. */
1750  uint32_t rc = _ntoh_ui(mi ? mi->mi_offset : 0);
1751 if (_rpmmi_debug)
1752 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc);
1753  return rc;
1754 }
1755 
1756 uint32_t rpmmiBNTag(rpmmi mi) {
1757  uint32_t rc = (mi ? mi->mi_bntag : 0);
1758 if (_rpmmi_debug)
1759 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc);
1760  return rc;
1761 }
1762 
1763 unsigned int rpmmiCount(rpmmi mi)
1764 {
1765  unsigned int rc;
1766  int initDbc;
1767 
1768  /* XXX Secondary db associated with Packages needs cursor record count */
1769  if (mi && mi->mi_primary && ((initDbc = mi->mi_dbc == NULL) || mi->mi_count == 0)) {
1770  dbiIndex dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
1771  DBT k = DBT_INIT;
1772  DBT v = DBT_INIT;
1773  int xx;
1774  if(initDbc) {
1775 assert(dbi != NULL); /* XXX dbiCopen doesn't handle dbi == NULL */
1776  xx = dbiCopen(dbi, dbiTxnid(dbi), &mi->mi_dbc, mi->mi_cflags);
1777  }
1778  k.data = mi->mi_keyp;
1779  k.size = (u_int32_t)mi->mi_keylen;
1780 if (k.data && k.size == 0) k.size = (UINT32_T) strlen((char *)k.data);
1781 if (k.data && k.size == 0) k.size++; /* XXX "/" fixup. */
1782  if (!dbiGet(dbi, mi->mi_dbc, &k, &v, DB_SET))
1783  xx = dbiCount(dbi, mi->mi_dbc, &mi->mi_count, 0);
1784  if(initDbc)
1785  mi->mi_dbc = NULL;
1786  }
1787 
1788  rc = (mi ? mi->mi_count : 0);
1789 
1790 if (_rpmmi_debug)
1791 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc);
1792  return rc;
1793 }
1794 
1801 static int mireCmp(const void * a, const void * b)
1802 {
1803 /*@-castexpose @*/
1804  const miRE mireA = (const miRE) a;
1805  const miRE mireB = (const miRE) b;
1806 /*@=castexpose @*/
1807  return (mireA->tag - mireB->tag);
1808 }
1809 
1817 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep,
1818  const char * pattern)
1819  /*@modifies *modep @*/
1820  /*@requires maxSet(modep) >= 0 @*/
1821 {
1822  const char * s;
1823  char * pat;
1824  char * t;
1825  int brackets;
1826  size_t nb;
1827  int c;
1828 
1829  switch (*modep) {
1830  default:
1831  case RPMMIRE_DEFAULT:
1832  if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES
1833  || tag == RPMTAG_FILEPATHS)
1834  {
1835  *modep = RPMMIRE_GLOB;
1836  pat = xstrdup(pattern);
1837  break;
1838  }
1839 
1840  nb = strlen(pattern) + sizeof("^$");
1841 
1842  /* Find no. of bytes needed for pattern. */
1843  /* periods and plusses are escaped, splats become '.*' */
1844  c = (int) '\0';
1845  brackets = 0;
1846  for (s = pattern; *s != '\0'; s++) {
1847  switch (*s) {
1848  case '.':
1849  case '+':
1850  case '*':
1851  if (!brackets) nb++;
1852  /*@switchbreak@*/ break;
1853  case '\\':
1854  s++;
1855  /*@switchbreak@*/ break;
1856  case '[':
1857  brackets = 1;
1858  /*@switchbreak@*/ break;
1859  case ']':
1860  if (c != (int) '[') brackets = 0;
1861  /*@switchbreak@*/ break;
1862  }
1863  c = (int) *s;
1864  }
1865 
1866  pat = t = (char *) xmalloc(nb);
1867 
1868  if (pattern[0] != '^') *t++ = '^';
1869 
1870  /* Copy pattern, escaping periods, prefixing splats with period. */
1871  c = (int) '\0';
1872  brackets = 0;
1873  for (s = pattern; *s != '\0'; s++, t++) {
1874  switch (*s) {
1875  case '.':
1876  case '+':
1877  if (!brackets) *t++ = '\\';
1878  /*@switchbreak@*/ break;
1879  case '*':
1880  if (!brackets) *t++ = '.';
1881  /*@switchbreak@*/ break;
1882  case '\\':
1883  *t++ = *s++;
1884  /*@switchbreak@*/ break;
1885  case '[':
1886  brackets = 1;
1887  /*@switchbreak@*/ break;
1888  case ']':
1889  if (c != (int) '[') brackets = 0;
1890  /*@switchbreak@*/ break;
1891  }
1892  *t = *s;
1893  c = (int) *t;
1894  }
1895 
1896  if (s > pattern && s[-1] != '$') *t++ = '$';
1897  *t = '\0';
1898  *modep = RPMMIRE_REGEX;
1899  break;
1900  case RPMMIRE_STRCMP:
1901  case RPMMIRE_REGEX:
1902  case RPMMIRE_GLOB:
1903  pat = xstrdup(pattern);
1904  break;
1905  }
1906 
1907  return pat;
1908 }
1909 
1911  rpmMireMode mode, const char * pattern)
1912 {
1913  static rpmMireMode defmode = (rpmMireMode)-1;
1914  miRE nmire = NULL;
1915  miRE mire = NULL;
1916  const char * allpat = NULL;
1917  int notmatch = 0;
1918  int rc = 0;
1919 
1920  if (defmode == (rpmMireMode)-1) {
1921  const char *t = rpmExpand("%{?_query_selector_match}", NULL);
1922 
1923  if (*t == '\0' || !strcmp(t, "default"))
1924  defmode = RPMMIRE_DEFAULT;
1925  else if (!strcmp(t, "strcmp"))
1926  defmode = RPMMIRE_STRCMP;
1927  else if (!strcmp(t, "regex"))
1928  defmode = RPMMIRE_REGEX;
1929  else if (!strcmp(t, "glob"))
1930  defmode = RPMMIRE_GLOB;
1931  else
1932  defmode = RPMMIRE_DEFAULT;
1933  t = _free(t);
1934  }
1935 
1936  if (mi == NULL || pattern == NULL)
1937  return rc;
1938 
1939  /* Leading '!' inverts pattern match sense, like "grep -v". */
1940  if (*pattern == '!') {
1941  notmatch = 1;
1942  pattern++;
1943  }
1944 
1945  nmire = mireNew(mode, tag);
1946 assert(nmire != NULL);
1947  allpat = mireDup((rpmTag)nmire->tag, &nmire->mode, pattern);
1948 
1949  if (nmire->mode == RPMMIRE_DEFAULT)
1950  nmire->mode = defmode;
1951 
1952  rc = mireRegcomp(nmire, allpat);
1953  if (rc)
1954  goto exit;
1955 
1956  if (mi->mi_re == NULL) {
1957  mi->mi_re = mireGetPool(_mirePool);
1958  mire = mireLink(mi->mi_re);
1959  } else {
1960  yarnLock use = mi->mi_re->_item.use;
1961  void *pool = mi->mi_re->_item.pool;
1962  mi->mi_re = (miRE) xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
1963 if (_mire_debug)
1964 fprintf(stderr, " mire %p[%u] realloc\n", mi->mi_re, mi->mi_nre+1);
1965  mire = mi->mi_re + mi->mi_nre;
1966  memset(mire, 0, sizeof(*mire));
1967  /* XXX ensure no segfault, copy the use/pool from 1st item. */
1968 /*@-assignexpose@*/
1969  mire->_item.use = use;
1970  mire->_item.pool = pool;
1971 /*@=assignexpose@*/
1972  }
1973  mi->mi_nre++;
1974 
1975  mire->mode = nmire->mode;
1976  mire->pattern = nmire->pattern; nmire->pattern = NULL;
1977  mire->preg = nmire->preg; nmire->preg = NULL;
1978  mire->cflags = nmire->cflags;
1979  mire->eflags = nmire->eflags;
1980  mire->fnflags = nmire->fnflags;
1981  mire->tag = nmire->tag;
1982  mire->notmatch = notmatch;
1983  /* XXX todo: permit PCRE patterns to be used. */
1984  mire->offsets = NULL;
1985  mire->noffsets = 0;
1986 
1987  if (mi->mi_nre > 1)
1988  qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
1989 
1990 exit:
1991 if (_rpmmi_debug)
1992 fprintf(stderr, "<-- %s(%p, %u(%s), %u, \"%s\") rc %d mi_re %p[%u]\n", __FUNCTION__, mi, (unsigned)tag, tagName(tag), (unsigned)mode, pattern, rc, (mi ? mi->mi_re: NULL), (unsigned)(mi ? mi->mi_nre : 0));
1993  allpat = _free(allpat);
1994  nmire = mireFree(nmire);
1995  return rc;
1996 }
1997 
2003 static inline unsigned char nibble(char c)
2004  /*@*/
2005 {
2006  if (c >= '0' && c <= '9')
2007  return (unsigned char)(c - '0');
2008  if (c >= 'A' && c <= 'F')
2009  return (unsigned char)((int)(c - 'A') + 10);
2010  if (c >= 'a' && c <= 'f')
2011  return (unsigned char)((int)(c - 'a') + 10);
2012  return '\0';
2013 }
2014 
2021 /*@only@*/
2022 static char * bin2hex(const void *data, size_t size)
2023  /*@*/
2024 {
2025  static char hex[] = "0123456789abcdef";
2026  const char * s = (const char *) data;
2027  char * t, * val;
2028  val = t = (char *) xmalloc(size * 2 + 1);
2029  while (size-- > 0) {
2030  unsigned i;
2031  i = (unsigned) *s++;
2032  *t++ = hex[ (i >> 4) & 0xf ];
2033  *t++ = hex[ (i ) & 0xf ];
2034  }
2035  *t = '\0';
2036 
2037  return val;
2038 }
2039 
2045 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */
2046 static int mireSkip (const rpmmi mi)
2047  /*@globals internalState @*/
2048  /*@modifies mi->mi_re, internalState @*/
2049 {
2050  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2051  char numbuf[32];
2052  miRE mire;
2053  int ntags = 0;
2054  int nmatches = 0;
2055  int i;
2056  int rc;
2057 
2058  if (mi->mi_h == NULL) /* XXX can't happen */
2059  return 1;
2060 
2061  /*
2062  * Apply tag tests, implicitly "||" for multiple patterns/values of a
2063  * single tag, implicitly "&&" between multiple tag patterns.
2064  */
2065  if ((mire = mi->mi_re) == NULL)
2066  return 0;
2067 
2068  for (i = 0; i < mi->mi_nre; i++, mire++) {
2069  int anymatch;
2070 
2071  he->tag = (rpmTag) mire->tag;
2072 
2073  if (!headerGet(mi->mi_h, he, 0)) {
2074  if (he->tag != RPMTAG_EPOCH) {
2075  ntags++;
2076  continue;
2077  }
2078  he->t = RPM_UINT32_TYPE;
2079  he->p.ui32p = (rpmuint32_t *) xcalloc(1, sizeof(*he->p.ui32p));
2080  he->c = 1;
2081  }
2082 
2083  anymatch = 0; /* no matches yet */
2084  while (1) {
2085  unsigned j;
2086  switch (he->t) {
2087  case RPM_UINT8_TYPE:
2088  for (j = 0; j < (unsigned) he->c; j++) {
2089  sprintf(numbuf, "%u", (unsigned) he->p.ui8p[j]);
2090  rc = mireRegexec(mire, numbuf, 0);
2091  if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2092  anymatch++;
2093  }
2094  /*@switchbreak@*/ break;
2095  case RPM_UINT16_TYPE:
2096  for (j = 0; j < (unsigned) he->c; j++) {
2097  sprintf(numbuf, "%u", (unsigned) he->p.ui16p[j]);
2098  rc = mireRegexec(mire, numbuf, 0);
2099  if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2100  anymatch++;
2101  }
2102  /*@switchbreak@*/ break;
2103  case RPM_UINT32_TYPE:
2104  for (j = 0; j < (unsigned) he->c; j++) {
2105  sprintf(numbuf, "%u", (unsigned) he->p.ui32p[j]);
2106  rc = mireRegexec(mire, numbuf, 0);
2107  if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2108  anymatch++;
2109  }
2110  /*@switchbreak@*/ break;
2111  case RPM_UINT64_TYPE:
2112 /*@-duplicatequals@*/
2113  for (j = 0; j < (unsigned) he->c; j++) {
2114  sprintf(numbuf, "%llu", (unsigned long long)he->p.ui64p[j]);
2115  rc = mireRegexec(mire, numbuf, 0);
2116  if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2117  anymatch++;
2118  }
2119 /*@=duplicatequals@*/
2120  /*@switchbreak@*/ break;
2121  case RPM_STRING_TYPE:
2122  rc = mireRegexec(mire, he->p.str, 0);
2123  if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2124  anymatch++;
2125  /*@switchbreak@*/ break;
2126  case RPM_STRING_ARRAY_TYPE:
2127  for (j = 0; j < (unsigned) he->c; j++) {
2128  rc = mireRegexec(mire, he->p.argv[j], 0);
2129  if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) {
2130  anymatch++;
2131  /*@innerbreak@*/ break;
2132  }
2133  }
2134  /*@switchbreak@*/ break;
2135  case RPM_BIN_TYPE:
2136  { const char * s;
2137 assert(he->p.ptr != NULL);
2138  s = bin2hex(he->p.ptr, he->c);
2139  rc = mireRegexec(mire, s, 0);
2140  if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2141  anymatch++;
2142  s = _free(s);
2143  } /*@switchbreak@*/ break;
2144  case RPM_I18NSTRING_TYPE:
2145 #if !defined(SUPPORT_I18NSTRING_TYPE)
2146 assert(0);
2147 #endif
2148  default:
2149  /*@switchbreak@*/ break;
2150  }
2151  if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
2152  i++;
2153  mire++;
2154  /*@innercontinue@*/ continue;
2155  }
2156  /*@innerbreak@*/ break;
2157  }
2158 
2159  he->p.ptr = _free(he->p.ptr);
2160 
2161  if (anymatch)
2162  nmatches++;
2163  ntags++;
2164  }
2165 
2166  return (ntags > 0 && ntags == nmatches ? 0 : 1);
2167 }
2168 /*@=onlytrans@*/
2169 
2170 int rpmmiSetRewrite(rpmmi mi, int rewrite)
2171 {
2172  int rc;
2173  if (mi == NULL)
2174  return 0;
2175  rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
2176  if (rewrite)
2177  mi->mi_cflags |= DB_WRITECURSOR;
2178  else
2179  mi->mi_cflags &= ~DB_WRITECURSOR;
2180  return rc;
2181 }
2182 
2183 int rpmmiSetModified(rpmmi mi, int modified)
2184 {
2185  int rc;
2186  if (mi == NULL)
2187  return 0;
2188  rc = mi->mi_modified;
2189  mi->mi_modified = modified;
2190  return rc;
2191 }
2192 
2193 /*@unchecked@*/
2194 static int _rpmmi_usermem = 1;
2195 
2196 static int rpmmiGet(dbiIndex dbi, DBC * dbcursor, DBT * kp, DBT * pk, DBT * vp,
2197  unsigned int flags)
2198  /*@globals internalState @*/
2199  /*@modifies dbi, dbcursor, *kp, *pk, *vp, internalState @*/
2200 {
2201  int map;
2202  int rc;
2203 
2204  switch (dbi->dbi_rpmdb->db_api) {
2205  default: map = 0; break;
2206  case 3: map = _rpmmi_usermem; break; /* Berkeley DB */
2207  }
2208 
2209  if (map) {
2210  static const int _prot = PROT_READ | PROT_WRITE;
2211  static const int _flags = MAP_PRIVATE| MAP_ANONYMOUS;
2212  static const int _fdno = -1;
2213  static const off_t _off = 0;
2214 
2215  memset(vp, 0, sizeof(*vp));
2216  vp->flags |= DB_DBT_USERMEM;
2217  rc = dbiGet(dbi, dbcursor, kp, vp, flags);
2218  if (rc == DB_BUFFER_SMALL) {
2219  size_t uhlen = vp->size;
2220  void * uh = mmap(NULL, uhlen, _prot, _flags, _fdno, _off);
2221  if (uh == NULL || uh == (void *)-1)
2222  fprintf(stderr,
2223  "==> mmap(%p[%u], 0x%x, 0x%x, %d, 0x%x) error(%d): %s\n",
2224  NULL, (unsigned)uhlen, _prot, _flags, _fdno, (unsigned)_off,
2225  errno, strerror(errno));
2226 
2227  vp->ulen = (u_int32_t)uhlen;
2228  vp->data = uh;
2229  if (dbi->dbi_primary && pk)
2230  rc = dbiPget(dbi, dbcursor, kp, pk, vp, flags);
2231  else
2232  rc = dbiGet(dbi, dbcursor, kp, vp, flags);
2233  if (rc == 0) {
2234  if (mprotect(uh, uhlen, PROT_READ) != 0)
2235  fprintf(stderr, "==> mprotect(%p[%u],0x%x) error(%d): %s\n",
2236  uh, (unsigned)uhlen, PROT_READ,
2237  errno, strerror(errno));
2238  } else {
2239  if (munmap(uh, uhlen) != 0)
2240  fprintf(stderr, "==> munmap(%p[%u]) error(%d): %s\n",
2241  uh, (unsigned)uhlen, errno, strerror(errno));
2242  }
2243  }
2244  } else
2245  rc = dbiGet(dbi, dbcursor, kp, vp, flags);
2246 if (_rpmmi_debug || dbi->dbi_debug)
2247 fprintf(stderr, "<-- %s(%p(%s),%p,%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbcursor, kp, vp, flags, rc);
2248 
2249  return rc;
2250 }
2251 
2253 {
2254  dbiIndex dbi;
2255  DBT k = DBT_INIT;
2256  DBT p = DBT_INIT;
2257  DBT v = DBT_INIT;
2258  void * uh;
2259  size_t uhlen;
2260 rpmTag tag;
2261 unsigned int _flags;
2262  int map;
2263  int rc;
2264  int xx;
2265 
2266  if (mi == NULL)
2267  return NULL;
2268 
2269  /* Find the tag to open. */
2270  tag = (mi->mi_set == NULL && mi->mi_primary != NULL
2271  ? mi->mi_rpmtag : RPMDBI_PACKAGES);
2272  dbi = dbiOpen(mi->mi_db, tag, 0);
2273  if (dbi == NULL)
2274  return NULL;
2275 
2276  switch (dbi->dbi_rpmdb->db_api) {
2277  default: map = 0; break;
2278  case 3: map = _rpmmi_usermem; break; /* Berkeley DB */
2279  }
2280 
2281 if (_rpmmi_debug || dbi->dbi_debug)
2282 fprintf(stderr, "--> %s(%p) dbi %p(%s)\n", __FUNCTION__, mi, dbi, tagName(tag));
2283 
2284  /*
2285  * Cursors are per-iterator, not per-dbi, so get a cursor for the
2286  * iterator on 1st call. If the iteration is to rewrite headers, and the
2287  * CDB model is used for the database, then the cursor needs to
2288  * marked with DB_WRITECURSOR as well.
2289  */
2290  if (mi->mi_dbc == NULL) {
2291  xx = dbiCopen(dbi, dbiTxnid(dbi), &mi->mi_dbc, mi->mi_cflags);
2292  k.data = mi->mi_keyp;
2293  k.size = (u_int32_t)mi->mi_keylen;
2294 if (k.data && k.size == 0) k.size = (UINT32_T) strlen((char *)k.data);
2295 if (k.data && k.size == 0) k.size++; /* XXX "/" fixup. */
2296  _flags = DB_SET;
2297  } else
2298  _flags = (mi->mi_setx ? DB_NEXT_DUP : DB_SET);
2299 
2300 next:
2301  if (mi->mi_set) {
2302  /* The set of header instances is known in advance. */
2303  if (!(mi->mi_setx < mi->mi_set->count))
2304  return NULL;
2307  mi->mi_setx++;
2308 
2309  /* If next header is identical, return it now. */
2310  if (mi->mi_offset == mi->mi_prevoffset && mi->mi_h != NULL)
2311  return mi->mi_h;
2312 
2313  /* Should this header be skipped? */
2314  if (mi->mi_bf != NULL
2315  && rpmbfChk(mi->mi_bf, &mi->mi_offset, sizeof(mi->mi_offset)) > 0)
2316  goto next;
2317 
2318  /* Fetch header by offset. */
2319  k.data = &mi->mi_offset;
2320  k.size = (UINT32_T)sizeof(mi->mi_offset);
2321  rc = rpmmiGet(dbi, mi->mi_dbc, &k, NULL, &v, DB_SET);
2322  }
2323  else if (dbi->dbi_primary) {
2324  rc = rpmmiGet(dbi, mi->mi_dbc, &k, &p, &v, _flags);
2325  switch (rc) {
2326  default:
2327 assert(0);
2328  /*@notreached@*/ break;
2329  case DB_NOTFOUND:
2330  return NULL;
2331  /*@notreached@*/ break;
2332  case 0:
2333  mi->mi_setx++;
2334 assert((size_t)p.size == sizeof(mi->mi_offset));
2335  memcpy(&mi->mi_offset, p.data, sizeof(mi->mi_offset));
2336  /* If next header is identical, return it now. */
2337  if (mi->mi_offset == mi->mi_prevoffset && mi->mi_h != NULL)
2338  return mi->mi_h;
2339  break;
2340  }
2341  _flags = DB_NEXT_DUP;
2342  }
2343  else {
2344  /* Iterating Packages database. */
2345 assert(mi->mi_rpmtag == RPMDBI_PACKAGES);
2346 
2347  /* Fetch header with DB_NEXT. */
2348  /* Instance 0 is the largest header instance in legacy databases,
2349  * and must be skipped. */
2350  do {
2351  rc = rpmmiGet(dbi, mi->mi_dbc, &k, NULL, &v, DB_NEXT);
2352  if (rc == 0) {
2353 assert((size_t)k.size == sizeof(mi->mi_offset));
2354  memcpy(&mi->mi_offset, k.data, sizeof(mi->mi_offset));
2355  }
2356  } while (rc == 0 && mi->mi_offset == 0);
2357  }
2358 
2359  /* Did the header blob load correctly? */
2360  if (rc)
2361  return NULL;
2362 
2363  /* Should this header be skipped? */
2364  if (mi->mi_set == NULL && mi->mi_bf != NULL
2365  && rpmbfChk(mi->mi_bf, &mi->mi_offset, sizeof(mi->mi_offset)) > 0)
2366  goto next;
2367 
2368  uh = v.data;
2369  uhlen = v.size;
2370  if (uh == NULL)
2371  return NULL;
2372 
2373  /* Rewrite current header (if necessary) and unlink. */
2374  xx = miFreeHeader(mi, dbi);
2375 
2376  if (map) {
2377 /*@-onlytrans@*/
2378  mi->mi_h = headerLoad(uh);
2379 /*@=onlytrans@*/
2380  if (mi->mi_h) {
2381  mi->mi_h->flags |= HEADERFLAG_MAPPED;
2382  mi->mi_h->flags |= HEADERFLAG_RDONLY;
2383  }
2384  } else
2385  mi->mi_h = headerCopyLoad(uh);
2386 
2387  if (mi->mi_h == NULL) {
2389  _("rpmdb: header #%u cannot be loaded -- skipping.\n"),
2390  (unsigned)_ntoh_ui(mi->mi_offset));
2391  /* damaged header should not be reused */
2392  if (mi->mi_h) {
2393  (void)headerFree(mi->mi_h);
2394  mi->mi_h = NULL;
2395  }
2396  /* TODO: skip more mi_set records */
2397  goto next;
2398  }
2399 
2400  /* Skip this header if iterator selector (if any) doesn't match. */
2401  if (mireSkip(mi))
2402  goto next;
2403 
2404  /* Mark header with its instance number. */
2405  { char origin[32];
2406  uint32_t hdrNum = _ntoh_ui(mi->mi_offset);
2407  sprintf(origin, "rpmdb (h#%u)", (unsigned)hdrNum);
2408  (void) headerSetOrigin(mi->mi_h, origin);
2409  (void) headerSetInstance(mi->mi_h, hdrNum);
2410  }
2411 
2412  mi->mi_prevoffset = mi->mi_offset;
2413  mi->mi_modified = 0;
2414 
2415 /*@-compdef -retalias -retexpose -usereleased @*/
2416  return mi->mi_h;
2417 /*@=compdef =retalias =retexpose =usereleased @*/
2418 }
2419 
2421 {
2422  int rc = 0;
2423 
2424  if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
2425  /*
2426  * mergesort is much (~10x with lots of identical basenames) faster
2427  * than pure quicksort, but glibc uses msort_with_tmp() on stack.
2428  */
2429  if (mi->mi_set->count > 1) {
2430 #if defined(__GLIBC__)
2431  qsort(mi->mi_set->recs, mi->mi_set->count,
2432  sizeof(*mi->mi_set->recs), hdrNumCmp);
2433 #else
2434  rpm_mergesort(mi->mi_set->recs, mi->mi_set->count,
2435  sizeof(*mi->mi_set->recs), hdrNumCmp);
2436 #endif
2437  }
2438  mi->mi_sorted = 1;
2439 #ifdef NOTNOW
2440  { struct _dbiIndexItem * rec;
2441  int i;
2442  for (i = 0, rec = mi->mi_set->recs; i < mi->mi_set->count; i++, rec++) {
2443  fprintf(stderr, "\t%p[%u] = %p: %u %u %u\n", mi->mi_set->recs,
2444  i, rec, rec->hdrNum, rec->tagNum, rec->fpNum);
2445  }
2446  }
2447 #endif
2448  }
2449  return rc;
2450 }
2451 
2452 /* XXX TODO: a Bloom Filter on removed packages created once, not each time. */
2453 int rpmmiPrune(rpmmi mi, uint32_t * hdrNums, int nHdrNums, int sorted)
2454 {
2455  int rc = (mi == NULL || hdrNums == NULL || nHdrNums <= 0);
2456 
2457  if (!rc) {
2458  int i;
2459  if (mi->mi_bf == NULL) {
2460  static size_t nRemoves = 2 * 8192; /* XXX population estimate */
2461  static double e = 1.0e-4;
2462  size_t m = 0;
2463  size_t k = 0;
2464  rpmbfParams(nRemoves, e, &m, &k);
2465  mi->mi_bf = rpmbfNew(m, k, 0);
2466  }
2467  for (i = 0; i < nHdrNums; i++) {
2468  uint32_t mi_offset = _hton_ui(hdrNums[i]);
2469  int xx = rpmbfAdd(mi->mi_bf, &mi_offset, sizeof(mi_offset));
2470 assert(xx == 0);
2471  }
2472  }
2473 
2474 if (_rpmmi_debug)
2475 fprintf(stderr, "<-- %s(%p, %p[%u], %d) rc %d h# %u\n", __FUNCTION__, mi, hdrNums, (unsigned)nHdrNums, sorted, rc, (unsigned) (hdrNums ? hdrNums[0] : 0));
2476  return rc;
2477 }
2478 
2479 int rpmmiGrow(rpmmi mi, const uint32_t * hdrNums, int nHdrNums)
2480 {
2481  int rc = (mi == NULL || hdrNums == NULL || nHdrNums <= 0);
2482 
2483  if (!rc) {
2484  if (mi->mi_set == NULL)
2485  mi->mi_set = (dbiIndexSet) xcalloc(1, sizeof(*mi->mi_set));
2486  (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
2487  }
2488 
2489 if (_rpmmi_debug)
2490 fprintf(stderr, "<-- %s(%p, %p[%u]) rc %d h# %u\n", __FUNCTION__, mi, hdrNums, (unsigned)nHdrNums, rc, (unsigned) (hdrNums ? hdrNums[0] : 0));
2491  return rc;
2492 }
2493 
2494 /*@-dependenttrans -exposetrans -globstate @*/
2495 rpmmi rpmmiInit(rpmdb db, rpmTag tag, const void * keyp, size_t keylen)
2496 {
2497  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2498  rpmmi mi = NULL;
2499  dbiIndexSet set = NULL;
2500  dbiIndex dbi = NULL;
2501  int usePatterns = 0;
2502 
2503  if (db == NULL)
2504  goto exit;
2505 
2506  (void) rpmdbCheckSignals();
2507 
2508  /* XXX Control for whether patterns are permitted. */
2509  switch (tag) {
2510  default: break;
2511  case 2: /* XXX HACK to remove RPMDBI_LABEL from RPM. */
2512  /* XXX rpmlog message warning RPMDBI is deprecated? */
2513  tag = RPMTAG_NVRA;
2514  /*@fallthrough@*/
2515  case RPMTAG_NVRA:
2516 #ifdef NOTYET /* XXX JS unit tests break. */
2517  case RPMTAG_NAME:
2518 #endif
2519 #ifdef RPM_VENDOR_MANDRIVA_XXX /* XXX rpm -qf /non/existent breaks */
2520  case RPMTAG_PROVIDENAME:
2521 #endif
2522  case RPMTAG_VERSION:
2523  case RPMTAG_RELEASE:
2524  case RPMTAG_ARCH:
2525  case RPMTAG_OS:
2526  case RPMTAG_GROUP:
2527  usePatterns = 1;
2528  break;
2529 #ifndef NOTYET /* XXX can't quite do this yet */
2530  /* XXX HACK to remove the existing complexity of RPMTAG_BASENAMES */
2531  case RPMTAG_BASENAMES:
2532  if (keyp == NULL) /* XXX rpmdbFindFpList & grow are speshul */
2533  break;
2534  tag = RPMTAG_FILEPATHS;
2535  /*@fallthrough@*/
2536 #endif
2537  case RPMTAG_FILEPATHS:
2538  case RPMTAG_DIRNAMES:
2539  usePatterns = 1;
2540  break;
2541  }
2542 
2543  dbi = dbiOpen(db, tag, 0);
2544 #ifdef NOTYET /* XXX non-configured tag indices force NULL return */
2545 assert(dbi != NULL); /* XXX sanity */
2546 #else
2547  if (dbi == NULL)
2548  goto exit;
2549 #endif
2550 
2551  mi = rpmmiGetPool(_rpmmiPool);
2552  (void)rpmioLinkPoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__);
2553 
2554 /* XXX FIXME: prints unprintable characters (while debugging). */
2555 if (_rpmmi_debug || (dbi && dbi->dbi_debug))
2556 fprintf(stderr, "--> %s(%p, %s, %p[%u]=\"%s\") dbi %p mi %p\n", __FUNCTION__, db, tagName(tag), keyp, (unsigned)keylen, (keyp != NULL && (keylen == 0 || ((const char *)keyp)[keylen] == '\0') ? (const char *)keyp : "???"), dbi, mi);
2557 
2558  /* Chain cursors for teardown on abnormal exit. */
2559  mi->mi_next = rpmmiRock;
2560  rpmmiRock = mi;
2561 
2562  if (tag == RPMDBI_PACKAGES && keyp == NULL) {
2563  /* Special case #1: sequentially iterate Packages database. */
2564  assert(keylen == 0);
2565  /* This should be the only case when (set == NULL). */
2566  }
2567  else if (tag == RPMDBI_PACKAGES) {
2568  /* Special case #2: will fetch header instance. */
2569  uint32_t hdrNum;
2570 assert(keylen == sizeof(hdrNum));
2571  memcpy(&hdrNum, keyp, sizeof(hdrNum));
2572  /* The set has only one element, which is hdrNum. */
2573  set = (dbiIndexSet) xcalloc(1, sizeof(*set));
2574  set->count = 1;
2575  set->recs = (dbiIndexItem) xcalloc(1, sizeof(set->recs[0]));
2576  set->recs[0].hdrNum = hdrNum;
2577  }
2578  else if (keyp == NULL) {
2579  /* XXX Special case #3: empty iterator with rpmmiGrow() */
2580  assert(keylen == 0);
2581  }
2582  else if (usePatterns) {
2583  /* XXX Special case #4: gather primary keys with patterns. */
2584  rpmRC rc;
2585 
2586  rc = dbiFindMatches(dbi, (const char *)keyp, &set);
2587 #if defined(RPM_VENDOR_MANDRIVA)
2588  /*
2589  * Hack to workaround disttag/distepoch pattern matching issue to buy some
2590  * time to come up with better pattern fix..
2591  * One size should fit all now.. ;)
2592  *
2593  * This patch will try match NVR first, then for all matches returned,
2594  * it will match disttag, distepoch & arch individually.
2595  */
2596 
2597  /* We'll only try this if query fails */
2598  if(!rc && ((const char*)keyp)[0] != '^' && tag == RPMTAG_NVRA &&
2599  (set == NULL || set->count < 1)) {
2600  size_t i;
2601  char *tmp = (char*)keyp;
2602 
2603  /* If pattern has less than three '-', it can't contain disttag, so
2604  * no point in trying */
2605  for (i = 0; (tmp = strchr(tmp, '-')); i++)
2606  tmp++;
2607 
2608  if (i >= 3) {
2609  dbiIndex pdbi;
2610  DBC *pdbc;
2611  const char *origkeyp = keyp;
2612  size_t klen = strlen(keyp)+1;
2613  size_t size = 0;
2614  int xx;
2615 
2616  keyp = alloca(klen);
2617  stpcpy((char*)keyp, origkeyp);
2618  tmp = strrchr(keyp, '-');
2619  *tmp = '\0';
2620  rc = dbiFindMatches(dbi, keyp, &set);
2621 
2622  pdbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
2623  xx = dbiCopen(pdbi, dbiTxnid(pdbi), &pdbc, 0);
2624 
2625  for(i = 0; set && i < set->count; i++) {
2626  DBT k = DBT_INIT;
2627  DBT v = DBT_INIT;
2628  Header h;
2629  uint32_t offset = _hton_ui(set->recs[i].hdrNum);
2630  rpmTag checkTags[] =
2632  int j;
2633 
2634  memset(&k, 0, sizeof(k));
2635  memset(&v, 0, sizeof(v));
2636  k.data = &offset;
2637  k.size = sizeof(offset);
2638 
2639  xx = dbiGet(dbi, pdbc, &k, &v, DB_SET);
2640  h = headerLoad(v.data);
2641  tmp = (char*)((size_t)keyp + strlen(keyp) + 1);
2642 
2643  for (j = 0; j < (int)(sizeof(checkTags)/sizeof(checkTags[0])) &&
2644  *tmp != '\0'; j++) {
2645  he->tag = checkTags[j];
2646  if(headerGet(h, he, 0)) {
2647  size_t len = strlen(he->p.str);
2648 
2649  if (he->tag == RPMTAG_ARCH && *tmp == '.')
2650  tmp++;
2651 
2652  if(!strncmp(he->p.str, tmp, len))
2653  tmp += len;
2654  _free(he->p.ptr);
2655  }
2656  }
2657  if(j && *tmp == '\0') {
2658  set->recs[size].hdrNum = set->recs[i].hdrNum;
2659  set->recs[size].tagNum = set->recs[i].tagNum;
2660  size++;
2661  }
2662 
2663  h = headerFree(h);
2664  }
2665  if(set && set->count != size) {
2666  set->count = size;
2667  set->recs = xrealloc(set->recs, size * sizeof(*set->recs));
2668  }
2669 
2670  xx = dbiCclose(pdbi, pdbc, 0);
2671  }
2672  }
2673 #endif
2674 
2675  if ((rc && rc != RPMRC_NOTFOUND) || set == NULL || set->count < 1) { /* error or empty set */
2676  set = dbiFreeIndexSet(set);
2677  rpmmiRock = mi->mi_next;
2678  mi->mi_next = NULL;
2679  mi = (rpmmi)rpmioFreePoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__);
2680  return NULL;
2681  }
2682  }
2683  else if (dbi && dbi->dbi_primary != NULL) {
2684  /* XXX Special case #5: secondary index associated w primary table. */
2685  }
2686  else {
2687  /* Common case: retrieve join keys. */
2688 assert(0);
2689  }
2690 
2691 /*@-assignexpose@*/
2692  mi->mi_db = (rpmdb) rpmdbLink(db, __FUNCTION__);
2693 /*@=assignexpose@*/
2694  mi->mi_rpmtag = tag;
2695 
2696  mi->mi_dbc = NULL;
2697  mi->mi_set = set;
2698  mi->mi_setx = 0;
2699  mi->mi_count = (set ? set->count : 0);
2700 
2701  mi->mi_primary = (dbi && dbi->dbi_primary
2702  ? xstrdup(dbi->dbi_primary) : NULL);
2703 
2704  /* Coerce/swab integer keys. Save key ind keylen in the iterator. */
2705  switch (tagType(tag) & 0xffff) {
2706  case RPM_UINT8_TYPE:
2707 assert(keylen == sizeof(he->p.ui8p[0]));
2708  mi->mi_keylen = sizeof(he->p.ui32p[0]); /* XXX coerce to uint32_t */
2709  mi->mi_keyp = he->p.ui32p = (rpmuint32_t *) xmalloc(mi->mi_keylen);
2710  he->p.ui32p[0] = 0;
2711  memcpy(&he->p.ui8p[3], keyp, keylen);
2712  break;
2713  case RPM_UINT16_TYPE:
2714 assert(keylen == sizeof(he->p.ui16p[0]));
2715  mi->mi_keylen = sizeof(he->p.ui32p[0]); /* XXX coerce to uint32_t */
2716  mi->mi_keyp = he->p.ui32p = (rpmuint32_t *) xmalloc(mi->mi_keylen);
2717  he->p.ui32p[0] = 0;
2718  memcpy(&he->p.ui16p[1], keyp, keylen);
2719  he->p.ui16p[1] = _hton_us(he->p.ui16p[1]);
2720  break;
2721 #if !defined(__LCLINT__) /* LCL: buggy */
2722  case RPM_UINT32_TYPE:
2723 assert(keylen == sizeof(he->p.ui32p[0]));
2724  mi->mi_keylen = keylen;
2725 /*@-mayaliasunique@*/
2726  mi->mi_keyp = memcpy((he->p.ptr = xmalloc(keylen)), keyp, keylen);
2727 /*@=mayaliasunique@*/
2728  he->p.ui32p[0] = _hton_ui(he->p.ui32p[0]);
2729  break;
2730  case RPM_UINT64_TYPE:
2731 assert(keylen == sizeof(he->p.ui64p[0]));
2732  mi->mi_keylen = keylen;
2733 /*@-mayaliasunique@*/
2734  mi->mi_keyp = memcpy((he->p.ptr = xmalloc(keylen)), keyp, keylen);
2735 /*@=mayaliasunique@*/
2736  { uint32_t _tmp = he->p.ui32p[0];
2737  he->p.ui32p[0] = _hton_ui(he->p.ui32p[1]);
2738  he->p.ui32p[1] = _hton_ui(_tmp);
2739  }
2740  break;
2741 #endif /* !defined(__LCLINT__) */
2742  case RPM_I18NSTRING_TYPE: /* XXX never occurs */
2743 #if !defined(SUPPORT_I18NSTRING_TYPE)
2744 assert(0);
2745 #endif
2746  case RPM_BIN_TYPE:
2747  case RPM_STRING_TYPE:
2748  case RPM_STRING_ARRAY_TYPE:
2749  default:
2750  mi->mi_keylen = keylen;
2751  if (keyp)
2752  mi->mi_keyp = (keylen > 0
2753  ? memcpy(xmalloc(keylen), (char *)keyp, keylen)
2754  : xstrdup((char *)keyp));
2755  else
2756  mi->mi_keyp = NULL;
2757  break;
2758  }
2759  he->p.ptr = NULL;
2760 
2761  mi->mi_h = NULL;
2762  mi->mi_sorted = 0;
2763  mi->mi_cflags = 0;
2764  mi->mi_modified = 0;
2765  mi->mi_prevoffset = 0;
2766  mi->mi_offset = 0;
2767  mi->mi_nre = 0;
2768  mi->mi_re = NULL;
2769 
2770 exit:
2771  return mi;
2772 }
2773 /*@=dependenttrans =exposetrans =globstate @*/
2774 
2775 /* XXX psm.c */
2776 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, uint32_t hdrNum,
2777  /*@unused@*/ rpmts ts)
2778 {
2779  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2780  Header h = NULL;
2781  sigset_t signalMask;
2782  dbiIndex dbi;
2783  size_t dbix;
2784  int rc = RPMRC_FAIL; /* XXX RPMRC */
2785  int xx;
2786 
2787  if (db == NULL)
2788  return RPMRC_OK; /* XXX RPMRC */
2789 
2790  /* Retrieve header for use by associated secondary index callbacks. */
2791  { rpmmi mi;
2792  mi = rpmmiInit(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
2793  h = rpmmiNext(mi);
2794  if (h)
2795  h = headerLink(h);
2796  mi = rpmmiFree(mi);
2797  }
2798 
2799  if (h == NULL) {
2800  rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n"),
2801  "rpmdbRemove", (unsigned)hdrNum);
2802  return RPMRC_FAIL; /* XXX RPMRC */
2803  }
2804 
2805  he->tag = RPMTAG_NVRA;
2806  xx = headerGet(h, he, 0);
2807  rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", (unsigned)hdrNum, he->p.str);
2808  he->p.ptr = _free(he->p.ptr);
2809 
2810  (void) blockSignals(db, &signalMask);
2811 
2812  dbix = db->db_ndbi - 1;
2813  if (db->db_tags != NULL)
2814  do {
2815  tagStore_t dbiTag = db->db_tags + dbix;
2816  DBC * dbcursor;
2817  DBT k;
2818  DBT v;
2819  uint32_t ui;
2820 
2821  dbi = NULL;
2822  dbcursor = NULL;
2823  (void) memset(&k, 0, sizeof(k));
2824  (void) memset(&v, 0, sizeof(v));
2825  (void) memset(he, 0, sizeof(*he));
2826  he->tag = dbiTag->tag;
2827 
2828  switch (he->tag) {
2829  default:
2830  /* Don't bother if tag is not present. */
2831  if (!headerGet(h, he, 0))
2832  /*@switchbreak@*/ break;
2833 
2834  dbi = dbiOpen(db, he->tag, 0);
2835  if (dbi == NULL) goto exit;
2836 
2837  he->p.ptr = _free(he->p.ptr);
2838  /*@switchbreak@*/ break;
2839  case RPMDBI_AVAILABLE: /* Filter out temporary databases */
2840  case RPMDBI_ADDED:
2841  case RPMDBI_REMOVED:
2842  case RPMDBI_DEPCACHE:
2843  case RPMDBI_SEQNO:
2844  /*@switchbreak@*/ break;
2845  case RPMDBI_PACKAGES:
2846  if (db->db_export != NULL)
2847  xx = db->db_export(db, h, 0);
2848 
2849  ui = _hton_ui(hdrNum);
2850  k.data = &ui;
2851  k.size = (UINT32_T) sizeof(ui);
2852 
2853  /* New h ref for use by associated secondary index callbacks. */
2854  db->db_h = headerLink(h);
2855 
2856  dbi = dbiOpen(db, he->tag, 0);
2857  if (dbi == NULL) goto exit;
2858 
2859  rc = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
2860  rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
2861  if (!rc)
2862  rc = dbiDel(dbi, dbcursor, &k, &v, 0);
2863  xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2864 
2865  /* Unreference db_h used by associated secondary index callbacks. */
2866  (void) headerFree(db->db_h);
2867  db->db_h = NULL;
2868 
2869  if (!dbi->dbi_no_dbsync)
2870  xx = dbiSync(dbi, 0);
2871 
2872  /*@switchbreak@*/ break;
2873  }
2874  } while (dbix-- > 0);
2875 
2876  /* Unreference header used by associated secondary index callbacks. */
2877  (void) headerFree(h);
2878  h = NULL;
2879  rc = RPMRC_OK; /* XXX RPMRC */
2880 
2881 exit:
2882  (void) unblockSignals(db, &signalMask);
2883  return rc;
2884 }
2885 
2886 /* XXX install.c */
2887 int rpmdbAdd(rpmdb db, int iid, Header h, /*@unused@*/ rpmts ts)
2888 {
2889  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2890  sigset_t signalMask;
2891  dbiIndex dbi;
2892  size_t dbix;
2893  uint32_t hdrNum = headerGetInstance(h);
2894  int rc = RPMRC_FAIL; /* XXX RPMRC */
2895  int xx;
2896 
2897  if (db == NULL)
2898  return RPMRC_OK; /* XXX RPMRC */
2899 
2900 if (_rpmdb_debug)
2901 fprintf(stderr, "--> %s(%p, %u, %p, %p) h# %u\n", __FUNCTION__, db, (unsigned)iid, h, ts, (unsigned)hdrNum);
2902 
2903 //assert(headerIsEntry(h, RPMTAG_REMOVETID) == 0); /* XXX sanity */
2904 
2905  /* Add the install transaction id. */
2906  if (iid != 0 && iid != -1) {
2907  rpmuint32_t tid[2];
2908  tid[0] = iid;
2909  tid[1] = 0;
2910  he->tag = RPMTAG_INSTALLTID;
2911  he->t = RPM_UINT32_TYPE;
2912  he->p.ui32p = tid;
2913  he->c = 2;
2914  if (!headerIsEntry(h, he->tag))
2915 /*@-compmempass@*/
2916  xx = headerPut(h, he, 0);
2917 /*@=compmempass@*/
2918  }
2919 
2920 /* XXX pubkeys used to set RPMTAG_PACKAGECOLOR here. */
2921 assert(headerIsEntry(h, RPMTAG_PACKAGECOLOR) != 0); /* XXX sanity */
2922 
2923  (void) blockSignals(db, &signalMask);
2924 
2925  /* Assign a primary Packages key for new Header's. */
2926  if (hdrNum == 0) {
2927  int64_t seqno = 0;
2928 
2929  dbi = dbiOpen(db, RPMDBI_SEQNO, 0);
2930  if (dbi == NULL) goto exit;
2931 
2932  if ((xx = dbiSeqno(dbi, &seqno, 0)) == 0) {
2933  hdrNum = seqno;
2934  (void) headerSetInstance(h, hdrNum);
2935  } else
2936  goto exit;
2937  }
2938 
2939 /* XXX ensure that the header instance is set persistently. */
2940 if (hdrNum == 0) {
2941 assert(hdrNum > 0);
2942 assert(hdrNum == headerGetInstance(h));
2943 }
2944 
2945  dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
2946  if (dbi == NULL) goto exit;
2947 
2948  dbix = db->db_ndbi - 1;
2949  if (db->db_tags != NULL)
2950  do {
2951  tagStore_t dbiTag = db->db_tags + dbix;
2952  DBC * dbcursor;
2953  DBT k;
2954  DBT v;
2955  uint32_t ui;
2956 
2957  dbi = NULL;
2958  dbcursor = NULL;
2959  (void) memset(&k, 0, sizeof(k));
2960  (void) memset(&v, 0, sizeof(v));
2961  (void) memset(he, 0, sizeof(*he));
2962  he->tag = dbiTag->tag;
2963 
2964  switch (he->tag) {
2965  default:
2966  /* Don't bother if tag is not present. */
2967  if (!headerGet(h, he, 0))
2968  /*@switchbreak@*/ break;
2969 
2970  dbi = dbiOpen(db, he->tag, 0);
2971  if (dbi == NULL) goto exit;
2972 
2973  he->p.ptr = _free(he->p.ptr);
2974  /*@switchbreak@*/ break;
2975  case RPMDBI_AVAILABLE: /* Filter out temporary databases */
2976  case RPMDBI_ADDED:
2977  case RPMDBI_REMOVED:
2978  case RPMDBI_DEPCACHE:
2979  case RPMDBI_SEQNO:
2980  /*@switchbreak@*/ break;
2981  case RPMDBI_PACKAGES:
2982  if (db->db_export != NULL)
2983  xx = db->db_export(db, h, 1);
2984 
2985  ui = _hton_ui(hdrNum);
2986  k.data = (void *) &ui;
2987  k.size = (UINT32_T) sizeof(ui);
2988 
2989  { size_t len = 0;
2990  v.data = headerUnload(h, &len);
2991 assert(v.data != NULL);
2992  v.size = (UINT32_T) len;
2993  }
2994 
2995  /* New h ref for use by associated secondary index callbacks. */
2996  db->db_h = headerLink(h);
2997 
2998  dbi = dbiOpen(db, he->tag, 0);
2999  if (dbi == NULL) goto exit;
3000 
3001  xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
3002  xx = dbiPut(dbi, dbcursor, &k, &v, DB_KEYLAST);
3003  xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3004 
3005  /* Unreference db_h used by associated secondary index callbacks. */
3006  (void) headerFree(db->db_h);
3007  db->db_h = NULL;
3008 
3009  if (!dbi->dbi_no_dbsync)
3010  xx = dbiSync(dbi, 0);
3011 
3012  v.data = _free(v.data); /* headerUnload */
3013  v.size = 0;
3014  /*@switchbreak@*/ break;
3015  }
3016 
3017  } while (dbix-- > 0);
3018  rc = RPMRC_OK; /* XXX RPMRC */
3019 
3020 exit:
3021  (void) unblockSignals(db, &signalMask);
3022  return rc;
3023 }
static union _dbswap _endian
Definition: rpmdb.c:301
const bson * b
Definition: bson.h:280
rpmTagType t
Definition: rpmtag.h:504
struct rpmioItem_s _item
Definition: rpmdb.c:437
int rpmmiPrune(rpmmi mi, uint32_t *hdrNums, int nHdrNums, int sorted)
Remove items from set of package instances to iterate.
Definition: rpmdb.c:2453
int rpmdbOpenAll(rpmdb db)
Open all database indices.
Definition: rpmdb.c:791
const char * str
Definition: rpmtag.h:73
static const int one
Definition: mongo.c:49
rpmTag tag
Definition: rpmtag.h:503
void yarnTwist(yarnLock bolt, yarnTwistOP op, long val)
Definition: yarn.c:279
const char ** argv
Definition: rpmtag.h:75
int _mire_debug
Definition: mire.c:18
int rpmmiGrowBasename(rpmmi mi, const char *bn)
Append packages containing common basename to iterator.
Definition: rpmdb.c:1495
miRE mireNew(rpmMireMode mode, int tag)
Create pattern container.
Definition: mire.c:113
mongo_error_t const char * errstr
Definition: mongo.h:922
int headerIsEntry(Header h, rpmTag tag)
Check if tag is in header.
Definition: header.c:1439
struct _setSwap_s * setSwap
static uint16_t _hton_us(uint16_t us)
Definition: rpmdb.c:352
static const char * queryHeader(Header h, const char *qfmt)
Return header query string.
Definition: rpmdb.c:579
int mi_nre
Definition: rpmdb.c:460
const char const char size_t len
Definition: bson.h:823
const char bson_timestamp_t * ts
Definition: bson.h:1004
static rpmRC dbiFindMatches(dbiIndex dbi, const char *pat, dbiIndexSet *matches)
Attempt partial matches on name[-version[-release]] strings.
Definition: rpmdb.c:1536
uint64_t ul
Definition: db3.c:45
void * mireFreeAll(miRE mire, int nmire)
Destroy compiled patterns.
Definition: mire.c:96
enum urltype_e urltype
Supported URL types.
uint32_t fp
Definition: rpmdb.c:361
OpenPGP constants and structures from RFC-2440.
void yarnPossess(yarnLock bolt)
Definition: yarn.c:262
static struct _dbiVec * mydbvecs[]
Definition: rpmdb.c:207
rpmbf rpmbfNew(size_t m, size_t k, unsigned flags)
Create a Bloom filter.
Definition: rpmbf.c:52
#define EXIT_FAILURE
long yarnPeekLock(yarnLock bolt)
Definition: yarn.c:325
uint32_t rpmmiInstance(rpmmi mi)
Return header instance for current position of rpmdb iterator.
Definition: rpmdb.c:1747
char * xstrdup(const char *str)
Definition: rpmmalloc.c:321
static rpmdb rpmdbGetPool(rpmioPool pool)
Definition: rpmdb.c:775
rpmuint32_t * ui32p
Definition: rpmtag.h:70
static int _rpmmi_usermem
Definition: rpmdb.c:2194
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2840
static uint32_t _ntoh_ui(uint32_t ui)
Definition: rpmdb.c:323
#define _DB_FLAGS
Definition: rpmdb.c:999
char * rpmGetPath(const char *path,...)
Return (malloc'ed) expanded, canonicalized, file path.
Definition: macro.c:3443
rpmbf mi_bf
Definition: rpmdb.c:459
#define RPMDBI_QUEUE
Definition: rpmtag.h:491
static unsigned char nibble(char c)
Convert hex to binary nibble.
Definition: rpmdb.c:2003
#define _DB_ROOT
Definition: rpmdb.c:997
uint8_t uc[8]
Definition: db3.c:48
int headerGet(Header h, HE_t he, unsigned int flags)
Retrieve extension or tag value from a header.
Definition: header.c:2231
int headerPut(Header h, HE_t he, unsigned int flags)
Add or append tag container to header.
Definition: header.c:2294
rpmioItem rpmioLinkPoolItem(rpmioItem item, const char *msg, const char *fn, unsigned ln)
Increment a pool item refcount.
Definition: rpmmalloc.c:165
struct rpmbf_s * rpmbf
Definition: rpmbf.h:17
unsigned int mi_count
Definition: rpmdb.c:445
The Header data structure.
int rpmioMkpath(const char *path, mode_t mode, uid_t uid, gid_t gid)
Insure that directories in path exist, creating as needed.
Definition: rpmio.c:3024
int mireRegcomp(miRE mire, const char *pattern)
Compile pattern match.
Definition: mire.c:332
#define RPMDBI_REMOVED
Definition: rpmtag.h:483
#define DB_SET
Definition: db_emu.h:88
miRE mi_re
Definition: rpmdb.c:462
int argvAppend(ARGV_t *argvp, ARGV_t av)
Append one argv array to another.
Definition: argv.c:216
rpmuint16_t * ui16p
Definition: rpmtag.h:69
uint32_t mi_bntag
Definition: rpmdb.c:457
int headerSetOrigin(Header h, const char *origin)
Store header origin (e.g path or URL).
Definition: header.c:1189
static rpmlogRec recs
Definition: rpmlog.c:21
#define RPMDBI_RECNO
Definition: rpmtag.h:492
rpmdb rpmdbLink(rpmdb db, const char *msg)
Reference a database instance.
rpmdb mi_db
Definition: rpmdb.c:441
int _rpmmi_debug
Definition: rpmdb.c:64
Definition: rpmdb.c:436
uint32_t mi_prevoffset
Definition: rpmdb.c:455
static uint64_t _ntoh_ul(uint64_t ul)
Definition: rpmdb.c:303
#define DB2vec
Definition: rpmdb.c:181
Hash table implemenation.
void * rpmioFreePoolItem(rpmioItem item, const char *msg, const char *fn, unsigned ln)
Free a pool item.
Definition: rpmmalloc.c:186
int errno
#define DB3vec
Definition: rpmdb.c:191
static rpmmi rpmmiGetPool(rpmioPool pool)
Definition: rpmdb.c:1731
int rpmdbCheckSignals(void)
Check for and exit on termination signals.
Definition: rpmdb.c:523
Header headerCopyLoad(const void *uh)
Make a copy and convert header to in-memory representation.
Definition: header.c:1433
#define DB_KEYLAST
Definition: db_emu.h:85
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
static size_t dbiTagToDbix(rpmdb db, rpmTag tag)
Return dbi index used for rpm tag.
Definition: rpmdb.c:76
#define HEADERFLAG_RDONLY
struct _dbiIndexSet * dbiIndexSet
A single element (i.e.
Definition: rpmdb.h:55
#define _DB_MODE
Definition: rpmdb.c:1000
#define DB_NOTFOUND
Definition: db_emu.h:94
uint32_t dbiIndexRecordFileNumber(dbiIndexSet set, unsigned int recno)
Definition: rpmdb.c:423
static int hdrNumCmp(const void *one, const void *two)
Definition: rpmdb.c:365
static int dbiAppendSet(dbiIndexSet set, const void *recs, int nrecs, size_t recsize, int sortset)
Append element(s) to set of index database items.
Definition: rpmdb.c:382
int Utime(const char *path, const struct utimbuf *buf)
Definition: rpmrpc.c:2021
char * headerSprintf(Header h, const char *fmt, headerTagTableEntry tags, headerSprintfExtension exts, errmsg_t *errmsg)
Return formatted output string from header tags.
Definition: hdrfmt.c:6730
rpmTag tagValue(const char *tagstr)
Return tag value from name.
Definition: tagname.c:446
dbiIndexSet dbiFreeIndexSet(dbiIndexSet set)
Definition: rpmdb.c:428
void * headerUnload(Header h, size_t *lenp)
headerUnload.
Definition: header.c:648
rpmmi rpmmiInit(rpmdb db, rpmTag tag, const void *keyp, size_t keylen)
Return database iterator.
Definition: rpmdb.c:2495
int rpmdbCheckTerminate(int terminate)
Check rpmdb signal handler for trapped signal and/or requested exit.
Definition: rpmdb.c:476
int rpmmiGrow(rpmmi mi, const uint32_t *hdrNums, int nHdrNums)
Append items to set of package instances to iterate.
Definition: rpmdb.c:2479
void rpmbfParams(size_t n, double e, size_t *mp, size_t *kp)
Return optimal {m, k} for given n and e.
Definition: rpmbf.c:202
char * alloca()
const char * str
Definition: bson.h:593
Yet Another syslog(3) API clone.
int mi_modified
Definition: rpmdb.c:454
unsigned int rpmuint32_t
Definition: rpmiotypes.h:28
struct _HE_s * HE_t
Definition: rpmtag.h:59
miRE mireFree(miRE mire)
Free pattern container.
#define DB1vec
Definition: rpmdb.c:180
static int nrecs
Definition: rpmlog.c:19
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:300
union _dbswap tag
Definition: rpmdb.c:360
void * data
Definition: db_emu.h:22
void * ptr
Definition: rpmtag.h:67
#define RPMDBI_SEQNO
Definition: rpmtag.h:488
DBC * mi_dbc
Definition: rpmdb.c:444
const char const bson_bool_t v
Definition: bson.h:919
uint32_t headerSetInstance(Header h, uint32_t instance)
Store header instance (e.g path or URL).
Definition: header.c:1280
rpmbf rpmbfFree(rpmbf bf)
Destroy a Bloom filter.
int rpmmiSort(rpmmi mi)
Sort iterator instances.
Definition: rpmdb.c:2420
static uint16_t _ntoh_us(uint16_t us)
Definition: rpmdb.c:341
rpmmi mi_next
Definition: rpmdb.c:439
const char * mode
Definition: mongo.h:440
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:220
#define DB_WRITECURSOR
Definition: db_emu.h:91
uint32_t dlen
Definition: db_emu.h:26
static int dbiMireKeys(rpmdb db, rpmTag tag, rpmMireMode mode, const char *pat, dbiIndexSet *matches, const char ***argvp)
Retrieve prinary/secondary keys for a pattern match.
Definition: rpmdb.c:1320
unsigned int tagType(rpmTag tag)
Return tag data type from value.
Definition: tagname.c:441
int rpmdbRemove(rpmdb db, int rid, uint32_t hdrNum, rpmts ts)
Remove package header from rpm database and indices.
Definition: rpmdb.c:2776
char * stpncpy(char *dest, const char *src, size_t n)
const char const bson * data
Definition: mongo.h:463
rpmTagData p
Definition: rpmtag.h:506
rpmioPool _rpmmiPool
Definition: rpmdb.c:1729
static int xisspace(int c)
Definition: rpmiotypes.h:555
int mi_sorted
Definition: rpmdb.c:452
static const char * rpmdbURIPath(const char *uri)
Return macro expanded absolute path to rpmdb.
Definition: rpmdb.c:944
#define _DB_HOME
Definition: rpmdb.c:998
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
struct miRE_s * miRE
Definition: mire.h:60
static int rpmdbExportInfo(rpmdb db, Header h, int adding)
Write added/removed header info.
Definition: rpmdb.c:750
const char * tagName(rpmTag tag)
Return tag name from value.
Definition: tagname.c:436
#define RPMDBI_HEAP
Definition: rpmtag.h:493
int rpmdbOpen(const char *prefix, rpmdb *dbp, int mode, mode_t perms)
Open rpm database.
Definition: rpmdb.c:1179
static int blockSignals(rpmdb db, sigset_t *oldMask)
Block all signals, returning previous signal mask.
Definition: rpmdb.c:541
int Glob_pattern_p(const char *pattern, int quote)
glob_pattern_p(3) clone.
Definition: rpmrpc.c:2231
uint16_t us
Definition: db3.c:47
struct tagStore_s * tagStore_t
Definition: rpmtag.h:521
int rpmdbCloseDBI(rpmdb db, int tag)
Close a single database index.
Definition: rpmdb.c:843
#define DB_CURRENT
Definition: db_emu.h:84
Header headerLoad(void *uh)
Convert header to in-memory representation.
Definition: header.c:970
The FD_t File Handle data structure.
void * dbiStatsAccumulator(dbiIndex dbi, int opx)
Definition: rpmdb.c:1607
struct rpmdb_s * rpmdb
Database of headers and tag value indices.
Definition: rpmtypes.h:43
static int rpmdbOpenDatabase(const char *prefix, const char *dbpath, int _dbapi, rpmdb *dbp, int mode, mode_t perms, int flags)
Definition: rpmdb.c:1077
uint32_t mi_setx
Definition: rpmdb.c:446
int argvAdd(ARGV_t *argvp, ARGstr_t val)
Add a string to an argv array.
Definition: argv.c:199
rpmioItem rpmioPutPool(rpmioItem item)
Put unused item into pool (or free).
Definition: rpmmalloc.c:264
rpmTagCount c
Definition: rpmtag.h:507
int rpmdbMireApply(rpmdb db, rpmTag tag, rpmMireMode mode, const char *pat, const char ***argvp)
Return array of keys matching a pattern.
Definition: rpmdb.c:1486
int mireRegexec(miRE mire, const char *val, size_t vallen)
Execute pattern match.
Definition: mire.c:396
rpmioPool _mirePool
Definition: mire.c:79
struct rpmmi_s * rpmmi
Database iterator.
Definition: rpmtypes.h:48
Header headerFree(Header h)
Dereference a header instance.
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3250
static void rpmmiFini(void *_mi)
Definition: rpmdb.c:1679
#define DB_NEXT
Definition: db_emu.h:86
#define HEADERFLAG_MAPPED
uint32_t ulen
Definition: db_emu.h:25
Identify a file name path by a unique "finger print".
enum rpmMireMode_e rpmMireMode
Tag value pattern match mode.
rpmuint8_t * ui8p
Definition: rpmtag.h:68
uint32_t size
Definition: db_emu.h:23
uint32_t flags
Definition: db_emu.h:43
rpmmi rpmmiFree(rpmmi mi)
Destroy rpm database iterator.
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
#define RPMDBI_DEPCACHE
Definition: rpmtag.h:480
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
#define SQLITEvec
Definition: rpmdb.c:202
sigset_t rpmsqCaught
Definition: rpmsq.c:352
uint32_t mi_offset
Definition: rpmdb.c:456
Header headerLink(Header h)
Reference a header instance.
rpmdb rpmdbNew(const char *root, const char *home, int mode, mode_t perms, int flags)
Definition: rpmdb.c:1008
rpmTag mi_rpmtag
Definition: rpmdb.c:442
#define DB_BUFFER_SMALL
Definition: db_emu.h:93
static rpmdb rpmdbRock
Definition: rpmdb.c:471
enum rpmRC_e rpmRC
RPM return codes.
#define L(CS)
Definition: fnmatch.c:161
int rpmmiAddPattern(rpmmi mi, rpmTag tag, rpmMireMode mode, const char *pattern)
Add pattern to iterator selector.
Definition: rpmdb.c:1910
Definition: rpmtag.h:502
int rpmmiSetRewrite(rpmmi mi, int rewrite)
Prepare iterator for lazy writes.
Definition: rpmdb.c:2170
const char const int i
Definition: bson.h:778
#define RPMDBI_BTREE
Definition: rpmtag.h:489
#define DB_SET_RANGE
Definition: db_emu.h:89
struct _dbiVec db3vec
Definition: db3.c:2836
static int miFreeHeader(rpmmi mi, dbiIndex dbi)
Rewrite a header into packages (if necessary) and free the header.
Definition: rpmdb.c:1633
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
uint32_t dbiIndexRecordOffset(dbiIndexSet set, unsigned int recno)
Definition: rpmdb.c:418
static const char * prefix[]
Tables for prefixing and suffixing patterns, according to the -w, -x, and -F options.
Definition: rpmgrep.c:183
union _dbswap hdr
Definition: rpmdb.c:359
static void set(char *t, NODE *ip)
Definition: rpmmtree.c:1408
static uint32_t _hton_ui(uint32_t ui)
Definition: rpmdb.c:335
dbiIndex dbiOpen(rpmdb db, rpmTag tag, unsigned int flags)
Definition: rpmdb.c:223
Methods to handle package elements.
rpmioPool rpmioNewPool(const char *name, size_t size, int limit, int flags, char *(*dbg)(void *item), void(*init)(void *item), void(*fini)(void *item))
Create a memory pool.
Definition: rpmmalloc.c:109
Definition: db_emu.h:72
int rpmdbCountPackages(rpmdb db, const char *N)
Return number of instances of package in Name index.
Definition: rpmdb.c:1242
uint32_t rpmmiBNTag(rpmmi mi)
Return basename tag for current position of rpmdb iterator.
Definition: rpmdb.c:1756
static char * mireDup(rpmTag tag, rpmMireMode *modep, const char *pattern)
Copy pattern, escaping for appropriate mode.
Definition: rpmdb.c:1817
char * stpcpy(char *dest, const char *src)
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
const char const char size_t size
Definition: bson.h:895
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
int rpm_mergesort(void *base, size_t nmemb, size_t size, int(*cmp)(const void *, const void *))
Mergesort, same arguments as qsort(2).
Definition: merge.c:213
dbiIndexSet mi_set
Definition: rpmdb.c:443
int rpmmiSetModified(rpmmi mi, int modified)
Modify iterator to mark header for lazy write on release.
Definition: rpmdb.c:2183
Header rpmmiNext(rpmmi mi)
Return next package header from iteration.
Definition: rpmdb.c:2252
rpmioPool _rpmdbPool
Definition: rpmdb.c:773
tagStore_t tagStoreFree(tagStore_t dbiTags, size_t dbiNTags)
Destroy tagStore array.
Definition: tagname.c:473
const char * db
Definition: mongo.h:697
#define DB_NEXT_DUP
Definition: db_emu.h:87
int rpmbfAdd(rpmbf bf, const void *_s, size_t ns)
Add item to a Bloom filter.
Definition: rpmbf.c:68
static int checkfd(const char *devnull, int fdno, int flags)
Definition: rpmdb.c:212
static int rpmdbExportHR_MIB(rpmdb db, Header h, int adding)
Write added/removed header info into %{_hrmib_path}.
Definition: rpmdb.c:601
int argvSplit(ARGV_t *argvp, const char *str, const char *seps)
Split a string into an argv array.
Definition: argv.c:233
static void dbiTagsInit(tagStore_t *dbiTagsP, size_t *dbiNTagsP)
Initialize database (index, tag) tuple from configuration.
Definition: rpmdb.c:94
rpmuint32_t flags
static int mireCmp(const void *a, const void *b)
Compare iterator selectors by rpm tag (qsort/bsearch).
Definition: rpmdb.c:1801
#define RPMDBI_AVAILABLE
Definition: rpmtag.h:484
void * mi_keyp
Definition: rpmdb.c:447
int mi_cflags
Definition: rpmdb.c:453
miRE mireGetPool(rpmioPool pool)
Allocate a miRE container from the pool.
Definition: mire.c:81
int rpmdbCount(rpmdb db, rpmTag tag, const void *keyp, size_t keylen)
Return number of instances of key in a tag index.
Definition: rpmdb.c:1192
static uint64_t _hton_ul(uint64_t ul)
Definition: rpmdb.c:317
#define DB_DBT_USERMEM
Definition: db_emu.h:42
uint32_t ui
Definition: db3.c:46
rpmuint32_t hashFunctionString(rpmuint32_t h, const void *data, size_t size)
Return hash value of a string.
Definition: rpmhash.c:83
Definition: yarn.h:166
#define _(Text)
Definition: system.h:29
int rpmdbAdd(rpmdb db, int iid, Header h, rpmts ts)
Add package header to rpm database and indices.
Definition: rpmdb.c:2887
const char const char * pattern
Definition: bson.h:971
#define xmalloc
Definition: system.h:32
static int unblockSignals(rpmdb db, sigset_t *oldMask)
Restore signal mask.
Definition: rpmdb.c:564
int _rpmdb_debug
Definition: rpmdb.c:61
miRE mireLink(miRE mire)
Reference a pattern container instance.
static int mireSkip(const rpmmi mi)
Return iterator selector match.
Definition: rpmdb.c:2046
ARGstr_t * ARGV_t
Definition: argv.h:12
struct _dbiIndexItem * dbiIndexItem
Definition: rpmdb.h:50
Access RPM indices using Berkeley DB interface(s).
enum rpmTag_e rpmTag
Definition: rpmtag.h:470
#define _DB_MAJOR
Definition: rpmdb.c:1003
int rpmdbClose(rpmdb db)
Close all database indices and free rpmdb.
Definition: rpmdb.c:870
#define D_(Text)
Definition: system.h:526
#define PATH_MAX
Definition: query.c:10
Definition: db3.c:44
static rpmmi rpmmiRock
Definition: rpmdb.c:474
int rpmdbBlockDBI(rpmdb db, int tag)
Block access to a single database index.
Definition: rpmdb.c:825
unsigned int rpmmiCount(rpmmi mi)
Return number of elements in rpm database iterator.
Definition: rpmdb.c:1763
static char * bin2hex(const void *data, size_t size)
Convert binary blob to printable hex string.
Definition: rpmdb.c:2022
struct _dbiVec sqlitevec
Definition: sqlite.c:1793
uint32_t headerGetInstance(Header h)
Return header instance (if from rpmdb).
Definition: header.c:1275
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:3324
#define RPMDBI_HASH
Definition: rpmtag.h:490
#define RPMDBI_PACKAGES
Pseudo-tags used by the rpmdb and rpmgi iterator API's.
Definition: rpmtag.h:479
#define xrealloc
Definition: system.h:35
int rpmsqEnable(int signum, rpmsqAction_t handler)
Enable or disable a signal handler.
Definition: rpmsq.c:439
headerSprintfExtension headerCompoundFormats
Supported default header extension/tag output formats.
Definition: hdrfmt.c:5278
const char * mi_primary
Definition: rpmdb.c:448
#define DB_DBT_PARTIAL
Definition: db_emu.h:37
#define RPMDBI_ADDED
Definition: rpmtag.h:482
size_t mi_keylen
Definition: rpmdb.c:449
static const char * _str2PCREpat(const char *_pre, const char *s, const char *_post)
Definition: rpmdb.c:1282
static int rpmmiGet(dbiIndex dbi, DBC *dbcursor, DBT *kp, DBT *pk, DBT *vp, unsigned int flags)
Definition: rpmdb.c:2196
int j
Definition: mongo.h:438
Header mi_h
Definition: rpmdb.c:451
int rpmbfChk(rpmbf bf, const void *_s, size_t ns)
Check for item in a Bloom filter.
Definition: rpmbf.c:90
struct _dbiIndex * dbiIndex
Definition: rpmdb.h:59
unsigned int dbiIndexSetCount(dbiIndexSet set)
Definition: rpmdb.c:413
#define UINT32_T
Definition: rpmdb.c:39
rpmuint64_t * ui64p
Definition: rpmtag.h:71
uint32_t doff
Definition: db_emu.h:27
#define _DB_PERMS
Definition: rpmdb.c:1001
const char * ns
Definition: mongo.h:326
static const char * stemEnd(const char *s)
Definition: rpmdb.c:1248
#define _DB_ERRPFX
Definition: rpmdb.c:1004
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397