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