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