rpm  4.5
rpmdb.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #define _USE_COPY_LOAD /* XXX don't use DB_DBT_MALLOC (yet) */
8 
9 #include <sys/file.h>
10 
11 #include <rpmio.h>
12 #include <rpmpgp.h>
13 #include <rpmurl.h>
14 #include <rpmmacro.h>
15 #include <rpmsq.h>
16 
17 #define _RPMEVR_INTERNAL /* XXX isInstallPrereq */
18 #include <rpmevr.h>
19 
20 #define _RPMDB_INTERNAL
21 #define _MIRE_INTERNAL
22 #include "rpmdb.h"
23 #include "fprint.h"
24 #include "legacy.h"
25 #include "header_internal.h" /* XXX for HEADERFLAG_ALLOCATED */
26 #include "debug.h"
27 
28 /*@access dbiIndexSet@*/
29 /*@access dbiIndexItem@*/
30 /*@access rpmts@*/ /* XXX compared with NULL */
31 /*@access Header@*/ /* XXX compared with NULL */
32 /*@access rpmdbMatchIterator@*/
33 
34 /*@unchecked@*/
35 int _rpmdb_debug = 0;
36 
37 /*@unchecked@*/
38 static int _rebuildinprogress = 0;
39 /*@unchecked@*/
40 static int _db_filter_dups = 0;
41 
42 
43 /* Use a path uniquifier in the upper 16 bits of tagNum? */
44 /* XXX Note: one cannot just choose a value, rpmdb tagNum's need fixing too */
45 #define _DB_TAGGED_FILE_INDICES 1
46 /*@unchecked@*/
48 
49 #define _DBI_FLAGS 0
50 #define _DBI_PERMS 0644
51 #define _DBI_MAJOR -1
52 
53 /* Bit mask macros. */
54 /*@-exporttype@*/
55 typedef unsigned int __pbm_bits;
56 /*@=exporttype@*/
57 #define __PBM_NBITS (8 * sizeof (__pbm_bits))
58 #define __PBM_IX(d) ((d) / __PBM_NBITS)
59 #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
60 /*@-exporttype@*/
61 typedef struct {
62  __pbm_bits bits[1];
63 } pbm_set;
64 /*@=exporttype@*/
65 #define __PBM_BITS(set) ((set)->bits)
66 
67 #define PBM_FREE(s) _free(s);
68 #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
69 #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
70 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
71 
72 #define PBM_ALLOC(d) xcalloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
73 
80 /*@unused@*/
81 static inline pbm_set * PBM_REALLOC(pbm_set ** sp, int * odp, int nd)
82  /*@modifies *sp, *odp @*/
83 {
84  int i, nb;
85 
86 /*@-bounds -sizeoftype@*/
87  if (nd > (*odp)) {
88  nd *= 2;
89  nb = __PBM_IX(nd) + 1;
90 /*@-unqualifiedtrans@*/
91  *sp = xrealloc(*sp, nb * sizeof(__pbm_bits));
92 /*@=unqualifiedtrans@*/
93  for (i = __PBM_IX(*odp) + 1; i < nb; i++)
94  __PBM_BITS(*sp)[i] = 0;
95  *odp = nd;
96  }
97 /*@=bounds =sizeoftype@*/
98 /*@-compdef -retalias -usereleased@*/
99  return *sp;
100 /*@=compdef =retalias =usereleased@*/
101 }
102 
108 static inline unsigned char nibble(char c)
109  /*@*/
110 {
111  if (c >= '0' && c <= '9')
112  return (c - '0');
113  if (c >= 'A' && c <= 'F')
114  return (c - 'A') + 10;
115  if (c >= 'a' && c <= 'f')
116  return (c - 'a') + 10;
117  return 0;
118 }
119 
120 #ifdef DYING
121 
127 static int printable(const void * ptr, size_t len) /*@*/
128 {
129  const char * s = ptr;
130  int i;
131  for (i = 0; i < len; i++, s++)
132  if (!(*s >= ' ' && *s <= '~')) return 0;
133  return 1;
134 }
135 #endif
136 
143 static int dbiTagToDbix(rpmdb db, int rpmtag)
144  /*@*/
145 {
146  int dbix;
147 
148  if (db->db_tagn != NULL)
149  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
150 /*@-boundsread@*/
151  if (rpmtag != db->db_tagn[dbix])
152  continue;
153  return dbix;
154 /*@=boundsread@*/
155  }
156  return -1;
157 }
158 
162 /*@-exportheader@*/
163 static void dbiTagsInit(/*@null@*/int ** dbiTagsP, /*@null@*/int * dbiTagsMaxP)
164  /*@globals rpmGlobalMacroContext, h_errno @*/
165  /*@modifies dbiTagsP, dbiTagsMaxP, rpmGlobalMacroContext @*/
166 {
167 /*@observer@*/
168  static const char * const _dbiTagStr_default =
169  "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filemd5s:Depends:Pubkeys";
170  int * dbiTags = NULL;
171  int dbiTagsMax = 0;
172  char * dbiTagStr = NULL;
173  char * o, * oe;
174  int dbix, rpmtag, bingo;
175 
176  dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL);
177  if (!(dbiTagStr && *dbiTagStr)) {
178  dbiTagStr = _free(dbiTagStr);
179  dbiTagStr = xstrdup(_dbiTagStr_default);
180  }
181 
182  /* Always allocate package index */
183  dbiTags = xcalloc(1, sizeof(*dbiTags));
184  dbiTags[dbiTagsMax++] = RPMDBI_PACKAGES;
185 
186  for (o = dbiTagStr; o && *o; o = oe) {
187  while (*o && xisspace(*o))
188  o++;
189  if (*o == '\0')
190  break;
191  for (oe = o; oe && *oe; oe++) {
192  if (xisspace(*oe))
193  /*@innerbreak@*/ break;
194  if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
195  /*@innerbreak@*/ break;
196  }
197  if (oe && *oe)
198  *oe++ = '\0';
199  rpmtag = tagValue(o);
200  if (rpmtag < 0) {
202  _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
203  continue;
204  }
205 
206  bingo = 0;
207  if (dbiTags != NULL)
208  for (dbix = 0; dbix < dbiTagsMax; dbix++) {
209 /*@-boundsread@*/
210  if (rpmtag == dbiTags[dbix]) {
211  bingo = 1;
212  /*@innerbreak@*/ break;
213  }
214 /*@=boundsread@*/
215  }
216  if (bingo)
217  continue;
218 
219  dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags)); /* XXX memory leak */
220  dbiTags[dbiTagsMax++] = rpmtag;
221  }
222 
223  if (dbiTagsMaxP != NULL)
224  *dbiTagsMaxP = dbiTagsMax;
225 /*@-branchstate@*/
226  if (dbiTagsP != NULL)
227  *dbiTagsP = dbiTags;
228  else
229  dbiTags = _free(dbiTags);
230 /*@=branchstate@*/
231  dbiTagStr = _free(dbiTagStr);
232 }
233 /*@=exportheader@*/
234 
235 /*@-redecl@*/
236 #define DB1vec NULL
237 #define DB2vec NULL
238 
239 #ifdef HAVE_DB3_DB_H
240 /*@-exportheadervar -declundef @*/
241 /*@observer@*/ /*@unchecked@*/
242 extern struct _dbiVec db3vec;
243 /*@=exportheadervar =declundef @*/
244 #define DB3vec &db3vec
245 /*@=redecl@*/
246 #else
247 #define DB3vec NULL
248 #endif
249 
250 #ifdef HAVE_SQLITE3_H
251 #define SQLITE_HACK
252 /*@-exportheadervar -declundef @*/
253 /*@observer@*/ /*@unchecked@*/
254 extern struct _dbiVec sqlitevec;
255 /*@=exportheadervar =declundef @*/
256 #define SQLITEvec &sqlitevec
257 /*@=redecl@*/
258 #else
259 #define SQLITEvec NULL
260 #endif
261 
262 /*@-nullassign@*/
263 /*@observer@*/ /*@unchecked@*/
264 static struct _dbiVec *mydbvecs[] = {
266 };
267 /*@=nullassign@*/
268 
269 
275 static const char * mapTagName(int value)
276  /*@*/
277 {
278  const char * s = tagName(value);
279  if (s == NULL)
280  s = "";
281  else if (!strcmp(s, "Filedigests"))
282  s = "Filemd5s";
283  return s;
284 }
285 
286 dbiIndex dbiOpen(rpmdb db, rpmTag rpmtag, /*@unused@*/ unsigned int flags)
287 {
288  int dbix;
289  dbiIndex dbi = NULL;
290  int _dbapi, _dbapi_rebuild, _dbapi_wanted;
291  int rc = 0;
292 
293 /*@-modfilesys@*/
294 if (_rpmdb_debug)
295 fprintf(stderr, "==> %s(%p, %s, 0x%x)\n", __FUNCTION__, db, mapTagName(rpmtag), flags);
296 /*@=modfilesys@*/
297 
298  if (db == NULL)
299  return NULL;
300 
301  dbix = dbiTagToDbix(db, rpmtag);
302  if (dbix < 0 || dbix >= db->db_ndbi)
303  return NULL;
304 
305  /* Is this index already open ? */
306 /*@-compdef@*/ /* FIX: db->_dbi may be NULL */
307  if (db->_dbi != NULL && (dbi = db->_dbi[dbix]) != NULL)
308  return dbi;
309 /*@=compdef@*/
310 
311  _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
312  if (_dbapi_rebuild < 1 || _dbapi_rebuild > 4)
313  _dbapi_rebuild = 4;
314 /* _dbapi_wanted = (_rebuildinprogress ? -1 : db->db_api); */
315  _dbapi_wanted = (_rebuildinprogress ? _dbapi_rebuild : db->db_api);
316 
317  switch (_dbapi_wanted) {
318  default:
319  _dbapi = _dbapi_wanted;
320  if (_dbapi < 0 || _dbapi >= 5 || mydbvecs[_dbapi] == NULL) {
321  rpmMessage(RPMMESS_DEBUG, D_("dbiOpen: _dbiapi failed\n"));
322  return NULL;
323  }
324  errno = 0;
325  dbi = NULL;
326  rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
327  if (rc) {
328  static int _printed[32];
329  if (!_printed[dbix & 0x1f]++)
331  _("cannot open %s index using db%d - %s (%d)\n"),
332  mapTagName(rpmtag), _dbapi,
333  (rc > 0 ? strerror(rc) : ""), rc);
334  _dbapi = -1;
335  }
336  break;
337  case -1:
338  _dbapi = 5;
339  while (_dbapi-- > 1) {
340  if (mydbvecs[_dbapi] == NULL)
341  continue;
342  errno = 0;
343  dbi = NULL;
344  rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
345  if (rc == 0 && dbi)
346  /*@loopbreak@*/ break;
347  }
348  if (_dbapi <= 0) {
349  static int _printed[32];
350  if (!_printed[dbix & 0x1f]++)
351  rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"),
352  mapTagName(rpmtag));
353  rc = 1;
354  goto exit;
355  }
356  if (db->db_api == -1 && _dbapi > 0)
357  db->db_api = _dbapi;
358  break;
359  }
360 
361 exit:
362  if (dbi != NULL && rc == 0) {
363  if (db->_dbi != NULL)
364  db->_dbi[dbix] = dbi;
365 /*@-sizeoftype@*/
366  if (rpmtag == RPMDBI_PACKAGES && db->db_bits == NULL) {
367  db->db_nbits = 1024;
368  if (!dbiStat(dbi, DB_FAST_STAT)) {
369  DB_HASH_STAT * hash = (DB_HASH_STAT *)dbi->dbi_stats;
370  if (hash)
371  db->db_nbits += hash->hash_nkeys;
372  }
373  db->db_bits = PBM_ALLOC(db->db_nbits);
374  }
375 /*@=sizeoftype@*/
376  }
377 #ifdef HAVE_DB3_DB_H
378  else
379  dbi = db3Free(dbi);
380 #endif
381 
382 /*@-compdef -nullstate@*/ /* FIX: db->_dbi may be NULL */
383  return dbi;
384 /*@=compdef =nullstate@*/
385 }
386 
393 static dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
394  /*@*/
395 {
396  dbiIndexItem rec = xcalloc(1, sizeof(*rec));
397  rec->hdrNum = hdrNum;
398  rec->tagNum = tagNum;
399  return rec;
400 }
401 
402 union _dbswap {
403  uint32_t ui;
404  unsigned char uc[4];
405 };
406 
407 #define _DBSWAP(_a) \
408 /*@-bounds@*/ \
409  { unsigned char _b, *_c = (_a).uc; \
410  _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
411  _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
412 /*@=bounds@*/ \
413  }
414 
422 static int dbt2set(dbiIndex dbi, DBT * data, /*@out@*/ dbiIndexSet * setp)
423  /*@modifies dbi, *setp @*/
424 {
425  int _dbbyteswapped;
426  const char * sdbir;
427  dbiIndexSet set;
428  int i;
429 
430  if (dbi == NULL || data == NULL || setp == NULL)
431  return -1;
432  _dbbyteswapped = dbiByteSwapped(dbi);
433 
434  if ((sdbir = data->data) == NULL) {
435  *setp = NULL;
436  return 0;
437  }
438 
439  set = xmalloc(sizeof(*set));
440  set->count = data->size / dbi->dbi_jlen;
441  set->recs = xmalloc(set->count * sizeof(*(set->recs)));
442 
443 /*@-bounds -sizeoftype @*/
444  switch (dbi->dbi_jlen) {
445  default:
446  case 2*sizeof(int_32):
447  for (i = 0; i < set->count; i++) {
448  union _dbswap hdrNum, tagNum;
449 
450  memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
451  sdbir += sizeof(hdrNum.ui);
452  memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
453  sdbir += sizeof(tagNum.ui);
454  if (_dbbyteswapped) {
455  _DBSWAP(hdrNum);
456  _DBSWAP(tagNum);
457  }
458  set->recs[i].hdrNum = hdrNum.ui;
459  set->recs[i].tagNum = tagNum.ui;
460  set->recs[i].fpNum = 0;
461  }
462  break;
463  case 1*sizeof(int_32):
464  for (i = 0; i < set->count; i++) {
465  union _dbswap hdrNum;
466 
467  memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
468  sdbir += sizeof(hdrNum.ui);
469  if (_dbbyteswapped) {
470  _DBSWAP(hdrNum);
471  }
472  set->recs[i].hdrNum = hdrNum.ui;
473  set->recs[i].tagNum = 0;
474  set->recs[i].fpNum = 0;
475  }
476  break;
477  }
478  *setp = set;
479 /*@=bounds =sizeoftype @*/
480 /*@-compdef@*/
481  return 0;
482 /*@=compdef@*/
483 }
484 
492 static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
493  /*@modifies dbi, *data @*/
494 {
495  int _dbbyteswapped;
496  char * tdbir;
497  int i;
498 
499  if (dbi == NULL || data == NULL || set == NULL)
500  return -1;
501  _dbbyteswapped = dbiByteSwapped(dbi);
502 
503  data->size = set->count * (dbi->dbi_jlen);
504  if (data->size == 0) {
505  data->data = NULL;
506  return 0;
507  }
508  tdbir = data->data = xmalloc(data->size);
509 
510 /*@-bounds -sizeoftype@*/
511  switch (dbi->dbi_jlen) {
512  default:
513  case 2*sizeof(int_32):
514  for (i = 0; i < set->count; i++) {
515  union _dbswap hdrNum, tagNum;
516 
517  memset(&hdrNum, 0, sizeof(hdrNum));
518  memset(&tagNum, 0, sizeof(tagNum));
519  hdrNum.ui = set->recs[i].hdrNum;
520  tagNum.ui = set->recs[i].tagNum;
521  if (_dbbyteswapped) {
522  _DBSWAP(hdrNum);
523  _DBSWAP(tagNum);
524  }
525  memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
526  tdbir += sizeof(hdrNum.ui);
527  memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
528  tdbir += sizeof(tagNum.ui);
529  }
530  break;
531  case 1*sizeof(int_32):
532  for (i = 0; i < set->count; i++) {
533  union _dbswap hdrNum;
534 
535  memset(&hdrNum, 0, sizeof(hdrNum));
536  hdrNum.ui = set->recs[i].hdrNum;
537  if (_dbbyteswapped) {
538  _DBSWAP(hdrNum);
539  }
540  memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
541  tdbir += sizeof(hdrNum.ui);
542  }
543  break;
544  }
545 /*@=bounds =sizeoftype@*/
546 
547 /*@-compdef@*/
548  return 0;
549 /*@=compdef@*/
550 }
551 
552 /* XXX assumes hdrNum is first int in dbiIndexItem */
553 static int hdrNumCmp(const void * one, const void * two)
554  /*@*/
555 {
556  const int * a = one, * b = two;
557  return (*a - *b);
558 }
559 
569 static int dbiAppendSet(dbiIndexSet set, const void * recs,
570  int nrecs, size_t recsize, int sortset)
571  /*@modifies *set @*/
572 {
573  const char * rptr = recs;
574  size_t rlen = (recsize < sizeof(*(set->recs)))
575  ? recsize : sizeof(*(set->recs));
576 
577  if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
578  return 1;
579 
580  set->recs = xrealloc(set->recs,
581  (set->count + nrecs) * sizeof(*(set->recs)));
582 
583  memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
584 
585  while (nrecs-- > 0) {
586  /*@-mayaliasunique@*/
587  memcpy(set->recs + set->count, rptr, rlen);
588  /*@=mayaliasunique@*/
589  rptr += recsize;
590  set->count++;
591  }
592 
593  if (sortset && set->count > 1)
594  qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
595 
596  return 0;
597 }
598 
608 static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
609  size_t recsize, int sorted)
610  /*@modifies set, recs @*/
611 {
612  int from;
613  int to = 0;
614  int num = set->count;
615  int numCopied = 0;
616 
617 assert(set->count > 0);
618  if (nrecs > 1 && !sorted)
619  qsort(recs, nrecs, recsize, hdrNumCmp);
620 
621  for (from = 0; from < num; from++) {
622  if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
623  set->count--;
624  continue;
625  }
626  if (from != to)
627  set->recs[to] = set->recs[from]; /* structure assignment */
628  to++;
629  numCopied++;
630  }
631  return (numCopied == num);
632 }
633 
634 /* XXX transaction.c */
635 unsigned int dbiIndexSetCount(dbiIndexSet set) {
636  return set->count;
637 }
638 
639 /* XXX transaction.c */
640 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
641  return set->recs[recno].hdrNum;
642 }
643 
644 /* XXX transaction.c */
645 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
646  return set->recs[recno].tagNum;
647 }
648 
649 /* XXX transaction.c */
651  if (set) {
652  set->recs = _free(set->recs);
653  set = _free(set);
654  }
655  return set;
656 }
657 
659 /*@dependent@*/ /*@null@*/
661 /*@only@*/
662  const void * mi_keyp;
663  size_t mi_keylen;
664 /*@refcounted@*/
668  DBC * mi_dbc;
669  DBT mi_key;
670  DBT mi_data;
671  int mi_setx;
672 /*@refcounted@*/ /*@null@*/
677  unsigned int mi_prevoffset; /* header instance (native endian) */
678  unsigned int mi_offset; /* header instance (native endian) */
679  unsigned int mi_filenum; /* tag element (native endian) */
680  int mi_nre;
681 /*@only@*/ /*@null@*/
682  miRE mi_re;
683 /*@null@*/
685 /*@null@*/
686  rpmRC (*mi_hdrchk) (rpmts ts, const void * uh, size_t uc, const char ** msg)
687  /*@modifies ts, *msg @*/;
688 
689 };
690 
691 /*@unchecked@*/
693 
694 /*@unchecked@*/ /*@exposed@*/ /*@null@*/
696 
697 int rpmdbCheckTerminate(int terminate)
698  /*@globals rpmdbRock, rpmmiRock @*/
699  /*@modifies rpmdbRock, rpmmiRock @*/
700 {
701  sigset_t newMask, oldMask;
702  static int terminating = 0;
703 
704  if (terminating) return 1;
705 
706  (void) sigfillset(&newMask); /* block all signals */
707  (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
708 
709  if (sigismember(&rpmsqCaught, SIGINT)
710  || sigismember(&rpmsqCaught, SIGQUIT)
711  || sigismember(&rpmsqCaught, SIGHUP)
712  || sigismember(&rpmsqCaught, SIGTERM)
713  || sigismember(&rpmsqCaught, SIGPIPE)
714  || terminate)
715  terminating = 1;
716 
717  if (terminating) {
718  rpmdb db;
720 
721 /*@-branchstate@*/
722  while ((mi = rpmmiRock) != NULL) {
723 /*@i@*/ rpmmiRock = mi->mi_next;
724  mi->mi_next = NULL;
725 /*@i@*/ mi = rpmdbFreeIterator(mi);
726  }
727 /*@=branchstate@*/
728 
729 /*@-newreftrans@*/
730  while ((db = rpmdbRock) != NULL) {
731 /*@i@*/ rpmdbRock = db->db_next;
732  db->db_next = NULL;
733  (void) rpmdbClose(db);
734  }
735 /*@=newreftrans@*/
736  }
737  (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
738  return terminating;
739 }
740 
742  /*@globals rpmdbRock, rpmmiRock @*/
743  /*@modifies rpmdbRock, rpmmiRock @*/
744 {
745 
746  if (rpmdbCheckTerminate(0)) {
747 /*@-abstract@*/ /* sigset_t is abstract type */
748  rpmMessage(RPMMESS_DEBUG, D_("Exiting on signal(0x%lx) ...\n"), *((unsigned long *)&rpmsqCaught));
749 /*@=abstract@*/
750  exit(EXIT_FAILURE);
751  }
752  return 0;
753 
754 }
755 
762 static int blockSignals(/*@unused@*/ rpmdb db, /*@out@*/ sigset_t * oldMask)
763  /*@globals fileSystem @*/
764  /*@modifies *oldMask, fileSystem @*/
765 {
766  sigset_t newMask;
767 
768  (void) sigfillset(&newMask); /* block all signals */
769  (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
770  (void) sigdelset(&newMask, SIGINT);
771  (void) sigdelset(&newMask, SIGQUIT);
772  (void) sigdelset(&newMask, SIGHUP);
773  (void) sigdelset(&newMask, SIGTERM);
774  (void) sigdelset(&newMask, SIGPIPE);
775  return sigprocmask(SIG_BLOCK, &newMask, NULL);
776 }
777 
784 /*@mayexit@*/
785 static int unblockSignals(/*@unused@*/ rpmdb db, sigset_t * oldMask)
786  /*@globals rpmdbRock, fileSystem, internalState @*/
787  /*@modifies rpmdbRock, fileSystem, internalState @*/
788 {
789  (void) rpmdbCheckSignals();
790  return sigprocmask(SIG_SETMASK, oldMask, NULL);
791 }
792 
800 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
801  /*@globals headerDefaultFormats @*/
802 {
803  static const struct headerSprintfExtension_s * hdrfmts = headerDefaultFormats;
804  const char * errstr = "(unkown error)";
805  const char * str;
806 
807 /*@-modobserver@*/
808  str = headerSprintf(h, qfmt, rpmTagTable, hdrfmts, &errstr);
809 /*@=modobserver@*/
810  if (str == NULL)
811  rpmError(RPMERR_QFMT, _("incorrect format: \"%s\": %s\n"), qfmt, errstr);
812  return str;
813 }
814 
822 static int rpmdbExportInfo(/*@unused@*/ rpmdb db, Header h, int adding)
823  /*@globals headerDefaultFormats, rpmGlobalMacroContext, h_errno,
824  fileSystem, internalState @*/
825  /*@modifies rpmGlobalMacroContext,
826  fileSystem, internalState @*/
827 {
828  const char * fn = NULL;
829  int xx;
830 
831 /*@-branchstate@*/
832  { const char * fnfmt = rpmGetPath("%{?_hrmib_path}", NULL);
833  if (fnfmt && *fnfmt)
834  fn = queryHeader(h, fnfmt);
835  fnfmt = _free(fnfmt);
836  }
837 /*@=branchstate@*/
838 
839  if (fn == NULL)
840  goto exit;
841 
842  if (adding) {
843  FD_t fd = Fopen(fn, "w");
844  int_32 *iidp;
845 
846  if (fd != NULL) {
847  xx = Fclose(fd);
848  fd = NULL;
849  if (headerGetEntry(h, RPMTAG_INSTALLTIME, NULL, &iidp, NULL)) {
850  struct utimbuf stamp;
851  stamp.actime = *iidp;
852  stamp.modtime = *iidp;
853  if (!Utime(fn, &stamp))
854  rpmMessage(RPMMESS_DEBUG, " +++ %s\n", fn);
855  }
856  }
857  } else {
858  if (!Unlink(fn))
859  rpmMessage(RPMMESS_DEBUG, " --- %s\n", fn);
860  }
861 
862 exit:
863  fn = _free(fn);
864  return 0;
865 }
866 
867 #define _DB_ROOT "/"
868 #define _DB_HOME "%{?_dbpath}"
869 #define _DB_FLAGS 0
870 #define _DB_MODE 0
871 #define _DB_PERMS 0644
872 
873 #define _DB_MAJOR -1
874 #define _DB_ERRPFX "rpmdb"
875 
876 /*@-fullinitblock@*/
877 /*@observer@*/ /*@unchecked@*/
878 static struct rpmdb_s dbTemplate = {
881 };
882 /*@=fullinitblock@*/
883 
885 {
886  int dbix;
887  int rc = 0;
888 
889  if (db == NULL) return -2;
890 
891  if (db->db_tagn != NULL && db->_dbi != NULL)
892  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
893  if (db->db_tagn[dbix] < 0)
894  continue;
895  if (db->_dbi[dbix] != NULL)
896  continue;
897  switch ((db->db_tagn[dbix])) {
898  case RPMDBI_AVAILABLE:
899  case RPMDBI_ADDED:
900  case RPMDBI_REMOVED:
901  case RPMDBI_DEPENDS:
902  continue;
903  /*@notreached@*/ /*@switchbreak@*/ break;
904  default:
905  /*@switchbreak@*/ break;
906  }
907  (void) dbiOpen(db, db->db_tagn[dbix], db->db_flags);
908  }
909  return rc;
910 }
911 
912 int rpmdbBlockDBI(rpmdb db, int rpmtag)
913 {
914  int tagn = (rpmtag >= 0 ? rpmtag : -rpmtag);
915  int dbix;
916 
917  if (db == NULL || db->_dbi == NULL)
918  return 0;
919 
920  if (db->db_tagn != NULL)
921  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
922  if (db->db_tagn[dbix] != tagn)
923  continue;
924  db->db_tagn[dbix] = rpmtag;
925  return 0;
926  }
927  return 0;
928 }
929 
930 int rpmdbCloseDBI(rpmdb db, int rpmtag)
931 {
932  int dbix;
933  int rc = 0;
934 
935  if (db == NULL || db->_dbi == NULL)
936  return 0;
937 
938  if (db->db_tagn != NULL)
939  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
940  if (db->db_tagn[dbix] != rpmtag)
941  continue;
942 /*@-boundswrite@*/
943  if (db->_dbi[dbix] != NULL) {
944  int xx;
945  /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
946  xx = dbiClose(db->_dbi[dbix], 0);
947  if (xx && rc == 0) rc = xx;
948  db->_dbi[dbix] = NULL;
949  /*@=unqualifiedtrans@*/
950  }
951 /*@=boundswrite@*/
952  break;
953  }
954  return rc;
955 }
956 
957 /* XXX query.c, rpminstall.c, verify.c */
958 /*@-incondefs@*/
960  /*@globals rpmdbRock @*/
961  /*@modifies rpmdbRock @*/
962 {
963  rpmdb * prev, next;
964  int dbix;
965  int rc = 0;
966 
967  if (db == NULL)
968  goto exit;
969 
970  (void) rpmdbUnlink(db, "rpmdbClose");
971 
972  /*@-usereleased@*/
973  if (db->nrefs > 0)
974  goto exit;
975 
976  if (db->_dbi)
977  for (dbix = db->db_ndbi; --dbix >= 0; ) {
978  int xx;
979  if (db->_dbi[dbix] == NULL)
980  continue;
981  /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
982  xx = dbiClose(db->_dbi[dbix], 0);
983  if (xx && rc == 0) rc = xx;
984  db->_dbi[dbix] = NULL;
985  /*@=unqualifiedtrans@*/
986  }
987  db->db_errpfx = _free(db->db_errpfx);
988  db->db_root = _free(db->db_root);
989  db->db_home = _free(db->db_home);
990  db->db_bits = PBM_FREE(db->db_bits);
991  db->db_tagn = _free(db->db_tagn);
992  db->_dbi = _free(db->_dbi);
993  db->db_ndbi = 0;
994 
995 /*@-newreftrans@*/
996  prev = &rpmdbRock;
997  while ((next = *prev) != NULL && next != db)
998  prev = &next->db_next;
999  if (next) {
1000 /*@i@*/ *prev = next->db_next;
1001  next->db_next = NULL;
1002  }
1003 /*@=newreftrans@*/
1004 
1005  /*@-refcounttrans@*/ db = _free(db); /*@=refcounttrans@*/
1006  /*@=usereleased@*/
1007 
1008 exit:
1009  (void) rpmsqEnable(-SIGHUP, NULL);
1010  (void) rpmsqEnable(-SIGINT, NULL);
1011  (void) rpmsqEnable(-SIGTERM,NULL);
1012  (void) rpmsqEnable(-SIGQUIT,NULL);
1013  (void) rpmsqEnable(-SIGPIPE,NULL);
1014  return rc;
1015 }
1016 /*@=incondefs@*/
1017 
1019 {
1020  int dbix;
1021  int rc = 0;
1022 
1023  if (db == NULL) return 0;
1024  if (db->_dbi != NULL)
1025  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
1026  int xx;
1027  if (db->_dbi[dbix] == NULL)
1028  continue;
1029  if (db->_dbi[dbix]->dbi_no_dbsync)
1030  continue;
1031  xx = dbiSync(db->_dbi[dbix], 0);
1032  if (xx && rc == 0) rc = xx;
1033  }
1034  return rc;
1035 }
1036 
1042 static const char * rpmdbURIPath(const char *uri)
1043  /*@globals rpmGlobalMacroContext, h_errno @*/
1044  /*@modifies rpmGlobalMacroContext @*/
1045 {
1046  const char * s = rpmGetPath(uri, NULL);
1047  const char * fn = NULL;
1048  urltype ut = urlPath(s, &fn);
1049 
1050 /*@-branchstate@*/
1051  switch (ut) {
1052  case URL_IS_PATH:
1053  case URL_IS_UNKNOWN:
1054  fn = s;
1055  s = NULL;
1056  break;
1057  case URL_IS_HTTPS:
1058  case URL_IS_HTTP:
1059  case URL_IS_FTP:
1060  case URL_IS_HKP:
1061  case URL_IS_DASH:
1062  default:
1063  /* HACK: strip the URI prefix for these schemes. */
1064  fn = rpmGetPath(fn, NULL);
1065  break;
1066  }
1067 /*@=branchstate@*/
1068 
1069  /* Convert relative to absolute paths. */
1070  if (ut != URL_IS_PATH) /* XXX permit file:///... URI's */
1071  if (fn && *fn && *fn != '/') {
1072  char dn[PATH_MAX];
1073  char *t;
1074  dn[0] = '\0';
1075  if ((t = realpath(".", dn)) != NULL) {
1076  t += strlen(dn);
1077  if (t > dn && t[-1] != '/')
1078  *t++ = '/';
1079  t = stpncpy(t, fn, (sizeof(dn) - (t - dn)));
1080  *t = '\0';
1081  fn = _free(fn);
1082  fn = rpmGetPath(dn, NULL);
1083  }
1084  }
1085 
1086  s = _free(s);
1087 assert(fn != NULL);
1088  return fn;
1089 }
1090 
1091 /*@-exportheader@*/
1092 /*@-mods@*/ /* FIX: dbTemplate structure assignment */
1093 /*@only@*/ /*@null@*/
1094 rpmdb rpmdbNew(/*@kept@*/ /*@null@*/ const char * root,
1095  /*@kept@*/ /*@null@*/ const char * home,
1096  int mode, int perms, int flags)
1097  /*@globals _db_filter_dups, rpmGlobalMacroContext, h_errno @*/
1098  /*@modifies _db_filter_dups, rpmGlobalMacroContext @*/
1099 {
1100  rpmdb db = xcalloc(sizeof(*db), 1);
1101  const char * epfx = _DB_ERRPFX;
1102  static int oneshot = 0;
1103 
1104 /*@-modfilesys@*/ /*@-nullpass@*/
1105 if (_rpmdb_debug)
1106 fprintf(stderr, "==> %s(%s, %s, 0x%x, 0%o, 0x%x) db %p\n", __FUNCTION__, root, home, mode, perms, flags, db);
1107 /*@=modfilesys@*/ /*@=nullpass@*/
1108 
1109  if (!oneshot) {
1110  _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}");
1111  oneshot = 1;
1112  }
1113 
1114 /*@-boundswrite@*/
1115  /*@-assignexpose@*/
1116  *db = dbTemplate; /* structure assignment */
1117  /*@=assignexpose@*/
1118 /*@=boundswrite@*/
1119 
1120  db->_dbi = NULL;
1121 
1122  if (!(perms & 0600)) perms = 0644; /* XXX sanity */
1123 
1124  if (mode >= 0) db->db_mode = mode;
1125  if (perms >= 0) db->db_perms = perms;
1126  if (flags >= 0) db->db_flags = flags;
1127 
1128  db->db_root = rpmdbURIPath( (root && *root ? root : _DB_ROOT) );
1129  db->db_home = rpmdbURIPath( (home && *home ? home : _DB_HOME) );
1130 
1131  if (!(db->db_home && db->db_home[0])) {
1132  rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
1133  db->db_root = _free(db->db_root);
1134  db->db_home = _free(db->db_home);
1135  db = _free(db);
1136  /*@-globstate@*/ return NULL; /*@=globstate@*/
1137  }
1138 
1139  /* XXX if default "/var/lib/rpm" path, manage %{_hrmib_path} entries too. */
1140  { const char * dbpath = rpmGetPath("%{?_dbpath}", NULL);
1141  const char * rootpath = NULL;
1142  const char * homepath = NULL;
1143 
1144  (void) urlPath(db->db_root, &rootpath);
1145  (void) urlPath(db->db_home, &homepath);
1146 #define _VARLIBRPM "/var/lib/rpm"
1147  if (!strcmp(rootpath, "/")
1148  && !strncmp(homepath, _VARLIBRPM, sizeof(_VARLIBRPM)-1))
1149  db->db_export = rpmdbExportInfo;
1150  dbpath = _free(dbpath);
1151 #undef _VARLIBRPM
1152  }
1153 
1154  db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
1155  db->db_remove_env = 0;
1156  db->db_filter_dups = _db_filter_dups;
1157  dbiTagsInit(&db->db_tagn, &db->db_ndbi);
1158  db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
1159  db->nrefs = 0;
1160  /*@-globstate@*/
1161  return rpmdbLink(db, "rpmdbCreate");
1162  /*@=globstate@*/
1163 }
1164 /*@=mods@*/
1165 /*@=exportheader@*/
1166 
1167 /*@-exportheader@*/
1168 int rpmdbOpenDatabase(/*@null@*/ const char * prefix,
1169  /*@null@*/ const char * dbpath,
1170  int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp,
1171  int mode, int perms, int flags)
1172  /*@globals rpmdbRock, rpmGlobalMacroContext, h_errno,
1173  fileSystem, internalState @*/
1174  /*@modifies rpmdbRock, *dbp, rpmGlobalMacroContext,
1175  fileSystem, internalState @*/
1176  /*@requires maxSet(dbp) >= 0 @*/
1177 {
1178  rpmdb db;
1179  int rc, xx;
1180  int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
1181  int minimal = flags & RPMDB_FLAG_MINIMAL;
1182 
1183  /* Insure that _dbapi has one of -1, 1, 2, or 3 */
1184  if (_dbapi < -1 || _dbapi > 4)
1185  _dbapi = -1;
1186  if (_dbapi == 0)
1187  _dbapi = 1;
1188 
1189  if (dbp)
1190  *dbp = NULL;
1191  if (mode & O_WRONLY)
1192  return 1;
1193 
1194  db = rpmdbNew(prefix, dbpath, mode, perms, flags);
1195  if (db == NULL)
1196  return 1;
1197 
1198  (void) rpmsqEnable(SIGHUP, NULL);
1199  (void) rpmsqEnable(SIGINT, NULL);
1200  (void) rpmsqEnable(SIGTERM, NULL);
1201  (void) rpmsqEnable(SIGQUIT, NULL);
1202  (void) rpmsqEnable(SIGPIPE, NULL);
1203 
1204  db->db_api = _dbapi;
1205 
1206  { int dbix;
1207 
1208  rc = 0;
1209  if (db->db_tagn != NULL)
1210  for (dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) {
1211  dbiIndex dbi;
1212  int rpmtag;
1213 
1214  /* Filter out temporary databases */
1215  switch ((rpmtag = db->db_tagn[dbix])) {
1216  case RPMDBI_AVAILABLE:
1217  case RPMDBI_ADDED:
1218  case RPMDBI_REMOVED:
1219  case RPMDBI_DEPENDS:
1220  continue;
1221  /*@notreached@*/ /*@switchbreak@*/ break;
1222  default:
1223  /*@switchbreak@*/ break;
1224  }
1225 
1226  dbi = dbiOpen(db, rpmtag, 0);
1227  if (dbi == NULL) {
1228  rc = -2;
1229  break;
1230  }
1231 
1232  switch (rpmtag) {
1233  case RPMDBI_PACKAGES:
1234  if (dbi == NULL) rc |= 1;
1235 #if 0
1236  /* XXX open only Packages, indices created on the fly. */
1237  if (db->db_api == 3)
1238 #endif
1239  goto exit;
1240  /*@notreached@*/ /*@switchbreak@*/ break;
1241  case RPMTAG_NAME:
1242  if (dbi == NULL) rc |= 1;
1243  if (minimal)
1244  goto exit;
1245  /*@switchbreak@*/ break;
1246  default:
1247  /*@switchbreak@*/ break;
1248  }
1249  }
1250  }
1251 
1252 exit:
1253  if (rc || justCheck || dbp == NULL)
1254  xx = rpmdbClose(db);
1255  else {
1256 /*@-assignexpose -newreftrans@*/
1257 /*@i@*/ db->db_next = rpmdbRock;
1258  rpmdbRock = db;
1259 /*@i@*/ *dbp = db;
1260 /*@=assignexpose =newreftrans@*/
1261  }
1262 
1263  return rc;
1264 }
1265 /*@=exportheader@*/
1266 
1267 rpmdb XrpmdbUnlink(rpmdb db, const char * msg, const char * fn, unsigned ln)
1268 {
1269 /*@-modfilesys@*/
1270 if (_rpmdb_debug)
1271 fprintf(stderr, "--> db %p -- %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
1272 /*@=modfilesys@*/
1273  db->nrefs--;
1274  return NULL;
1275 }
1276 
1277 rpmdb XrpmdbLink(rpmdb db, const char * msg, const char * fn, unsigned ln)
1278 {
1279  db->nrefs++;
1280 /*@-modfilesys@*/
1281 if (_rpmdb_debug)
1282 fprintf(stderr, "--> db %p ++ %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
1283 /*@=modfilesys@*/
1284  /*@-refcounttrans@*/ return db; /*@=refcounttrans@*/
1285 }
1286 
1287 /* XXX python/rpmmodule.c */
1288 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
1289 {
1290  int _dbapi = rpmExpandNumeric("%{_dbapi}");
1291 /*@-boundswrite@*/
1292  return rpmdbOpenDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
1293 /*@=boundswrite@*/
1294 }
1295 
1296 int rpmdbInit (const char * prefix, int perms)
1297 {
1298  rpmdb db = NULL;
1299  int _dbapi = rpmExpandNumeric("%{_dbapi}");
1300  int rc;
1301 
1302 /*@-boundswrite@*/
1303  rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
1304  perms, RPMDB_FLAG_JUSTCHECK);
1305 /*@=boundswrite@*/
1306  if (db != NULL) {
1307  int xx;
1308  xx = rpmdbOpenAll(db);
1309  if (xx && rc == 0) rc = xx;
1310  xx = rpmdbClose(db);
1311  if (xx && rc == 0) rc = xx;
1312  db = NULL;
1313  }
1314  return rc;
1315 }
1316 
1318 {
1319  int rc = 0;
1320 
1321  if (db != NULL) {
1322  int dbix;
1323  int xx;
1324  rc = rpmdbOpenAll(db);
1325 
1326  if (db->_dbi != NULL)
1327  for (dbix = db->db_ndbi; --dbix >= 0; ) {
1328  if (db->_dbi[dbix] == NULL)
1329  continue;
1330  /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
1331  xx = dbiVerify(db->_dbi[dbix], 0);
1332  if (xx && rc == 0) rc = xx;
1333  db->_dbi[dbix] = NULL;
1334  /*@=unqualifiedtrans@*/
1335  }
1336 
1337  /*@-nullstate@*/ /* FIX: db->_dbi[] may be NULL. */
1338  xx = rpmdbClose(db);
1339  /*@=nullstate@*/
1340  if (xx && rc == 0) rc = xx;
1341  db = NULL;
1342  }
1343  return rc;
1344 }
1345 
1346 int rpmdbVerify(const char * prefix)
1347 {
1348  rpmdb db = NULL;
1349  int _dbapi = rpmExpandNumeric("%{_dbapi}");
1350  int rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
1351 
1352  if (!rc && db != NULL)
1353  rc = rpmdbVerifyAllDBI(db);
1354  return rc;
1355 }
1356 
1362 static inline unsigned taghash(const char *s)
1363 {
1364  unsigned int r = 0;
1365  int c;
1366  while ((c = *(const unsigned char *)s++) != 0) {
1367  /* XXX Excluding the '/' character may cause hash collisions. */
1368  if (c != '/')
1369  r += (r << 3) + c;
1370  }
1371  return ((r & 0x7fff) | 0x8000) << 16;
1372 }
1373 
1383 static int rpmdbFindByFile(rpmdb db, /*@null@*/ const char * filespec,
1384  DBT * key, DBT * data, /*@out@*/ dbiIndexSet * matches)
1385  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1386  /*@modifies db, *key, *data, *matches, rpmGlobalMacroContext,
1387  fileSystem, internalState @*/
1388  /*@requires maxSet(matches) >= 0 @*/
1389 {
1391  HFD_t hfd = headerFreeData;
1392  const char * dirName;
1393  const char * baseName;
1394  rpmTagType bnt, dnt;
1395  fingerPrintCache fpc;
1396  fingerPrint fp1;
1397  dbiIndex dbi = NULL;
1398  DBC * dbcursor;
1399  dbiIndexSet allMatches = NULL;
1400  dbiIndexItem rec = NULL;
1401  int i;
1402  int rc;
1403  int xx;
1404 
1405  *matches = NULL;
1406  if (filespec == NULL) return -2;
1407 
1408  /*@-branchstate@*/
1409  if ((baseName = strrchr(filespec, '/')) != NULL) {
1410  char * t;
1411  size_t len;
1412 
1413  len = baseName - filespec + 1;
1414 /*@-boundswrite@*/
1415  t = strncpy(alloca(len + 1), filespec, len);
1416  t[len] = '\0';
1417 /*@=boundswrite@*/
1418  dirName = t;
1419  baseName++;
1420  } else {
1421  dirName = "";
1422  baseName = filespec;
1423  }
1424  /*@=branchstate@*/
1425  if (baseName == NULL)
1426  return -2;
1427 
1428  fpc = fpCacheCreate(20);
1429  fp1 = fpLookup(fpc, dirName, baseName, 1);
1430 
1431  dbi = dbiOpen(db, RPMTAG_BASENAMES, 0);
1432 /*@-branchstate@*/
1433  if (dbi != NULL) {
1434  dbcursor = NULL;
1435  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1436 
1437 /*@-temptrans@*/
1438 key->data = (void *) baseName;
1439 /*@=temptrans@*/
1440 key->size = strlen(baseName);
1441 if (key->size == 0) key->size++; /* XXX "/" fixup. */
1442 
1443  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1444  if (rc > 0) {
1446  _("error(%d) getting \"%s\" records from %s index\n"),
1447  rc, key->data, mapTagName(dbi->dbi_rpmtag));
1448  }
1449 
1450 if (rc == 0)
1451 (void) dbt2set(dbi, data, &allMatches);
1452 
1453  /* strip off directory tags */
1454  if (_db_tagged_file_indices && allMatches != NULL)
1455  for (i = 0; i < allMatches->count; i++) {
1456  if (allMatches->recs[i].tagNum & 0x80000000)
1457  allMatches->recs[i].tagNum &= 0x0000ffff;
1458  }
1459 
1460  xx = dbiCclose(dbi, dbcursor, 0);
1461  dbcursor = NULL;
1462  } else
1463  rc = -2;
1464 /*@=branchstate@*/
1465 
1466  if (rc) {
1467  allMatches = dbiFreeIndexSet(allMatches);
1468  fpc = fpCacheFree(fpc);
1469  return rc;
1470  }
1471 
1472  *matches = xcalloc(1, sizeof(**matches));
1473  rec = dbiIndexNewItem(0, 0);
1474  i = 0;
1475  if (allMatches != NULL)
1476  while (i < allMatches->count) {
1477  const char ** baseNames, ** dirNames;
1478  int_32 * dirIndexes;
1479  unsigned int offset = dbiIndexRecordOffset(allMatches, i);
1480  unsigned int prevoff;
1481  Header h;
1482 
1483  { rpmdbMatchIterator mi;
1484  mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset));
1485  h = rpmdbNextIterator(mi);
1486  if (h)
1487  h = headerLink(h);
1488  mi = rpmdbFreeIterator(mi);
1489  }
1490 
1491  if (h == NULL) {
1492  i++;
1493  continue;
1494  }
1495 
1496  xx = hge(h, RPMTAG_BASENAMES, &bnt, &baseNames, NULL);
1497  xx = hge(h, RPMTAG_DIRNAMES, &dnt, &dirNames, NULL);
1498  xx = hge(h, RPMTAG_DIRINDEXES, NULL, &dirIndexes, NULL);
1499 
1500  do {
1501  fingerPrint fp2;
1502  int num = dbiIndexRecordFileNumber(allMatches, i);
1503 
1504  fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
1505  /*@-nullpass@*/
1506  if (FP_EQUAL(fp1, fp2)) {
1507  /*@=nullpass@*/
1508  rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
1509  rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
1510  xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
1511  }
1512 
1513  prevoff = offset;
1514  i++;
1515  if (i < allMatches->count)
1516  offset = dbiIndexRecordOffset(allMatches, i);
1517  } while (i < allMatches->count && offset == prevoff);
1518 
1519  baseNames = hfd(baseNames, bnt);
1520  dirNames = hfd(dirNames, dnt);
1521  h = headerFree(h);
1522  }
1523 
1524  rec = _free(rec);
1525  allMatches = dbiFreeIndexSet(allMatches);
1526 
1527  fpc = fpCacheFree(fpc);
1528 
1529  if ((*matches)->count == 0) {
1530  *matches = dbiFreeIndexSet(*matches);
1531  return 1;
1532  }
1533 
1534  return 0;
1535 }
1536 
1537 int rpmdbCount(rpmdb db, rpmTag tag, const void * keyp, size_t keylen)
1538 {
1539 DBC * dbcursor = NULL;
1540 DBT * key = alloca(sizeof(*key));
1541 DBT * data = alloca(sizeof(*data));
1542  dbiIndex dbi;
1543  int rc;
1544  int xx;
1545 
1546  if (db == NULL || keyp == NULL)
1547  return 0;
1548 
1549 memset(key, 0, sizeof(*key));
1550 memset(data, 0, sizeof(*data));
1551 
1552  dbi = dbiOpen(db, tag, 0);
1553  if (dbi == NULL)
1554  return 0;
1555 
1556  if (keylen == 0)
1557  keylen = strlen(keyp);
1558 
1559 /*@-temptrans@*/
1560 key->data = (void *) keyp;
1561 /*@=temptrans@*/
1562 key->size = (u_int32_t) keylen;
1563 
1564  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1565  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1566 #ifndef SQLITE_HACK
1567  xx = dbiCclose(dbi, dbcursor, 0);
1568  dbcursor = NULL;
1569 #endif
1570 
1571  if (rc == 0) { /* success */
1572  dbiIndexSet matches;
1573  /*@-nullpass@*/ /* FIX: matches might be NULL */
1574  matches = NULL;
1575  (void) dbt2set(dbi, data, &matches);
1576  if (matches) {
1577  rc = dbiIndexSetCount(matches);
1578  matches = dbiFreeIndexSet(matches);
1579  }
1580  /*@=nullpass@*/
1581  } else
1582  if (rc == DB_NOTFOUND) { /* not found */
1583  rc = 0;
1584  } else { /* error */
1586  _("error(%d) getting \"%s\" records from %s index\n"),
1587  rc, key->data, mapTagName(dbi->dbi_rpmtag));
1588  rc = -1;
1589  }
1590 
1591 #ifdef SQLITE_HACK
1592  xx = dbiCclose(dbi, dbcursor, 0);
1593  dbcursor = NULL;
1594 #endif
1595 
1596  return rc;
1597 }
1598 
1599 /* XXX python/upgrade.c, install.c, uninstall.c */
1600 int rpmdbCountPackages(rpmdb db, const char * name)
1601 {
1602  return rpmdbCount(db, RPMTAG_NAME, name, 0);
1603 }
1604 
1617 static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
1618  DBT * key, DBT * data,
1619  const char * name,
1620  /*@null@*/ const char * version,
1621  /*@null@*/ const char * release,
1622  /*@out@*/ dbiIndexSet * matches)
1623  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1624  /*@modifies dbi, *dbcursor, *key, *data, *matches,
1625  rpmGlobalMacroContext, fileSystem, internalState @*/
1626  /*@requires maxSet(matches) >= 0 @*/
1627 {
1628  int gotMatches = 0;
1629  int rc;
1630  int i;
1631 
1632 /*@-temptrans@*/
1633 key->data = (void *) name;
1634 /*@=temptrans@*/
1635 key->size = strlen(name);
1636 
1637  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1638 
1639  if (rc == 0) { /* success */
1640  (void) dbt2set(dbi, data, matches);
1641  if (version == NULL && release == NULL)
1642  return RPMRC_OK;
1643  } else
1644  if (rc == DB_NOTFOUND) { /* not found */
1645  return RPMRC_NOTFOUND;
1646  } else { /* error */
1648  _("error(%d) getting \"%s\" records from %s index\n"),
1649  rc, key->data, mapTagName(dbi->dbi_rpmtag));
1650  return RPMRC_FAIL;
1651  }
1652 
1653  /* Make sure the version and release match. */
1654  /*@-branchstate@*/
1655  for (i = 0; i < dbiIndexSetCount(*matches); i++) {
1656  unsigned int recoff = dbiIndexRecordOffset(*matches, i);
1657  rpmdbMatchIterator mi;
1658  Header h;
1659 
1660  if (recoff == 0)
1661  continue;
1662 
1663  mi = rpmdbInitIterator(dbi->dbi_rpmdb,
1664  RPMDBI_PACKAGES, &recoff, sizeof(recoff));
1665 
1666  /* Set iterator selectors for version/release if available. */
1667  if (version &&
1668  rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
1669  {
1670  rc = RPMRC_FAIL;
1671  goto exit;
1672  }
1673  if (release &&
1674  rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
1675  {
1676  rc = RPMRC_FAIL;
1677  goto exit;
1678  }
1679 
1680  h = rpmdbNextIterator(mi);
1681 /*@-boundswrite@*/
1682  if (h)
1683  (*matches)->recs[gotMatches++] = (*matches)->recs[i];
1684  else
1685  (*matches)->recs[i].hdrNum = 0;
1686 /*@=boundswrite@*/
1687  mi = rpmdbFreeIterator(mi);
1688  }
1689  /*@=branchstate@*/
1690 
1691  if (gotMatches) {
1692  (*matches)->count = gotMatches;
1693  rc = RPMRC_OK;
1694  } else
1695  rc = RPMRC_NOTFOUND;
1696 
1697 exit:
1698 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1699  if (rc && matches && *matches)
1700  *matches = dbiFreeIndexSet(*matches);
1701 /*@=unqualifiedtrans@*/
1702  return rc;
1703 }
1704 
1717 static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
1718  /*@null@*/ const char * arg, /*@out@*/ dbiIndexSet * matches)
1719  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1720  /*@modifies dbi, *dbcursor, *key, *data, *matches,
1721  rpmGlobalMacroContext, fileSystem, internalState @*/
1722  /*@requires maxSet(matches) >= 0 @*/
1723 {
1724  const char * release;
1725  char * localarg;
1726  char * s;
1727  char c;
1728  int brackets;
1729  rpmRC rc;
1730 
1731  if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND;
1732 
1733  /* did they give us just a name? */
1734  rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches);
1735  if (rc != RPMRC_NOTFOUND) return rc;
1736 
1737  /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1738  *matches = dbiFreeIndexSet(*matches);
1739  /*@=unqualifiedtrans@*/
1740 
1741  /* maybe a name and a release */
1742  localarg = alloca(strlen(arg) + 1);
1743  s = stpcpy(localarg, arg);
1744 
1745  c = '\0';
1746  brackets = 0;
1747  for (s -= 1; s > localarg; s--) {
1748  switch (*s) {
1749  case '[':
1750  brackets = 1;
1751  /*@switchbreak@*/ break;
1752  case ']':
1753  if (c != '[') brackets = 0;
1754  /*@switchbreak@*/ break;
1755  }
1756  c = *s;
1757  if (!brackets && *s == '-')
1758  break;
1759  }
1760 
1761  /*@-nullstate@*/ /* FIX: *matches may be NULL. */
1762  if (s == localarg) return RPMRC_NOTFOUND;
1763 
1764 /*@-boundswrite@*/
1765  *s = '\0';
1766 /*@=boundswrite@*/
1767  rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches);
1768  /*@=nullstate@*/
1769  if (rc != RPMRC_NOTFOUND) return rc;
1770 
1771  /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1772  *matches = dbiFreeIndexSet(*matches);
1773  /*@=unqualifiedtrans@*/
1774 
1775  /* how about name-version-release? */
1776 
1777  release = s + 1;
1778 
1779  c = '\0';
1780  brackets = 0;
1781  for (; s > localarg; s--) {
1782  switch (*s) {
1783  case '[':
1784  brackets = 1;
1785  /*@switchbreak@*/ break;
1786  case ']':
1787  if (c != '[') brackets = 0;
1788  /*@switchbreak@*/ break;
1789  }
1790  c = *s;
1791  if (!brackets && *s == '-')
1792  break;
1793  }
1794 
1795  if (s == localarg) return RPMRC_NOTFOUND;
1796 
1797 /*@-boundswrite@*/
1798  *s = '\0';
1799 /*@=boundswrite@*/
1800  /*@-nullstate@*/ /* FIX: *matches may be NULL. */
1801  return dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches);
1802  /*@=nullstate@*/
1803 }
1804 
1805 void * dbiStatsAccumulator(dbiIndex dbi, int opx)
1806 {
1807  void * sw = NULL;
1808  switch (opx) {
1809  case 14: /* RPMTS_OP_DBGET */
1810  sw = &dbi->dbi_rpmdb->db_getops;
1811  break;
1812  case 15: /* RPMTS_OP_DBPUT */
1813  sw = &dbi->dbi_rpmdb->db_putops;
1814  break;
1815  default: /* XXX wrong, but let's not return NULL. */
1816  case 16: /* RPMTS_OP_DBDEL */
1817  sw = &dbi->dbi_rpmdb->db_delops;
1818  break;
1819  }
1820  return sw;
1821 }
1822 
1832  /*@globals fileSystem, internalState @*/
1833  /*@modifies mi, dbi, fileSystem, internalState @*/
1834 {
1835  int rc = 0;
1836 
1837  if (mi == NULL || mi->mi_h == NULL)
1838  return 0;
1839 
1840  if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
1841  DBT * key = &mi->mi_key;
1842  DBT * data = &mi->mi_data;
1843  sigset_t signalMask;
1844  rpmRC rpmrc = RPMRC_NOTFOUND;
1845  int xx;
1846 
1847 /*@i@*/ key->data = (void *) &mi->mi_prevoffset;
1848  key->size = sizeof(mi->mi_prevoffset);
1849  data->data = headerUnload(mi->mi_h);
1850  data->size = headerSizeof(mi->mi_h, HEADER_MAGIC_NO);
1851 
1852  /* Check header digest/signature on blob export (if requested). */
1853  if (mi->mi_hdrchk && mi->mi_ts) {
1854  const char * msg = NULL;
1855  int lvl;
1856 
1857  rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, data->data, data->size, &msg);
1858  lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG);
1859  rpmMessage(lvl, "%s h#%8u %s",
1860  (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping") : "write"),
1861  mi->mi_prevoffset, (msg ? msg : "\n"));
1862  msg = _free(msg);
1863  }
1864 
1865  if (data->data != NULL && rpmrc != RPMRC_FAIL) {
1866  (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
1867  rc = dbiPut(dbi, mi->mi_dbc, key, data, DB_KEYLAST);
1868  if (rc) {
1870  _("error(%d) storing record #%d into %s\n"),
1871  rc, mi->mi_prevoffset, mapTagName(dbi->dbi_rpmtag));
1872  }
1873  xx = dbiSync(dbi, 0);
1874  (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
1875  }
1876  data->data = _free(data->data);
1877  data->size = 0;
1878  }
1879 
1880  mi->mi_h = headerFree(mi->mi_h);
1881 
1882 /*@-nullstate@*/
1883  return rc;
1884 /*@=nullstate@*/
1885 }
1886 
1888  /*@globals rpmmiRock @*/
1889  /*@modifies rpmmiRock @*/
1890 {
1891  rpmdbMatchIterator * prev, next;
1892  dbiIndex dbi;
1893  int xx;
1894  int i;
1895 
1896  if (mi == NULL)
1897  return NULL;
1898 
1899  prev = &rpmmiRock;
1900  while ((next = *prev) != NULL && next != mi)
1901  prev = &next->mi_next;
1902  if (next) {
1903 /*@i@*/ *prev = next->mi_next;
1904  next->mi_next = NULL;
1905  }
1906 
1907  dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
1908  if (dbi == NULL) /* XXX can't happen */
1909  return NULL;
1910 
1911  xx = miFreeHeader(mi, dbi);
1912 
1913  if (mi->mi_dbc)
1914  xx = dbiCclose(dbi, mi->mi_dbc, 0);
1915  mi->mi_dbc = NULL;
1916 
1917  if (mi->mi_re != NULL)
1918  for (i = 0; i < mi->mi_nre; i++)
1919  xx = mireClean(mi->mi_re + i);
1920  mi->mi_re = _free(mi->mi_re);
1921 
1922  mi->mi_set = dbiFreeIndexSet(mi->mi_set);
1923  mi->mi_keyp = _free(mi->mi_keyp);
1924  mi->mi_db = rpmdbUnlink(mi->mi_db, "matchIterator");
1925 
1926  mi = _free(mi);
1927 
1928  (void) rpmdbCheckSignals();
1929 
1930  return mi;
1931 }
1932 
1934  return (mi ? mi->mi_offset : 0);
1935 }
1936 
1938  return (mi ? mi->mi_filenum : 0);
1939 }
1940 
1942  return (mi && mi->mi_set ? mi->mi_set->count : 0);
1943 }
1944 
1951 static int mireCmp(const void * a, const void * b)
1952 {
1953  const miRE mireA = (const miRE) a;
1954  const miRE mireB = (const miRE) b;
1955  return (mireA->tag - mireB->tag);
1956 }
1957 
1965 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep,
1966  const char * pattern)
1967  /*@modifies *modep @*/
1968  /*@requires maxSet(modep) >= 0 @*/
1969 {
1970  const char * s;
1971  char * pat;
1972  char * t;
1973  int brackets;
1974  size_t nb;
1975  int c;
1976 
1977 /*@-boundswrite@*/
1978  switch (*modep) {
1979  default:
1980  case RPMMIRE_DEFAULT:
1981  if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
1982  *modep = RPMMIRE_GLOB;
1983  pat = xstrdup(pattern);
1984  break;
1985  }
1986 
1987  nb = strlen(pattern) + sizeof("^$");
1988 
1989  /* Find no. of bytes needed for pattern. */
1990  /* periods and plusses are escaped, splats become '.*' */
1991  c = '\0';
1992  brackets = 0;
1993  for (s = pattern; *s != '\0'; s++) {
1994  switch (*s) {
1995  case '.':
1996  case '+':
1997  case '*':
1998  if (!brackets) nb++;
1999  /*@switchbreak@*/ break;
2000  case '\\':
2001  s++;
2002  /*@switchbreak@*/ break;
2003  case '[':
2004  brackets = 1;
2005  /*@switchbreak@*/ break;
2006  case ']':
2007  if (c != '[') brackets = 0;
2008  /*@switchbreak@*/ break;
2009  }
2010  c = *s;
2011  }
2012 
2013  pat = t = xmalloc(nb);
2014 
2015  if (pattern[0] != '^') *t++ = '^';
2016 
2017  /* Copy pattern, escaping periods, prefixing splats with period. */
2018  c = '\0';
2019  brackets = 0;
2020  for (s = pattern; *s != '\0'; s++, t++) {
2021  switch (*s) {
2022  case '.':
2023  case '+':
2024  if (!brackets) *t++ = '\\';
2025  /*@switchbreak@*/ break;
2026  case '*':
2027  if (!brackets) *t++ = '.';
2028  /*@switchbreak@*/ break;
2029  case '\\':
2030  *t++ = *s++;
2031  /*@switchbreak@*/ break;
2032  case '[':
2033  brackets = 1;
2034  /*@switchbreak@*/ break;
2035  case ']':
2036  if (c != '[') brackets = 0;
2037  /*@switchbreak@*/ break;
2038  }
2039  c = *t = *s;
2040  }
2041 
2042  if (s > pattern && s[-1] != '$') *t++ = '$';
2043  *t = '\0';
2044  *modep = RPMMIRE_REGEX;
2045  break;
2046  case RPMMIRE_STRCMP:
2047  case RPMMIRE_REGEX:
2048  case RPMMIRE_GLOB:
2049  pat = xstrdup(pattern);
2050  break;
2051  }
2052 /*@-boundswrite@*/
2053 
2054  return pat;
2055 }
2056 
2058  rpmMireMode mode, const char * pattern)
2059 {
2060  static rpmMireMode defmode = (rpmMireMode)-1;
2061  miRE nmire = NULL;
2062  miRE mire = NULL;
2063  const char * allpat = NULL;
2064  int notmatch = 0;
2065  int rc = 0;
2066 
2067 /*@-boundsread@*/
2068  if (defmode == (rpmMireMode)-1) {
2069  const char *t = rpmExpand("%{?_query_selector_match}", NULL);
2070 
2071  if (*t == '\0' || !strcmp(t, "default"))
2072  defmode = RPMMIRE_DEFAULT;
2073  else if (!strcmp(t, "strcmp"))
2074  defmode = RPMMIRE_STRCMP;
2075  else if (!strcmp(t, "regex"))
2076  defmode = RPMMIRE_REGEX;
2077  else if (!strcmp(t, "glob"))
2078  defmode = RPMMIRE_GLOB;
2079  else
2080  defmode = RPMMIRE_DEFAULT;
2081  t = _free(t);
2082  }
2083 
2084  if (mi == NULL || pattern == NULL)
2085  return rc;
2086 
2087  /* Leading '!' inverts pattern match sense, like "grep -v". */
2088  if (*pattern == '!') {
2089  notmatch = 1;
2090  pattern++;
2091  }
2092 /*@=boundsread@*/
2093 
2094  nmire = mireNew(mode, tag);
2095 /*@-boundswrite@*/
2096  allpat = mireDup(nmire->tag, &nmire->mode, pattern);
2097 /*@=boundswrite@*/
2098 
2099  if (nmire->mode == RPMMIRE_DEFAULT)
2100  nmire->mode = defmode;
2101 
2102  rc = mireRegcomp(nmire, allpat);
2103  if (rc)
2104  goto exit;
2105 
2106  mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
2107  mire = mi->mi_re + mi->mi_nre;
2108  mi->mi_nre++;
2109 
2110  mire->mode = nmire->mode;
2111  mire->pattern = nmire->pattern; nmire->pattern = NULL;
2112  mire->preg = nmire->preg; nmire->preg = NULL;
2113  mire->cflags = nmire->cflags;
2114  mire->eflags = nmire->eflags;
2115  mire->fnflags = nmire->fnflags;
2116  mire->tag = nmire->tag;
2117  mire->notmatch = notmatch;
2118 
2119 /*@-boundsread@*/
2120  if (mi->mi_nre > 1)
2121  qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
2122 /*@=boundsread@*/
2123 
2124 exit:
2125  allpat = _free(allpat);
2126  nmire = mireFree(nmire);
2127  return rc;
2128 }
2129 
2135 static int mireSkip (const rpmdbMatchIterator mi)
2136  /*@modifies mi->mi_re @*/
2137 {
2139  HFD_t hfd = (HFD_t) headerFreeData;
2140  union {
2141  void * ptr;
2142  const char ** argv;
2143  const char * str;
2144  int_32 * i32p;
2145  int_16 * i16p;
2146  int_8 * i8p;
2147  } u;
2148  char numbuf[32];
2149  rpmTagType t;
2150  int_32 c;
2151  miRE mire;
2152  static int_32 zero = 0;
2153  int ntags = 0;
2154  int nmatches = 0;
2155  int i, j;
2156  int rc;
2157 
2158  if (mi->mi_h == NULL) /* XXX can't happen */
2159  return 1;
2160 
2161  /*
2162  * Apply tag tests, implicitly "||" for multiple patterns/values of a
2163  * single tag, implicitly "&&" between multiple tag patterns.
2164  */
2165 /*@-boundsread@*/
2166  if ((mire = mi->mi_re) == NULL)
2167  return 0;
2168 
2169  for (i = 0; i < mi->mi_nre; i++, mire++) {
2170  int anymatch;
2171 
2172  if (!hge(mi->mi_h, mire->tag, &t, (void **)&u, &c)) {
2173  if (mire->tag != RPMTAG_EPOCH)
2174  continue;
2175  t = RPM_INT32_TYPE;
2176 /*@-immediatetrans@*/
2177  u.i32p = &zero;
2178 /*@=immediatetrans@*/
2179  c = 1;
2180  }
2181 
2182  anymatch = 0; /* no matches yet */
2183  while (1) {
2184  switch (t) {
2185  case RPM_CHAR_TYPE:
2186  case RPM_INT8_TYPE:
2187  sprintf(numbuf, "%d", (int) *u.i8p);
2188  rc = mireRegexec(mire, numbuf);
2189  if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2190  anymatch++;
2191  /*@switchbreak@*/ break;
2192  case RPM_INT16_TYPE:
2193  sprintf(numbuf, "%d", (int) *u.i16p);
2194  rc = mireRegexec(mire, numbuf);
2195  if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2196  anymatch++;
2197  /*@switchbreak@*/ break;
2198  case RPM_INT32_TYPE:
2199  sprintf(numbuf, "%d", (int) *u.i32p);
2200  rc = mireRegexec(mire, numbuf);
2201  if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2202  anymatch++;
2203  /*@switchbreak@*/ break;
2204  case RPM_STRING_TYPE:
2205  rc = mireRegexec(mire, u.str);
2206  if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2207  anymatch++;
2208  /*@switchbreak@*/ break;
2209  case RPM_I18NSTRING_TYPE:
2210  case RPM_STRING_ARRAY_TYPE:
2211  for (j = 0; j < c; j++) {
2212  rc = mireRegexec(mire, u.argv[j]);
2213  if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) {
2214  anymatch++;
2215  /*@innerbreak@*/ break;
2216  }
2217  }
2218  /*@switchbreak@*/ break;
2219  case RPM_NULL_TYPE:
2220  case RPM_BIN_TYPE:
2221  default:
2222  /*@switchbreak@*/ break;
2223  }
2224  if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
2225  i++;
2226  mire++;
2227  /*@innercontinue@*/ continue;
2228  }
2229  /*@innerbreak@*/ break;
2230  }
2231 /*@=boundsread@*/
2232 
2233  u.ptr = hfd(u.ptr, t);
2234 
2235  ntags++;
2236  if (anymatch)
2237  nmatches++;
2238  }
2239 
2240  return (ntags > 0 && ntags == nmatches ? 0 : 1);
2241 }
2242 
2244 {
2245  int rc;
2246  if (mi == NULL)
2247  return 0;
2248  rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
2249  if (rewrite)
2250  mi->mi_cflags |= DB_WRITECURSOR;
2251  else
2252  mi->mi_cflags &= ~DB_WRITECURSOR;
2253  return rc;
2254 }
2255 
2257 {
2258  int rc;
2259  if (mi == NULL)
2260  return 0;
2261  rc = mi->mi_modified;
2262  mi->mi_modified = modified;
2263  return rc;
2264 }
2265 
2267  rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
2268 {
2269  int rc = 0;
2270  if (mi == NULL)
2271  return 0;
2272 /*@-assignexpose -newreftrans @*/ /* XXX forward linkage prevents rpmtsLink */
2273 /*@i@*/ mi->mi_ts = ts;
2274  mi->mi_hdrchk = hdrchk;
2275 /*@=assignexpose =newreftrans @*/
2276  return rc;
2277 }
2278 
2279 
2280 /*@-nullstate@*/ /* FIX: mi->mi_key.data may be NULL */
2282 {
2283  dbiIndex dbi;
2284  void * uh;
2285  size_t uhlen;
2286  DBT * key;
2287  DBT * data;
2288  void * keyp;
2289  size_t keylen;
2290  int rc;
2291  int xx;
2292 
2293  if (mi == NULL)
2294  return NULL;
2295 
2296  dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
2297  if (dbi == NULL)
2298  return NULL;
2299 
2300  /*
2301  * Cursors are per-iterator, not per-dbi, so get a cursor for the
2302  * iterator on 1st call. If the iteration is to rewrite headers, and the
2303  * CDB model is used for the database, then the cursor needs to
2304  * marked with DB_WRITECURSOR as well.
2305  */
2306  if (mi->mi_dbc == NULL)
2307  xx = dbiCopen(dbi, dbi->dbi_txnid, &mi->mi_dbc, mi->mi_cflags);
2308 
2309 /*@-boundswrite@*/
2310  key = &mi->mi_key;
2311  memset(key, 0, sizeof(*key));
2312  data = &mi->mi_data;
2313  memset(data, 0, sizeof(*data));
2314 /*@=boundswrite@*/
2315 
2316 top:
2317  uh = NULL;
2318  uhlen = 0;
2319 
2320  do {
2321 union _dbswap mi_offset;
2322 
2323  /*@-branchstate -compmempass @*/
2324  if (mi->mi_set) {
2325  if (!(mi->mi_setx < mi->mi_set->count))
2326  return NULL;
2327  mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
2329 mi_offset.ui = mi->mi_offset;
2330 if (dbiByteSwapped(dbi) == 1)
2331  _DBSWAP(mi_offset);
2332  keyp = &mi_offset;
2333  keylen = sizeof(mi_offset.ui);
2334  } else {
2335 
2336  key->data = keyp = (void *)mi->mi_keyp;
2337  key->size = keylen = mi->mi_keylen;
2338  data->data = uh;
2339  data->size = uhlen;
2340 #if !defined(_USE_COPY_LOAD)
2341  data->flags |= DB_DBT_MALLOC;
2342 #endif
2343  rc = dbiGet(dbi, mi->mi_dbc, key, data,
2344  (key->data == NULL ? DB_NEXT : DB_SET));
2345  data->flags = 0;
2346  keyp = key->data;
2347  keylen = key->size;
2348  uh = data->data;
2349  uhlen = data->size;
2350 
2351  /*
2352  * If we got the next key, save the header instance number.
2353  *
2354  * For db3 Packages, instance 0 (i.e. mi->mi_setx == 0) is the
2355  * largest header instance in the database, and should be
2356  * skipped.
2357  */
2358 /*@-boundswrite@*/
2359  if (keyp && mi->mi_setx && rc == 0) {
2360  memcpy(&mi_offset, keyp, sizeof(mi_offset.ui));
2361 if (dbiByteSwapped(dbi) == 1)
2362  _DBSWAP(mi_offset);
2363  mi->mi_offset = mi_offset.ui;
2364  }
2365 /*@=boundswrite@*/
2366 
2367  /* Terminate on error or end of keys */
2368  if (rc || (mi->mi_setx && mi->mi_offset == 0))
2369  return NULL;
2370  }
2371  /*@=branchstate =compmempass @*/
2372  mi->mi_setx++;
2373  } while (mi->mi_offset == 0);
2374 
2375  /* If next header is identical, return it now. */
2376 /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
2377  if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
2378  return mi->mi_h;
2379 /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
2380 
2381  /* Retrieve next header blob for index iterator. */
2382  /*@-branchstate -compmempass -immediatetrans @*/
2383  if (uh == NULL) {
2384  key->data = keyp;
2385  key->size = keylen;
2386 #if !defined(_USE_COPY_LOAD)
2387  data->flags |= DB_DBT_MALLOC;
2388 #endif
2389  rc = dbiGet(dbi, mi->mi_dbc, key, data, DB_SET);
2390  data->flags = 0;
2391  keyp = key->data;
2392  keylen = key->size;
2393  uh = data->data;
2394  uhlen = data->size;
2395  if (rc)
2396  return NULL;
2397  }
2398  /*@=branchstate =compmempass =immediatetrans @*/
2399 
2400  /* Rewrite current header (if necessary) and unlink. */
2401  xx = miFreeHeader(mi, dbi);
2402 
2403  /* Is this the end of the iteration? */
2404  if (uh == NULL)
2405  return NULL;
2406 
2407  /* Check header digest/signature once (if requested). */
2408 /*@-boundsread -branchstate -sizeoftype @*/
2409  if (mi->mi_hdrchk && mi->mi_ts) {
2410  rpmRC rpmrc = RPMRC_NOTFOUND;
2411 
2412  /* Don't bother re-checking a previously read header. */
2413  if (mi->mi_db->db_bits) {
2414  pbm_set * set;
2415 
2416  set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
2417  &mi->mi_db->db_nbits, mi->mi_offset);
2418  if (PBM_ISSET(mi->mi_offset, set))
2419  rpmrc = RPMRC_OK;
2420  }
2421 
2422  /* If blob is unchecked, check blob import consistency now. */
2423  if (rpmrc != RPMRC_OK) {
2424  const char * msg = NULL;
2425  int lvl;
2426 
2427  rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg);
2428  lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG);
2429  rpmMessage(lvl, "%s h#%8u %s",
2430  (rpmrc == RPMRC_FAIL ? _("rpmdbNextIterator: skipping") : " read"),
2431  mi->mi_offset, (msg ? msg : "\n"));
2432  msg = _free(msg);
2433 
2434  /* Mark header checked. */
2435  if (mi->mi_db && mi->mi_db->db_bits && rpmrc == RPMRC_OK) {
2436  pbm_set * set;
2437 
2438  set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
2439  &mi->mi_db->db_nbits, mi->mi_offset);
2440  PBM_SET(mi->mi_offset, set);
2441  }
2442 
2443  /* Skip damaged and inconsistent headers. */
2444  if (rpmrc == RPMRC_FAIL)
2445  goto top;
2446  }
2447  }
2448 /*@=boundsread =branchstate =sizeoftype @*/
2449 
2450  /* Did the header blob load correctly? */
2451 #if !defined(_USE_COPY_LOAD)
2452 /*@-onlytrans@*/
2453  mi->mi_h = headerLoad(uh);
2454 /*@=onlytrans@*/
2455  if (mi->mi_h)
2457 #else
2458  mi->mi_h = headerCopyLoad(uh);
2459 #endif
2460  if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
2462  _("rpmdb: damaged header #%u retrieved -- skipping.\n"),
2463  mi->mi_offset);
2464  goto top;
2465  }
2466 
2467  /*
2468  * Skip this header if iterator selector (if any) doesn't match.
2469  */
2470  if (mireSkip(mi)) {
2471  /* XXX hack, can't restart with Packages locked on single instance. */
2472  if (mi->mi_set || mi->mi_keyp == NULL)
2473  goto top;
2474  return NULL;
2475  }
2476 
2477  /* Mark header with its instance number. */
2478  { char origin[32];
2479  sprintf(origin, "rpmdb (h#%u)", mi->mi_offset);
2480  (void) headerSetOrigin(mi->mi_h, origin);
2481  (void) headerSetInstance(mi->mi_h, mi->mi_offset);
2482  }
2483 
2484  mi->mi_prevoffset = mi->mi_offset;
2485  mi->mi_modified = 0;
2486 
2487 /*@-compdef -retalias -retexpose -usereleased @*/
2488  return mi->mi_h;
2489 /*@=compdef =retalias =retexpose =usereleased @*/
2490 }
2491 /*@=nullstate@*/
2492 
2493 static void rpmdbSortIterator(/*@null@*/ rpmdbMatchIterator mi)
2494  /*@modifies mi @*/
2495 {
2496  if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
2497  /*
2498  * mergesort is much (~10x with lots of identical basenames) faster
2499  * than pure quicksort, but glibc uses msort_with_tmp() on stack.
2500  */
2501 #if defined(__GLIBC__)
2502 /*@-boundsread@*/
2503  qsort(mi->mi_set->recs, mi->mi_set->count,
2504  sizeof(*mi->mi_set->recs), hdrNumCmp);
2505 /*@=boundsread@*/
2506 #else
2507  mergesort(mi->mi_set->recs, mi->mi_set->count,
2508  sizeof(*mi->mi_set->recs), hdrNumCmp);
2509 #endif
2510  mi->mi_sorted = 1;
2511  }
2512 }
2513 
2514 /*@-bounds@*/ /* LCL: segfault */
2515 static int rpmdbGrowIterator(/*@null@*/ rpmdbMatchIterator mi, int fpNum,
2516  unsigned int exclude, unsigned int tag)
2517  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2518  /*@modifies mi, rpmGlobalMacroContext, fileSystem, internalState @*/
2519 {
2520  DBC * dbcursor;
2521  DBT * key;
2522  DBT * data;
2523  dbiIndex dbi = NULL;
2524  dbiIndexSet set;
2525  int rc;
2526  int xx;
2527  int i, j;
2528 
2529  if (mi == NULL)
2530  return 1;
2531 
2532  dbcursor = mi->mi_dbc;
2533  key = &mi->mi_key;
2534  data = &mi->mi_data;
2535  if (key->data == NULL)
2536  return 1;
2537 
2538  dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
2539  if (dbi == NULL)
2540  return 1;
2541 
2542  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2543  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2544 #ifndef SQLITE_HACK
2545  xx = dbiCclose(dbi, dbcursor, 0);
2546  dbcursor = NULL;
2547 #endif
2548 
2549  if (rc) { /* error/not found */
2550  if (rc != DB_NOTFOUND)
2552  _("error(%d) getting \"%s\" records from %s index\n"),
2553  rc, key->data, mapTagName(dbi->dbi_rpmtag));
2554 #ifdef SQLITE_HACK
2555  xx = dbiCclose(dbi, dbcursor, 0);
2556  dbcursor = NULL;
2557 #endif
2558  return rc;
2559  }
2560 
2561  set = NULL;
2562  (void) dbt2set(dbi, data, &set);
2563 
2564  /* prune the set against exclude and tag */
2565  for (i = j = 0; i < set->count; i++) {
2566  if (exclude && set->recs[i].hdrNum == exclude)
2567  continue;
2568  if (_db_tagged_file_indices && set->recs[i].tagNum & 0x80000000) {
2569  /* tagged entry */
2570  if ((set->recs[i].tagNum & 0xffff0000) != tag)
2571  continue;
2572  set->recs[i].tagNum &= 0x0000ffff;
2573  }
2574  if (i > j)
2575  set->recs[j] = set->recs[i];
2576  j++;
2577  }
2578  if (j == 0) {
2579 #ifdef SQLITE_HACK
2580  xx = dbiCclose(dbi, dbcursor, 0);
2581  dbcursor = NULL;
2582 #endif
2583  set = dbiFreeIndexSet(set);
2584  return DB_NOTFOUND;
2585  }
2586  set->count = j;
2587 
2588  for (i = 0; i < set->count; i++)
2589  set->recs[i].fpNum = fpNum;
2590 
2591 #ifdef SQLITE_HACK
2592  xx = dbiCclose(dbi, dbcursor, 0);
2593  dbcursor = NULL;
2594 #endif
2595 
2596 /*@-branchstate@*/
2597  if (mi->mi_set == NULL) {
2598  mi->mi_set = set;
2599  } else {
2600 #if 0
2601 fprintf(stderr, "+++ %d = %d + %d\t\"%s\"\n", (mi->mi_set->count + set->count), mi->mi_set->count, set->count, ((char *)key->data));
2602 #endif
2603  mi->mi_set->recs = xrealloc(mi->mi_set->recs,
2604  (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
2605  memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
2606  set->count * sizeof(*(mi->mi_set->recs)));
2607  mi->mi_set->count += set->count;
2608  set = dbiFreeIndexSet(set);
2609  }
2610 /*@=branchstate@*/
2611 
2612  return rc;
2613 }
2614 /*@=bounds@*/
2615 
2617  int nHdrNums, int sorted)
2618 {
2619  if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2620  return 1;
2621 
2622  if (mi->mi_set)
2623  (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
2624  return 0;
2625 }
2626 
2627 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
2628 {
2629  if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2630  return 1;
2631 
2632  if (mi->mi_set == NULL)
2633  mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
2634  (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
2635  return 0;
2636 }
2637 
2639  const void * keyp, size_t keylen)
2640  /*@globals rpmmiRock @*/
2641  /*@modifies rpmmiRock @*/
2642 {
2643  rpmdbMatchIterator mi;
2644  DBT * key;
2645  DBT * data;
2646  dbiIndexSet set = NULL;
2647  dbiIndex dbi;
2648  const void * mi_keyp = NULL;
2649  int isLabel = 0;
2650 
2651  if (db == NULL)
2652  return NULL;
2653 
2654  (void) rpmdbCheckSignals();
2655 
2656  /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */
2657  if (rpmtag == RPMDBI_LABEL) {
2658  rpmtag = RPMTAG_NAME;
2659  isLabel = 1;
2660  }
2661 
2662  dbi = dbiOpen(db, rpmtag, 0);
2663  if (dbi == NULL)
2664  return NULL;
2665 
2666  /* Chain cursors for teardown on abnormal exit. */
2667  mi = xcalloc(1, sizeof(*mi));
2668  mi->mi_next = rpmmiRock;
2669  rpmmiRock = mi;
2670 
2671  key = &mi->mi_key;
2672  data = &mi->mi_data;
2673 
2674  /*
2675  * Handle label and file name special cases.
2676  * Otherwise, retrieve join keys for secondary lookup.
2677  */
2678 /*@-branchstate@*/
2679  if (rpmtag != RPMDBI_PACKAGES && keyp) {
2680  DBC * dbcursor = NULL;
2681  int rc;
2682  int xx;
2683 
2684  if (isLabel) {
2685  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2686  rc = dbiFindByLabel(dbi, dbcursor, key, data, keyp, &set);
2687  xx = dbiCclose(dbi, dbcursor, 0);
2688  dbcursor = NULL;
2689  } else if (rpmtag == RPMTAG_BASENAMES) {
2690  rc = rpmdbFindByFile(db, keyp, key, data, &set);
2691  } else {
2692  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2693 
2694 /*@-temptrans@*/
2695 key->data = (void *) keyp;
2696 /*@=temptrans@*/
2697 key->size = keylen;
2698 if (key->data && key->size == 0) key->size = strlen((char *)key->data);
2699 if (key->data && key->size == 0) key->size++; /* XXX "/" fixup. */
2700 
2701 /*@-nullstate@*/
2702  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2703 /*@=nullstate@*/
2704  if (rc > 0) {
2706  _("error(%d) getting \"%s\" records from %s index\n"),
2707  rc, (key->data ? key->data : "???"), mapTagName(dbi->dbi_rpmtag));
2708  }
2709 
2710  /* Join keys need to be native endian internally. */
2711  if (rc == 0)
2712  (void) dbt2set(dbi, data, &set);
2713 
2714  xx = dbiCclose(dbi, dbcursor, 0);
2715  dbcursor = NULL;
2716  }
2717  if (rc) { /* error/not found */
2718  set = dbiFreeIndexSet(set);
2719  rpmmiRock = mi->mi_next;
2720  mi->mi_next = NULL;
2721  mi = _free(mi);
2722  return NULL;
2723  }
2724  }
2725 /*@=branchstate@*/
2726 
2727  /* Copy the retrieval key, byte swapping header instance if necessary. */
2728  if (keyp) {
2729  switch (rpmtag) {
2730  case RPMDBI_PACKAGES:
2731  { union _dbswap *k;
2732 
2733 assert(keylen == sizeof(k->ui)); /* xxx programmer error */
2734  k = xmalloc(sizeof(*k));
2735  memcpy(k, keyp, keylen);
2736  if (dbiByteSwapped(dbi) == 1)
2737  _DBSWAP(*k);
2738  mi_keyp = k;
2739  } break;
2740  default:
2741  { char * k;
2742  if (keylen == 0)
2743  keylen = strlen(keyp);
2744  k = xmalloc(keylen + 1);
2745 /*@-boundsread@*/
2746  memcpy(k, keyp, keylen);
2747 /*@=boundsread@*/
2748  k[keylen] = '\0'; /* XXX assumes strings */
2749  mi_keyp = k;
2750  } break;
2751  }
2752  }
2753 
2754  mi->mi_keyp = mi_keyp;
2755  mi->mi_keylen = keylen;
2756 
2757  mi->mi_db = rpmdbLink(db, "matchIterator");
2758  mi->mi_rpmtag = rpmtag;
2759 
2760  mi->mi_dbc = NULL;
2761  mi->mi_set = set;
2762  mi->mi_setx = 0;
2763  mi->mi_h = NULL;
2764  mi->mi_sorted = 0;
2765  mi->mi_cflags = 0;
2766  mi->mi_modified = 0;
2767  mi->mi_prevoffset = 0;
2768  mi->mi_offset = 0;
2769  mi->mi_filenum = 0;
2770  mi->mi_nre = 0;
2771  mi->mi_re = NULL;
2772 
2773  mi->mi_ts = NULL;
2774  mi->mi_hdrchk = NULL;
2775 
2776 /*@i@*/ return mi;
2777 }
2778 
2779 /* XXX psm.c */
2780 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum,
2781  /*@unused@*/ rpmts ts,
2782  /*@unused@*/ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
2783 {
2784 DBC * dbcursor = NULL;
2785 DBT * key = alloca(sizeof(*key));
2786 DBT * data = alloca(sizeof(*data));
2787 union _dbswap mi_offset;
2789  HFD_t hfd = headerFreeData;
2790  Header h;
2791  sigset_t signalMask;
2792  int ret = 0;
2793  int rc = 0;
2794 
2795  if (db == NULL)
2796  return 0;
2797 
2798 memset(key, 0, sizeof(*key));
2799 memset(data, 0, sizeof(*data));
2800 
2801  { rpmdbMatchIterator mi;
2802  mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
2803  h = rpmdbNextIterator(mi);
2804  if (h)
2805  h = headerLink(h);
2806  mi = rpmdbFreeIterator(mi);
2807  }
2808 
2809  if (h == NULL) {
2810  rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
2811  "rpmdbRemove", hdrNum);
2812  return 1;
2813  }
2814 
2815 #ifdef DYING
2816  /* Add remove transaction id to header. */
2817  if (rid != 0 && rid != -1) {
2818  int_32 tid = rid;
2819  (void) headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
2820  }
2821 #endif
2822 
2823  { const char *n, *v, *r;
2824  (void) headerNVR(h, &n, &v, &r);
2825  rpmMessage(RPMMESS_DEBUG, " --- h#%8u %s-%s-%s\n", hdrNum, n, v, r);
2826  }
2827 
2828  (void) blockSignals(db, &signalMask);
2829 
2830  /*@-nullpass -nullptrarith -nullderef @*/ /* FIX: rpmvals heartburn */
2831  { int dbix;
2832  dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
2833 
2834  if (db->db_tagn != NULL)
2835  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
2836  dbiIndex dbi;
2837  const char *av[1];
2838  const char ** rpmvals = NULL;
2839  byte * bin = NULL;
2840  rpmTagType rpmtype = 0;
2841  int rpmcnt = 0;
2842  int rpmtag;
2843  int xx;
2844  int i, j;
2845 
2846  dbi = NULL;
2847 /*@-boundsread@*/
2848  rpmtag = db->db_tagn[dbix];
2849 /*@=boundsread@*/
2850 
2851  /*@-branchstate@*/
2852  switch (rpmtag) {
2853  /* Filter out temporary databases */
2854  case RPMDBI_AVAILABLE:
2855  case RPMDBI_ADDED:
2856  case RPMDBI_REMOVED:
2857  case RPMDBI_DEPENDS:
2858  continue;
2859  /*@notreached@*/ /*@switchbreak@*/ break;
2860  case RPMDBI_PACKAGES:
2861  if (db->db_export != NULL)
2862  xx = db->db_export(db, h, 0);
2863  dbi = dbiOpen(db, rpmtag, 0);
2864  if (dbi == NULL) /* XXX shouldn't happen */
2865  continue;
2866 
2867 /*@-immediatetrans@*/
2868 mi_offset.ui = hdrNum;
2869 if (dbiByteSwapped(dbi) == 1)
2870  _DBSWAP(mi_offset);
2871  key->data = &mi_offset;
2872 /*@=immediatetrans@*/
2873  key->size = sizeof(mi_offset.ui);
2874 
2875  rc = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2876  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2877  if (rc) {
2879  _("error(%d) setting header #%d record for %s removal\n"),
2880  rc, hdrNum, mapTagName(dbi->dbi_rpmtag));
2881  } else
2882  rc = dbiDel(dbi, dbcursor, key, data, 0);
2883  xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2884  dbcursor = NULL;
2885  if (!dbi->dbi_no_dbsync)
2886  xx = dbiSync(dbi, 0);
2887  continue;
2888  /*@notreached@*/ /*@switchbreak@*/ break;
2889  }
2890  /*@=branchstate@*/
2891 
2892  if (!hge(h, rpmtag, &rpmtype, &rpmvals, &rpmcnt))
2893  continue;
2894 
2895  dbi = dbiOpen(db, rpmtag, 0);
2896  if (dbi != NULL) {
2897  int printed;
2898 
2899  if (rpmtype == RPM_STRING_TYPE) {
2900  /* XXX force uniform headerGetEntry return */
2901  av[0] = (const char *) rpmvals;
2902  rpmvals = av;
2903  rpmcnt = 1;
2904  }
2905 
2906  printed = 0;
2907  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2908 /*@-branchstate@*/
2909  for (i = 0; i < rpmcnt; i++) {
2910  dbiIndexSet set;
2911  int stringvalued;
2912 
2913  bin = _free(bin);
2914  switch (dbi->dbi_rpmtag) {
2915  case RPMTAG_FILEDIGESTS:
2916  /* Filter out empty file digests. */
2917  if (!(rpmvals[i] && *rpmvals[i] != '\0'))
2918  /*@innercontinue@*/ continue;
2919  /*@switchbreak@*/ break;
2920  default:
2921  /*@switchbreak@*/ break;
2922  }
2923 
2924  /* Identify value pointer and length. */
2925  stringvalued = 0;
2926  switch (rpmtype) {
2927 /*@-sizeoftype@*/
2928  case RPM_CHAR_TYPE:
2929  case RPM_INT8_TYPE:
2930  key->size = sizeof(RPM_CHAR_TYPE);
2931  key->data = rpmvals + i;
2932  /*@switchbreak@*/ break;
2933  case RPM_INT16_TYPE:
2934  key->size = sizeof(int_16);
2935  key->data = rpmvals + i;
2936  /*@switchbreak@*/ break;
2937  case RPM_INT32_TYPE:
2938  key->size = sizeof(int_32);
2939  key->data = rpmvals + i;
2940  /*@switchbreak@*/ break;
2941 /*@=sizeoftype@*/
2942  case RPM_BIN_TYPE:
2943  key->size = rpmcnt;
2944  key->data = rpmvals;
2945  rpmcnt = 1; /* XXX break out of loop. */
2946  /*@switchbreak@*/ break;
2947  case RPM_STRING_TYPE:
2948  case RPM_I18NSTRING_TYPE:
2949  rpmcnt = 1; /* XXX break out of loop. */
2950  /*@fallthrough@*/
2951  case RPM_STRING_ARRAY_TYPE:
2952  /* Convert from hex to binary. */
2953 /*@-boundsread@*/
2954  if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) {
2955  const char * s = rpmvals[i];
2956  size_t dlen = strlen(s);
2957  byte * t;
2958 assert((dlen & 1) == 0);
2959  dlen /= 2;
2960  bin = t = xcalloc(1, dlen);
2961  for (j = 0; j < dlen; j++, t++, s += 2)
2962  *t = (nibble(s[0]) << 4) | nibble(s[1]);
2963  key->data = bin;
2964  key->size = dlen;
2965  /*@switchbreak@*/ break;
2966  }
2967  /* Extract the pubkey id from the base64 blob. */
2968  if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
2969  int nbin;
2970  bin = xcalloc(1, 32);
2971  nbin = pgpExtractPubkeyFingerprint(rpmvals[i], bin);
2972  if (nbin <= 0)
2973  /*@innercontinue@*/ continue;
2974  key->data = bin;
2975  key->size = nbin;
2976  /*@switchbreak@*/ break;
2977  }
2978 /*@=boundsread@*/
2979  /*@fallthrough@*/
2980  default:
2981 /*@i@*/ key->data = (void *) rpmvals[i];
2982  key->size = strlen(rpmvals[i]);
2983  stringvalued = 1;
2984  /*@switchbreak@*/ break;
2985  }
2986 
2987  if (!printed) {
2988  if (rpmcnt == 1 && stringvalued) {
2990  D_("removing \"%s\" from %s index.\n"),
2991  (char *)key->data, mapTagName(dbi->dbi_rpmtag));
2992  } else {
2994  D_("removing %d entries from %s index.\n"),
2995  rpmcnt, mapTagName(dbi->dbi_rpmtag));
2996  }
2997  printed++;
2998  }
2999 
3000  /* XXX
3001  * This is almost right, but, if there are duplicate tag
3002  * values, there will be duplicate attempts to remove
3003  * the header instance. It's faster to just ignore errors
3004  * than to do things correctly.
3005  */
3006 
3007 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */
3008 
3009  set = NULL;
3010 
3011 if (key->size == 0) key->size = strlen((char *)key->data);
3012 if (key->size == 0) key->size++; /* XXX "/" fixup. */
3013 
3014 /*@-compmempass@*/
3015  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
3016  if (rc == 0) { /* success */
3017  (void) dbt2set(dbi, data, &set);
3018  } else if (rc == DB_NOTFOUND) { /* not found */
3019  /*@innercontinue@*/ continue;
3020  } else { /* error */
3022  _("error(%d) setting \"%s\" records from %s index\n"),
3023  rc, key->data, mapTagName(dbi->dbi_rpmtag));
3024  ret += 1;
3025  /*@innercontinue@*/ continue;
3026  }
3027 /*@=compmempass@*/
3028 
3029  rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
3030 
3031  /* If nothing was pruned, then don't bother updating. */
3032  if (rc) {
3033  set = dbiFreeIndexSet(set);
3034  /*@innercontinue@*/ continue;
3035  }
3036 
3037 /*@-compmempass@*/
3038  if (set->count > 0) {
3039  (void) set2dbt(dbi, data, set);
3040  rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
3041  if (rc) {
3043  _("error(%d) storing record \"%s\" into %s\n"),
3044  rc, key->data, mapTagName(dbi->dbi_rpmtag));
3045  ret += 1;
3046  }
3047  data->data = _free(data->data);
3048  data->size = 0;
3049  } else {
3050  rc = dbiDel(dbi, dbcursor, key, data, 0);
3051  if (rc) {
3053  _("error(%d) removing record \"%s\" from %s\n"),
3054  rc, key->data, mapTagName(dbi->dbi_rpmtag));
3055  ret += 1;
3056  }
3057  }
3058 /*@=compmempass@*/
3059  set = dbiFreeIndexSet(set);
3060  }
3061 /*@=branchstate@*/
3062 
3063  xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3064  dbcursor = NULL;
3065 
3066  if (!dbi->dbi_no_dbsync)
3067  xx = dbiSync(dbi, 0);
3068  }
3069 
3070  if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */
3071  rpmvals = hfd(rpmvals, rpmtype);
3072  rpmtype = 0;
3073  rpmcnt = 0;
3074  bin = _free(bin);
3075  }
3076 
3077  rec = _free(rec);
3078  }
3079  /*@=nullpass =nullptrarith =nullderef @*/
3080 
3081  (void) unblockSignals(db, &signalMask);
3082 
3083  h = headerFree(h);
3084 
3085  /* XXX return ret; */
3086  return 0;
3087 }
3088 
3089 /* XXX install.c */
3090 int rpmdbAdd(rpmdb db, int iid, Header h,
3091  /*@unused@*/ rpmts ts,
3092  /*@unused@*/ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
3093 {
3094 DBC * dbcursor = NULL;
3095 DBT * key = alloca(sizeof(*key));
3096 DBT * data = alloca(sizeof(*data));
3098  HAE_t hae = (HAE_t) headerAddEntry;
3099  HFD_t hfd = headerFreeData;
3100  sigset_t signalMask;
3101  const char ** baseNames;
3102  rpmTagType bnt;
3103  const char ** dirNames;
3104  int_32 * dirIndexes;
3105  rpmTagType dit, dnt;
3106  int count = 0;
3107  dbiIndex dbi;
3108  int dbix;
3109  union _dbswap mi_offset;
3110  unsigned int hdrNum = 0;
3111  int ret = 0;
3112  int rc;
3113  int xx;
3114 
3115  /* Initialize the header instance */
3116  (void) headerSetInstance(h, 0);
3117 
3118  if (db == NULL)
3119  return 0;
3120 
3121 memset(key, 0, sizeof(*key));
3122 memset(data, 0, sizeof(*data));
3123 
3124 #ifdef NOTYET /* XXX headerRemoveEntry() broken on dribbles. */
3126 #endif
3127  if (iid != 0 && iid != -1) {
3128  int_32 tid = iid;
3130  xx = hae(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
3131  }
3132 
3133  /* Add the package color if not present. */
3135  uint32_t hcolor = hGetColor(h);
3136  xx = hae(h, RPMTAG_PACKAGECOLOR, RPM_INT32_TYPE, &hcolor, 1);
3137  }
3138 
3139  /*
3140  * If old style filename tags is requested, the basenames need to be
3141  * retrieved early, and the header needs to be converted before
3142  * being written to the package header database.
3143  */
3144 
3145  xx = hge(h, RPMTAG_BASENAMES, &bnt, &baseNames, &count);
3146  xx = hge(h, RPMTAG_DIRINDEXES, &dit, &dirIndexes, NULL);
3147  xx = hge(h, RPMTAG_DIRNAMES, &dnt, &dirNames, NULL);
3148 
3149  (void) blockSignals(db, &signalMask);
3150 
3151  {
3152  unsigned int firstkey = 0;
3153  void * keyp = &firstkey;
3154  size_t keylen = sizeof(firstkey);
3155  void * datap = NULL;
3156  size_t datalen = 0;
3157 
3158  dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
3159  /*@-branchstate@*/
3160  if (dbi != NULL) {
3161 
3162  /* XXX db0: hack to pass sizeof header to fadAlloc */
3163  datap = h;
3164  datalen = headerSizeof(h, HEADER_MAGIC_NO);
3165 
3166  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3167 
3168  /* Retrieve join key for next header instance. */
3169 
3170 /*@-compmempass@*/
3171  key->data = keyp;
3172  key->size = keylen;
3173 /*@i@*/ data->data = datap;
3174  data->size = datalen;
3175  ret = dbiGet(dbi, dbcursor, key, data, DB_SET);
3176  keyp = key->data;
3177  keylen = key->size;
3178  datap = data->data;
3179  datalen = data->size;
3180 /*@=compmempass@*/
3181 
3182 /*@-bounds@*/
3183  hdrNum = 0;
3184  if (ret == 0 && datap) {
3185  memcpy(&mi_offset, datap, sizeof(mi_offset.ui));
3186  if (dbiByteSwapped(dbi) == 1)
3187  _DBSWAP(mi_offset);
3188  hdrNum = mi_offset.ui;
3189  }
3190  ++hdrNum;
3191  mi_offset.ui = hdrNum;
3192  if (dbiByteSwapped(dbi) == 1)
3193  _DBSWAP(mi_offset);
3194  if (ret == 0 && datap) {
3195  memcpy(datap, &mi_offset, sizeof(mi_offset.ui));
3196  } else {
3197  datap = &mi_offset;
3198  datalen = sizeof(mi_offset.ui);
3199  }
3200 /*@=bounds@*/
3201 
3202  key->data = keyp;
3203  key->size = keylen;
3204 /*@-kepttrans@*/
3205  data->data = datap;
3206 /*@=kepttrans@*/
3207  data->size = datalen;
3208 
3209 /*@-compmempass@*/
3210  ret = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
3211 /*@=compmempass@*/
3212  xx = dbiSync(dbi, 0);
3213 
3214  xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3215  dbcursor = NULL;
3216  }
3217  /*@=branchstate@*/
3218 
3219  }
3220 
3221  if (ret) {
3223  _("error(%d) allocating new package instance\n"), ret);
3224  goto exit;
3225  }
3226 
3227  /* Now update the indexes */
3228 
3229  if (hdrNum)
3230  {
3231  dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
3232 
3233  /* Save the header instance. */
3234  (void) headerSetInstance(h, hdrNum);
3235 
3236  if (db->db_tagn != NULL)
3237  for (dbix = 0; dbix < db->db_ndbi; dbix++) {
3238  const char *av[1];
3239  const char **rpmvals = NULL;
3240  byte * bin = NULL;
3241  rpmTagType rpmtype = 0;
3242  int rpmcnt = 0;
3243  int rpmtag;
3244  int_32 * requireFlags;
3245  rpmRC rpmrc;
3246  int i, j;
3247 
3248  rpmrc = RPMRC_NOTFOUND;
3249  dbi = NULL;
3250  requireFlags = NULL;
3251 /*@-boundsread@*/
3252  rpmtag = db->db_tagn[dbix];
3253 /*@=boundsread@*/
3254 
3255  switch (rpmtag) {
3256  /* Filter out temporary databases */
3257  case RPMDBI_AVAILABLE:
3258  case RPMDBI_ADDED:
3259  case RPMDBI_REMOVED:
3260  case RPMDBI_DEPENDS:
3261  continue;
3262  /*@notreached@*/ /*@switchbreak@*/ break;
3263  case RPMDBI_PACKAGES:
3264  if (db->db_export != NULL)
3265  xx = db->db_export(db, h, 1);
3266  dbi = dbiOpen(db, rpmtag, 0);
3267  if (dbi == NULL) /* XXX shouldn't happen */
3268  continue;
3269  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3270 
3271 mi_offset.ui = hdrNum;
3272 if (dbiByteSwapped(dbi) == 1)
3273  _DBSWAP(mi_offset);
3274 /*@-immediatetrans@*/
3275 key->data = (void *) &mi_offset;
3276 /*@=immediatetrans@*/
3277 key->size = sizeof(mi_offset.ui);
3278 data->data = headerUnload(h);
3279 data->size = headerSizeof(h, HEADER_MAGIC_NO);
3280 
3281  /* Check header digest/signature on blob export. */
3282  if (hdrchk && ts) {
3283  const char * msg = NULL;
3284  int lvl;
3285 
3286  rpmrc = (*hdrchk) (ts, data->data, data->size, &msg);
3287  lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG);
3288  rpmMessage(lvl, "%s h#%8u %s",
3289  (rpmrc == RPMRC_FAIL ? _("rpmdbAdd: skipping") : " +++"),
3290  hdrNum, (msg ? msg : "\n"));
3291  msg = _free(msg);
3292  }
3293 
3294  if (data->data != NULL && rpmrc != RPMRC_FAIL) {
3295 /*@-compmempass@*/
3296  xx = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
3297 /*@=compmempass@*/
3298  xx = dbiSync(dbi, 0);
3299  }
3300 data->data = _free(data->data);
3301 data->size = 0;
3302  xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3303  dbcursor = NULL;
3304  if (!dbi->dbi_no_dbsync)
3305  xx = dbiSync(dbi, 0);
3306  continue;
3307  /*@notreached@*/ /*@switchbreak@*/ break;
3308  case RPMTAG_BASENAMES: /* XXX preserve legacy behavior */
3309  rpmtype = bnt;
3310  rpmvals = baseNames;
3311  rpmcnt = count;
3312  /*@switchbreak@*/ break;
3313  case RPMTAG_REQUIRENAME:
3314  xx = hge(h, rpmtag, &rpmtype, &rpmvals, &rpmcnt);
3315  xx = hge(h, RPMTAG_REQUIREFLAGS, NULL, &requireFlags, NULL);
3316  /*@switchbreak@*/ break;
3317  default:
3318  xx = hge(h, rpmtag, &rpmtype, &rpmvals, &rpmcnt);
3319  /*@switchbreak@*/ break;
3320  }
3321 
3322  /*@-branchstate@*/
3323  if (rpmcnt <= 0) {
3324  if (rpmtag != RPMTAG_GROUP)
3325  continue;
3326 
3327  /* XXX preserve legacy behavior */
3328  rpmtype = RPM_STRING_TYPE;
3329  rpmvals = (const char **) "Unknown";
3330  rpmcnt = 1;
3331  }
3332  /*@=branchstate@*/
3333 
3334  dbi = dbiOpen(db, rpmtag, 0);
3335  if (dbi != NULL) {
3336  int printed;
3337 
3338  if (rpmtype == RPM_STRING_TYPE) {
3339  /* XXX force uniform headerGetEntry return */
3340  /*@-observertrans@*/
3341  av[0] = (const char *) rpmvals;
3342  /*@=observertrans@*/
3343  rpmvals = av;
3344  rpmcnt = 1;
3345  }
3346 
3347  printed = 0;
3348  xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3349 
3350 /*@-branchstate@*/
3351  for (i = 0; i < rpmcnt; i++) {
3352  dbiIndexSet set;
3353  int stringvalued;
3354 
3355  bin = _free(bin);
3356  /*
3357  * Include the tagNum in all indices. rpm-3.0.4 and earlier
3358  * included the tagNum only for files.
3359  */
3360  rec->tagNum = i;
3361  switch (dbi->dbi_rpmtag) {
3362  case RPMTAG_BASENAMES:
3363  /* tag index entry with directory hash */
3364  if (_db_tagged_file_indices && i < 0x010000)
3365  rec->tagNum |= taghash(dirNames[dirIndexes[i]]);
3366  /*@switchbreak@*/ break;
3367  case RPMTAG_PUBKEYS:
3368  /*@switchbreak@*/ break;
3369  case RPMTAG_FILEMD5S:
3370  /* Filter out empty MD5 strings. */
3371  if (!(rpmvals[i] && *rpmvals[i] != '\0'))
3372  /*@innercontinue@*/ continue;
3373  /*@switchbreak@*/ break;
3374  case RPMTAG_REQUIRENAME:
3375  /* Filter out install prerequisites. */
3376  if (requireFlags && isInstallPreReq(requireFlags[i]))
3377  /*@innercontinue@*/ continue;
3378  /*@switchbreak@*/ break;
3379  case RPMTAG_TRIGGERNAME:
3380  if (i) { /* don't add duplicates */
3381 /*@-boundsread@*/
3382  for (j = 0; j < i; j++) {
3383  if (!strcmp(rpmvals[i], rpmvals[j]))
3384  /*@innerbreak@*/ break;
3385  }
3386 /*@=boundsread@*/
3387  if (j < i)
3388  /*@innercontinue@*/ continue;
3389  }
3390  /*@switchbreak@*/ break;
3391  default:
3392  /*@switchbreak@*/ break;
3393  }
3394 
3395  /* Identify value pointer and length. */
3396  stringvalued = 0;
3397  switch (rpmtype) {
3398 /*@-sizeoftype@*/
3399  case RPM_CHAR_TYPE:
3400  case RPM_INT8_TYPE:
3401  key->size = sizeof(int_8);
3402 /*@i@*/ key->data = rpmvals + i;
3403  /*@switchbreak@*/ break;
3404  case RPM_INT16_TYPE:
3405  key->size = sizeof(int_16);
3406 /*@i@*/ key->data = rpmvals + i;
3407  /*@switchbreak@*/ break;
3408  case RPM_INT32_TYPE:
3409  key->size = sizeof(int_32);
3410 /*@i@*/ key->data = rpmvals + i;
3411  /*@switchbreak@*/ break;
3412 /*@=sizeoftype@*/
3413  case RPM_BIN_TYPE:
3414  key->size = rpmcnt;
3415 /*@i@*/ key->data = rpmvals;
3416  rpmcnt = 1; /* XXX break out of loop. */
3417  /*@switchbreak@*/ break;
3418  case RPM_STRING_TYPE:
3419  case RPM_I18NSTRING_TYPE:
3420  rpmcnt = 1; /* XXX break out of loop. */
3421  /*@fallthrough@*/
3422  case RPM_STRING_ARRAY_TYPE:
3423  /* Convert from hex to binary. */
3424 /*@-boundsread@*/
3425  if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) {
3426  const char * s = rpmvals[i];
3427  size_t dlen = strlen(s);
3428  byte * t;
3429 assert((dlen & 1) == 0);
3430  dlen /= 2;
3431  bin = t = xcalloc(1, dlen);
3432  for (j = 0; j < dlen; j++, t++, s += 2)
3433  *t = (nibble(s[0]) << 4) | nibble(s[1]);
3434  key->data = bin;
3435  key->size = dlen;
3436  /*@switchbreak@*/ break;
3437  }
3438  /* Extract the pubkey id from the base64 blob. */
3439  if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
3440  int nbin;
3441  bin = xcalloc(1, 32);
3442  nbin = pgpExtractPubkeyFingerprint(rpmvals[i], bin);
3443  if (nbin <= 0)
3444  /*@innercontinue@*/ continue;
3445  key->data = bin;
3446  key->size = nbin;
3447  /*@switchbreak@*/ break;
3448  }
3449 /*@=boundsread@*/
3450  /*@fallthrough@*/
3451  default:
3452 /*@i@*/ key->data = (void *) rpmvals[i];
3453  key->size = strlen(rpmvals[i]);
3454  stringvalued = 1;
3455  /*@switchbreak@*/ break;
3456  }
3457 
3458  if (!printed) {
3459  if (rpmcnt == 1 && stringvalued) {
3461  D_("adding \"%s\" to %s index.\n"),
3462  (char *)key->data, mapTagName(dbi->dbi_rpmtag));
3463  } else {
3465  D_("adding %d entries to %s index.\n"),
3466  rpmcnt, mapTagName(dbi->dbi_rpmtag));
3467  }
3468  printed++;
3469  }
3470 
3471 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */
3472 
3473  set = NULL;
3474 
3475 if (key->size == 0) key->size = strlen((char *)key->data);
3476 if (key->size == 0) key->size++; /* XXX "/" fixup. */
3477 
3478 /*@-compmempass@*/
3479  rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
3480  if (rc == 0) { /* success */
3481  /* With duplicates, cursor is positioned, discard the record. */
3482  if (!dbi->dbi_permit_dups)
3483  (void) dbt2set(dbi, data, &set);
3484  } else if (rc != DB_NOTFOUND) { /* error */
3486  _("error(%d) getting \"%s\" records from %s index\n"),
3487  rc, key->data, mapTagName(dbi->dbi_rpmtag));
3488  ret += 1;
3489  /*@innercontinue@*/ continue;
3490  }
3491 /*@=compmempass@*/
3492 
3493  if (set == NULL) /* not found or duplicate */
3494  set = xcalloc(1, sizeof(*set));
3495 
3496  (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
3497 
3498 /*@-compmempass@*/
3499  (void) set2dbt(dbi, data, set);
3500  rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
3501 /*@=compmempass@*/
3502 
3503  if (rc) {
3505  _("error(%d) storing record %s into %s\n"),
3506  rc, key->data, mapTagName(dbi->dbi_rpmtag));
3507  ret += 1;
3508  }
3509 /*@-unqualifiedtrans@*/
3510  data->data = _free(data->data);
3511 /*@=unqualifiedtrans@*/
3512  data->size = 0;
3513  set = dbiFreeIndexSet(set);
3514  }
3515 /*@=branchstate@*/
3516 
3517  xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3518  dbcursor = NULL;
3519 
3520  if (!dbi->dbi_no_dbsync)
3521  xx = dbiSync(dbi, 0);
3522  }
3523 
3524  /*@-observertrans@*/
3525  if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */
3526  rpmvals = hfd(rpmvals, rpmtype);
3527  /*@=observertrans@*/
3528  rpmtype = 0;
3529  rpmcnt = 0;
3530  bin = _free(bin);
3531  }
3532  /*@=nullpass =nullptrarith =nullderef @*/
3533 
3534  rec = _free(rec);
3535  }
3536 
3537 exit:
3538  (void) unblockSignals(db, &signalMask);
3539  dirIndexes = hfd(dirIndexes, dit);
3540  dirNames = hfd(dirNames, dnt);
3541 
3542  return ret;
3543 }
3544 
3545 /* XXX transaction.c */
3546 /*@-compmempass@*/
3547 int rpmdbFindFpList(rpmdb db, fingerPrint * fpList, dbiIndexSet * matchList,
3548  int numItems, unsigned int exclude)
3549 {
3550 DBT * key;
3551 DBT * data;
3553  HFD_t hfd = headerFreeData;
3554  rpmdbMatchIterator mi;
3555  fingerPrintCache fpc;
3556  Header h;
3557  int i, xx;
3558 
3559  if (db == NULL) return 0;
3560 
3561  mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, NULL, 0);
3562 assert(mi); /* XXX will never happen. */
3563  if (mi == NULL)
3564  return 2;
3565 
3566 key = &mi->mi_key;
3567 data = &mi->mi_data;
3568 
3569  /* Gather all installed headers with matching basename's. */
3570  for (i = 0; i < numItems; i++) {
3571  unsigned int tag;
3572 
3573 /*@-boundswrite@*/
3574  matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
3575 /*@=boundswrite@*/
3576 
3577 /*@-boundsread -dependenttrans@*/
3578 key->data = (void *) fpList[i].baseName;
3579 /*@=boundsread =dependenttrans@*/
3580 key->size = strlen((char *)key->data);
3581 if (key->size == 0) key->size++; /* XXX "/" fixup. */
3582 
3583  tag = (_db_tagged_file_indices ? taghash(fpList[i].entry->dirName) : 0);
3584  xx = rpmdbGrowIterator(mi, i, exclude, tag);
3585 
3586  }
3587 
3588  if ((i = rpmdbGetIteratorCount(mi)) == 0) {
3589  mi = rpmdbFreeIterator(mi);
3590  return 0;
3591  }
3592  fpc = fpCacheCreate(i);
3593 
3594  rpmdbSortIterator(mi);
3595  /* iterator is now sorted by (recnum, filenum) */
3596 
3597  /* For all installed headers with matching basename's ... */
3598  if (mi != NULL)
3599  while ((h = rpmdbNextIterator(mi)) != NULL) {
3600  const char ** dirNames;
3601  const char ** baseNames;
3602  const char ** fullBaseNames;
3603  rpmTagType bnt, dnt;
3604  uint_32 * dirIndexes;
3605  uint_32 * fullDirIndexes;
3606  fingerPrint * fps;
3607  dbiIndexItem im;
3608  int start;
3609  int num;
3610  int end;
3611 
3612  start = mi->mi_setx - 1;
3613  im = mi->mi_set->recs + start;
3614 
3615  /* Find the end of the set of matched basename's in this package. */
3616 /*@-boundsread@*/
3617  for (end = start + 1; end < mi->mi_set->count; end++) {
3618  if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
3619  /*@innerbreak@*/ break;
3620  }
3621 /*@=boundsread@*/
3622  num = end - start;
3623 
3624  /* Compute fingerprints for this installed header's matches */
3625  xx = hge(h, RPMTAG_BASENAMES, &bnt, &fullBaseNames, NULL);
3626  xx = hge(h, RPMTAG_DIRNAMES, &dnt, &dirNames, NULL);
3627  xx = hge(h, RPMTAG_DIRINDEXES, NULL, &fullDirIndexes, NULL);
3628 
3629  baseNames = xcalloc(num, sizeof(*baseNames));
3630  dirIndexes = xcalloc(num, sizeof(*dirIndexes));
3631 /*@-bounds@*/
3632  for (i = 0; i < num; i++) {
3633  baseNames[i] = fullBaseNames[im[i].tagNum];
3634  dirIndexes[i] = fullDirIndexes[im[i].tagNum];
3635  }
3636 /*@=bounds@*/
3637 
3638  fps = xcalloc(num, sizeof(*fps));
3639  fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
3640 
3641  /* Add db (recnum,filenum) to list for fingerprint matches. */
3642 /*@-boundsread@*/
3643  for (i = 0; i < num; i++, im++) {
3644  /*@-nullpass@*/ /* FIX: fpList[].subDir may be NULL */
3645  if (!FP_EQUAL(fps[i], fpList[im->fpNum]))
3646  /*@innercontinue@*/ continue;
3647  /*@=nullpass@*/
3648  xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
3649  }
3650 /*@=boundsread@*/
3651 
3652  fps = _free(fps);
3653  dirNames = hfd(dirNames, dnt);
3654  fullBaseNames = hfd(fullBaseNames, bnt);
3655  baseNames = _free(baseNames);
3656  dirIndexes = _free(dirIndexes);
3657 
3658  mi->mi_setx = end;
3659  }
3660 
3661  mi = rpmdbFreeIterator(mi);
3662 
3663  fpc = fpCacheFree(fpc);
3664 
3665  return 0;
3666 
3667 }
3668 /*@=compmempass@*/
3669 
3675 static int rpmioFileExists(const char * urlfn)
3676  /*@globals h_errno, fileSystem, internalState @*/
3677  /*@modifies fileSystem, internalState @*/
3678 {
3679  const char *fn;
3680  int urltype = urlPath(urlfn, &fn);
3681  struct stat buf;
3682 
3683  /*@-branchstate@*/
3684  if (*fn == '\0') fn = "/";
3685  /*@=branchstate@*/
3686  switch (urltype) {
3687  case URL_IS_HTTPS: /* XXX WRONG WRONG WRONG */
3688  case URL_IS_HTTP: /* XXX WRONG WRONG WRONG */
3689  case URL_IS_FTP: /* XXX WRONG WRONG WRONG */
3690  case URL_IS_HKP: /* XXX WRONG WRONG WRONG */
3691  case URL_IS_PATH:
3692  case URL_IS_UNKNOWN:
3693  if (Stat(fn, &buf)) {
3694  switch(errno) {
3695  case ENOENT:
3696  case EINVAL:
3697  return 0;
3698  }
3699  }
3700  break;
3701  case URL_IS_DASH:
3702  default:
3703  return 0;
3704  /*@notreached@*/ break;
3705  }
3706 
3707  return 1;
3708 }
3709 
3710 static int rpmdbRemoveDatabase(const char * prefix,
3711  const char * dbpath, int _dbapi,
3712  const int * dbiTags, int dbiTagsMax)
3713  /*@globals h_errno, fileSystem, internalState @*/
3714  /*@modifies fileSystem, internalState @*/
3715 {
3716  int i;
3717  char * filename;
3718  int xx;
3719 
3720  i = strlen(dbpath);
3721  /*@-bounds -branchstate@*/
3722  if (dbpath[i - 1] != '/') {
3723  filename = alloca(i);
3724  strcpy(filename, dbpath);
3725  filename[i] = '/';
3726  filename[i + 1] = '\0';
3727  dbpath = filename;
3728  }
3729  /*@=bounds =branchstate@*/
3730 
3731  filename = alloca(strlen(prefix) + strlen(dbpath) + 40);
3732 
3733  switch (_dbapi) {
3734  case 4:
3735  /*@fallthrough@*/
3736  case 3:
3737  /* Nuke the rpmdb tables. */
3738  if (dbiTags != NULL)
3739  for (i = 0; i < dbiTagsMax; i++) {
3740 /*@-boundsread@*/
3741  const char * base = mapTagName(dbiTags[i]);
3742 /*@=boundsread@*/
3743  sprintf(filename, "%s/%s/%s", prefix, dbpath, base);
3744  (void)rpmCleanPath(filename);
3745  if (!rpmioFileExists(filename))
3746  continue;
3747  xx = Unlink(filename);
3748  }
3749  /* Nuke the dbenv. */
3750  for (i = 0; i < 16; i++) {
3751  sprintf(filename, "%s/%s/__db.%03d", prefix, dbpath, i);
3752  (void)rpmCleanPath(filename);
3753  if (!rpmioFileExists(filename))
3754  continue;
3755  xx = Unlink(filename);
3756  }
3757  break;
3758  case 2:
3759  case 1:
3760  case 0:
3761  break;
3762  }
3763 
3764  sprintf(filename, "%s/%s", prefix, dbpath);
3765  (void)rpmCleanPath(filename);
3766  xx = rmdir(filename);
3767 
3768  return 0;
3769 }
3770 
3771 static int rpmdbMoveDatabase(const char * prefix,
3772  const char * olddbpath, int _olddbapi,
3773  const char * newdbpath, /*@unused@*/ int _newdbapi,
3774  const int * dbiTags, int dbiTagsMax)
3775  /*@globals h_errno, fileSystem, internalState @*/
3776  /*@modifies fileSystem, internalState @*/
3777 {
3778  int i;
3779  char * ofn, * nfn;
3780  struct stat * nst = alloca(sizeof(*nst));
3781  int rc = 0;
3782  int xx;
3783  int selinux = is_selinux_enabled() > 0 && (matchpathcon_init(NULL) != -1);
3784  sigset_t sigMask;
3785 
3786  i = strlen(olddbpath);
3787  /*@-branchstate@*/
3788  if (olddbpath[i - 1] != '/') {
3789  ofn = alloca(i + 2);
3790  strcpy(ofn, olddbpath);
3791  ofn[i] = '/';
3792  ofn[i + 1] = '\0';
3793  olddbpath = ofn;
3794  }
3795  /*@=branchstate@*/
3796 
3797  i = strlen(newdbpath);
3798  /*@-branchstate@*/
3799  if (newdbpath[i - 1] != '/') {
3800  nfn = alloca(i + 2);
3801  strcpy(nfn, newdbpath);
3802  nfn[i] = '/';
3803  nfn[i + 1] = '\0';
3804  newdbpath = nfn;
3805  }
3806  /*@=branchstate@*/
3807 
3808  ofn = alloca(strlen(prefix) + strlen(olddbpath) + 40);
3809  nfn = alloca(strlen(prefix) + strlen(newdbpath) + 40);
3810 
3811  blockSignals(NULL, &sigMask);
3812  switch (_olddbapi) {
3813  case 4:
3814  /* Fall through */
3815  case 3:
3816  if (dbiTags != NULL)
3817  for (i = 0; i < dbiTagsMax; i++) {
3818  const char * base;
3819  int rpmtag;
3820 
3821  /* Filter out temporary databases */
3822  switch ((rpmtag = dbiTags[i])) {
3823  case RPMDBI_AVAILABLE:
3824  case RPMDBI_ADDED:
3825  case RPMDBI_REMOVED:
3826  case RPMDBI_DEPENDS:
3827  continue;
3828  /*@notreached@*/ /*@switchbreak@*/ break;
3829  default:
3830  /*@switchbreak@*/ break;
3831  }
3832 
3833  base = mapTagName(rpmtag);
3834  sprintf(ofn, "%s/%s/%s", prefix, olddbpath, base);
3835  (void)rpmCleanPath(ofn);
3836  if (!rpmioFileExists(ofn))
3837  continue;
3838  sprintf(nfn, "%s/%s/%s", prefix, newdbpath, base);
3839  (void)rpmCleanPath(nfn);
3840 
3841  /*
3842  * Get uid/gid/mode/mtime. If old doesn't exist, use new.
3843  * XXX Yes, the variable names are backwards.
3844  */
3845  if (stat(nfn, nst) < 0)
3846  if (stat(ofn, nst) < 0)
3847  continue;
3848 
3849  if ((xx = rename(ofn, nfn)) != 0) {
3850  rc = 1;
3851  continue;
3852  }
3853 
3854  /* Restore uid/gid/mode/mtime/security context if possible. */
3855  xx = chown(nfn, nst->st_uid, nst->st_gid);
3856  xx = chmod(nfn, (nst->st_mode & 07777));
3857  { struct utimbuf stamp;
3858  stamp.actime = nst->st_atime;
3859  stamp.modtime = nst->st_mtime;
3860  xx = utime(nfn, &stamp);
3861  }
3862  if (selinux) {
3863  security_context_t scon = NULL;
3864  if (matchpathcon(nfn, nst->st_mode, &scon) != -1)
3865  xx = setfilecon(nfn, scon);
3866  if (scon != NULL)
3867  freecon(scon);
3868  }
3869  }
3870  for (i = 0; i < 16; i++) {
3871  sprintf(ofn, "%s/%s/__db.%03d", prefix, olddbpath, i);
3872  (void)rpmCleanPath(ofn);
3873  if (rpmioFileExists(ofn))
3874  xx = unlink(ofn);
3875  sprintf(nfn, "%s/%s/__db.%03d", prefix, newdbpath, i);
3876  (void)rpmCleanPath(nfn);
3877  if (rpmioFileExists(nfn))
3878  xx = unlink(nfn);
3879  }
3880  break;
3881  case 2:
3882  case 1:
3883  case 0:
3884  break;
3885  }
3886  unblockSignals(NULL, &sigMask);
3887 
3888  if (selinux)
3889  matchpathcon_fini();
3890  return rc;
3891 }
3892 
3893 int rpmdbRebuild(const char * prefix, rpmts ts,
3894  rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
3895  /*@globals _rebuildinprogress @*/
3896  /*@modifies _rebuildinprogress @*/
3897 {
3898  rpmdb olddb;
3899  const char * dbpath = NULL;
3900  const char * rootdbpath = NULL;
3901  rpmdb newdb;
3902  const char * newdbpath = NULL;
3903  const char * newrootdbpath = NULL;
3904  const char * tfn;
3905  int nocleanup = 1;
3906  int failed = 0;
3907  int removedir = 0;
3908  int rc = 0, xx;
3909  int _dbapi;
3910  int _dbapi_rebuild;
3911  int * dbiTags = NULL;
3912  int dbiTagsMax = 0;
3913 
3914  /*@-branchstate@*/
3915  if (prefix == NULL) prefix = "/";
3916  /*@=branchstate@*/
3917  prefix = rpmGetPath(prefix, NULL); /* strip trailing '/' */
3918 
3919  _dbapi = rpmExpandNumeric("%{_dbapi}");
3920  _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
3921 
3922  dbiTagsInit(&dbiTags, &dbiTagsMax);
3923 
3924  /*@-nullpass@*/
3925  tfn = rpmGetPath("%{?_dbpath}", NULL);
3926  /*@=nullpass@*/
3927 /*@-boundsread@*/
3928  if (!(tfn && tfn[0] != '\0'))
3929 /*@=boundsread@*/
3930  {
3931  rpmMessage(RPMMESS_DEBUG, D_("no dbpath has been set"));
3932  rc = 1;
3933  goto exit;
3934  }
3935  dbpath = rootdbpath = rpmGetPath(prefix, tfn, NULL);
3936  if (!(prefix[0] == '/' && prefix[1] == '\0'))
3937  dbpath += strlen(prefix);
3938  tfn = _free(tfn);
3939 
3940  /*@-nullpass@*/
3941  tfn = rpmGetPath("%{?_dbpath_rebuild}", NULL);
3942  /*@=nullpass@*/
3943 /*@-boundsread@*/
3944  if (!(tfn && tfn[0] != '\0' && strcmp(tfn, dbpath)))
3945 /*@=boundsread@*/
3946  {
3947  char pidbuf[20];
3948  char *t;
3949  sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
3950  t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
3951 /*@-boundswrite@*/
3952  (void)stpcpy(stpcpy(t, dbpath), pidbuf);
3953 /*@=boundswrite@*/
3954  tfn = _free(tfn);
3955  tfn = t;
3956  nocleanup = 0;
3957  }
3958  newdbpath = newrootdbpath = rpmGetPath(prefix, tfn, NULL);
3959  if (!(prefix[0] == '/' && prefix[1] == '\0'))
3960  newdbpath += strlen(prefix) - 1;
3961  tfn = _free(tfn);
3962 
3963  rpmMessage(RPMMESS_DEBUG, D_("rebuilding database %s into %s\n"),
3964  rootdbpath, newrootdbpath);
3965 
3966  if (!Access(newrootdbpath, F_OK)) {
3967  rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
3968  newrootdbpath);
3969  rc = 1;
3970  goto exit;
3971  }
3972 
3973  rpmMessage(RPMMESS_DEBUG, D_("creating directory %s\n"), newrootdbpath);
3974  if (Mkdir(newrootdbpath, 0755)) {
3975  rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
3976  newrootdbpath, strerror(errno));
3977  rc = 1;
3978  goto exit;
3979  }
3980  removedir = 1;
3981 
3982  _rebuildinprogress = 0;
3983 
3984  rpmMessage(RPMMESS_DEBUG, D_("opening old database with dbapi %d\n"),
3985  _dbapi);
3986 /*@-boundswrite@*/
3987  if (rpmdbOpenDatabase(prefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
3988  RPMDB_FLAG_MINIMAL)) {
3989  rc = 1;
3990  goto exit;
3991  }
3992 /*@=boundswrite@*/
3993  _dbapi = olddb->db_api;
3994  _rebuildinprogress = 1;
3995  rpmMessage(RPMMESS_DEBUG, D_("opening new database with dbapi %d\n"),
3996  _dbapi_rebuild);
3997  (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
3998 /*@-boundswrite@*/
3999  if (rpmdbOpenDatabase(prefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
4000  rc = 1;
4001  goto exit;
4002  }
4003 /*@=boundswrite@*/
4004 
4005  _rebuildinprogress = 0;
4006 
4007  _dbapi_rebuild = newdb->db_api;
4008 
4009  { Header h = NULL;
4010  rpmdbMatchIterator mi;
4011 #define _RECNUM rpmdbGetIteratorOffset(mi)
4012 
4013  mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
4014  if (ts && hdrchk)
4015  (void) rpmdbSetHdrChk(mi, ts, hdrchk);
4016 
4017  while ((h = rpmdbNextIterator(mi)) != NULL) {
4018 
4019  /* let's sanity check this record a bit, otherwise just skip it */
4020  if (!(headerIsEntry(h, RPMTAG_NAME) &&
4024  {
4026  _("header #%u in the database is bad -- skipping.\n"),
4027  _RECNUM);
4028  continue;
4029  }
4030 
4031  /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
4032  if (_db_filter_dups || newdb->db_filter_dups) {
4033  const char * name, * version, * release;
4034  int skip = 0;
4035 
4036  (void) headerNVR(h, &name, &version, &release);
4037 
4038  /*@-shadow@*/
4039  { rpmdbMatchIterator mi;
4040  mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
4042  RPMMIRE_DEFAULT, version);
4044  RPMMIRE_DEFAULT, release);
4045  while (rpmdbNextIterator(mi)) {
4046  skip = 1;
4047  /*@innerbreak@*/ break;
4048  }
4049  mi = rpmdbFreeIterator(mi);
4050  }
4051  /*@=shadow@*/
4052 
4053  if (skip)
4054  continue;
4055  }
4056 
4057  /* Deleted entries are eliminated in legacy headers by copy. */
4059  ? headerCopy(h) : NULL);
4060  rc = rpmdbAdd(newdb, -1, (nh ? nh : h), ts, hdrchk);
4061  nh = headerFree(nh);
4062  }
4063 
4064  if (rc) {
4066  _("cannot add record originally at %u\n"), _RECNUM);
4067  failed = 1;
4068  break;
4069  }
4070  }
4071 
4072  mi = rpmdbFreeIterator(mi);
4073 
4074  }
4075 
4076  xx = rpmdbClose(olddb);
4077  xx = rpmdbClose(newdb);
4078 
4079  if (failed) {
4080  rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
4081  "remains in place\n"));
4082 
4083  xx = rpmdbRemoveDatabase(prefix, newdbpath, _dbapi_rebuild,
4084  dbiTags, dbiTagsMax);
4085  rc = 1;
4086  goto exit;
4087  } else if (!nocleanup) {
4088  xx = rpmdbMoveDatabase(prefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi,
4089  dbiTags, dbiTagsMax);
4090 
4091  if (xx) {
4092  rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
4093  "database!\n"));
4094  rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
4095  "to recover"), dbpath, newdbpath);
4096  rc = 1;
4097  goto exit;
4098  }
4099  }
4100  rc = 0;
4101 
4102 exit:
4103  if (removedir && !(rc == 0 && nocleanup)) {
4104  rpmMessage(RPMMESS_DEBUG, D_("removing directory %s\n"), newrootdbpath);
4105  if (Rmdir(newrootdbpath))
4106  rpmMessage(RPMMESS_ERROR, D_("failed to remove directory %s: %s\n"),
4107  newrootdbpath, strerror(errno));
4108  }
4109  newrootdbpath = _free(newrootdbpath);
4110  rootdbpath = _free(rootdbpath);
4111  dbiTags = _free(dbiTags);
4112  prefix = _free(prefix);
4113 
4114  return rc;
4115 }