7 #define _USE_COPY_LOAD /* XXX don't use DB_DBT_MALLOC (yet) */
14 #include <sys/signal.h>
16 #ifndef DYING /* XXX already in "system.h" */
20 #if defined(__LCLINT__)
21 /*@-declundef -exportheader -redecl @*/ /* LCL: missing annotation */
22 extern int fnmatch (const char *pattern, const char *string, int flags)
24 /*@=declundef =exportheader =redecl @*/
29 #if defined(__LCLINT__)
30 /*@-declundef -exportheader @*/ /* LCL: missing modifies (only is bogus) */
31 extern void regfree (/*@only@*/ regex_t *preg)
32 /*@modifies *preg @*/;
33 /*@=declundef =exportheader @*/
36 #include <rpmio_internal.h>
42 #include "header_internal.h" /* XXX for HEADERFLAG_ALLOCATED */
45 /*@access dbiIndexSet@*/
46 /*@access dbiIndexItem@*/
47 /*@access rpmts@*/ /* XXX compared with NULL */
48 /*@access Header@*/ /* XXX compared with NULL */
49 /*@access rpmdbMatchIterator@*/
53 static int _rebuildinprogress = 0;
55 static int _db_filter_dups = 0;
58 #define _DBI_PERMS 0644
62 /*@globstate@*/ /*@null@*/ int * dbiTags = NULL;
66 /* Bit mask macros. */
68 typedef unsigned int __pbm_bits;
70 #define __PBM_NBITS (8 * sizeof (__pbm_bits))
71 #define __PBM_IX(d) ((d) / __PBM_NBITS)
72 #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
78 #define __PBM_BITS(set) ((set)->bits)
80 #define PBM_FREE(s) _free(s);
81 #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
82 #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
83 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
85 #define PBM_ALLOC(d) xcalloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
88 * Reallocate a bit map.
89 * @retval sp address of bit map pointer
90 * @retval odp no. of bits in map
91 * @param nd desired no. of bits
94 static inline pbm_set * PBM_REALLOC(pbm_set ** sp, int * odp, int nd)
95 /*@modifies *sp, *odp @*/
99 /*@-bounds -sizeoftype@*/
102 nb = __PBM_IX(nd) + 1;
103 /*@-unqualifiedtrans@*/
104 *sp = xrealloc(*sp, nb * sizeof(__pbm_bits));
105 /*@=unqualifiedtrans@*/
106 for (i = __PBM_IX(*odp) + 1; i < nb; i++)
107 __PBM_BITS(*sp)[i] = 0;
110 /*@=bounds =sizeoftype@*/
111 /*@-compdef -retalias -usereleased@*/
113 /*@=compdef =retalias =usereleased@*/
117 * Convert hex to binary nibble.
118 * @param c hex character
119 * @return binary nibble
121 static inline unsigned char nibble(char c)
124 if (c >= '0' && c <= '9')
126 if (c >= 'A' && c <= 'F')
127 return (c - 'A') + 10;
128 if (c >= 'a' && c <= 'f')
129 return (c - 'a') + 10;
135 * Check key for printable characters.
136 * @param ptr key value pointer
137 * @param len key value length
138 * @return 1 if only ASCII, 0 otherwise.
140 static int printable(const void * ptr, size_t len) /*@*/
142 const char * s = ptr;
144 for (i = 0; i < len; i++, s++)
145 if (!(*s >= ' ' && *s <= '~')) return 0;
151 * Return dbi index used for rpm tag.
152 * @param rpmtag rpm header tag
153 * @return dbi index, -1 on error
155 static int dbiTagToDbix(int rpmtag)
161 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
163 if (rpmtag == dbiTags[dbix])
171 * Initialize database (index, tag) tuple from configuration.
173 /*@-bounds@*/ /* LCL: segfault */
174 static void dbiTagsInit(void)
175 /*@globals rpmGlobalMacroContext, dbiTags, dbiTagsMax @*/
176 /*@modifies rpmGlobalMacroContext, dbiTags, dbiTagsMax @*/
178 /*@observer@*/ static const char * const _dbiTagStr_default =
179 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filemd5s:Depends:Pubkeys";
180 char * dbiTagStr = NULL;
184 dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL);
185 if (!(dbiTagStr && *dbiTagStr)) {
186 dbiTagStr = _free(dbiTagStr);
187 dbiTagStr = xstrdup(_dbiTagStr_default);
190 /* Discard previous values. */
191 dbiTags = _free(dbiTags);
194 /* Always allocate package index */
195 dbiTags = xcalloc(1, sizeof(*dbiTags));
196 dbiTags[dbiTagsMax++] = RPMDBI_PACKAGES;
198 for (o = dbiTagStr; o && *o; o = oe) {
199 while (*o && xisspace(*o))
203 for (oe = o; oe && *oe; oe++) {
205 /*@innerbreak@*/ break;
206 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
207 /*@innerbreak@*/ break;
211 rpmtag = tagValue(o);
215 fprintf(stderr, _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
219 if (dbiTagToDbix(rpmtag) >= 0)
222 dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags)); /* XXX memory leak */
223 dbiTags[dbiTagsMax++] = rpmtag;
226 dbiTagStr = _free(dbiTagStr);
234 /*@-exportheadervar -declundef @*/
236 extern struct _dbiVec db3vec;
237 /*@=exportheadervar =declundef @*/
238 #define DB3vec &db3vec
242 /*@observer@*/ /*@unchecked@*/
243 static struct _dbiVec *mydbvecs[] = {
244 DB1vec, DB1vec, DB2vec, DB3vec, NULL
248 dbiIndex dbiOpen(rpmdb db, rpmTag rpmtag, /*@unused@*/ unsigned int flags)
252 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
258 dbix = dbiTagToDbix(rpmtag);
259 if (dbix < 0 || dbix >= dbiTagsMax)
262 /* Is this index already open ? */
263 /*@-compdef@*/ /* FIX: db->_dbi may be NULL */
264 if ((dbi = db->_dbi[dbix]) != NULL)
268 /*@-globs -mods @*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
269 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
271 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 3)
273 _dbapi_wanted = (_rebuildinprogress ? -1 : db->db_api);
275 switch (_dbapi_wanted) {
277 _dbapi = _dbapi_wanted;
278 if (_dbapi < 0 || _dbapi >= 4 || mydbvecs[_dbapi] == NULL) {
285 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
287 static int _printed[32];
288 if (!_printed[dbix & 0x1f]++)
289 rpmError(RPMERR_DBOPEN,
290 _("cannot open %s index using db%d - %s (%d)\n"),
291 tagName(rpmtag), _dbapi,
292 (rc > 0 ? strerror(rc) : ""), rc);
298 while (_dbapi-- > 1) {
299 if (mydbvecs[_dbapi] == NULL)
305 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
307 /*@loopbreak@*/ break;
310 static int _printed[32];
311 if (!_printed[dbix & 0x1f]++)
312 rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"),
317 if (db->db_api == -1 && _dbapi > 0)
322 /* Require conversion. */
323 if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
324 rc = (_rebuildinprogress ? 0 : 1);
328 /* Suggest possible configuration */
329 if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
334 /* Suggest possible configuration */
335 if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
336 rc = (_rebuildinprogress ? 0 : 1);
341 if (dbi != NULL && rc == 0) {
342 db->_dbi[dbix] = dbi;
344 if (rpmtag == RPMDBI_PACKAGES && db->db_bits == NULL) {
346 if (!dbiStat(dbi, DB_FAST_STAT)) {
347 DB_HASH_STAT * hash = (DB_HASH_STAT *)dbi->dbi_stats;
349 db->db_nbits += hash->hash_nkeys;
351 db->db_bits = PBM_ALLOC(db->db_nbits);
357 /*@-compdef -nullstate@*/ /* FIX: db->_dbi may be NULL */
359 /*@=compdef =nullstate@*/
363 * Create and initialize item for index database set.
364 * @param hdrNum header instance in db
365 * @param tagNum tag index in header
368 static dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
371 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
372 rec->hdrNum = hdrNum;
373 rec->tagNum = tagNum;
382 #define _DBSWAP(_a) \
383 { unsigned char _b, *_c = (_a).uc; \
384 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
385 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
389 * Convert retrieved data to index set.
390 * @param dbi index database handle
391 * @param data retrieved data
392 * @retval setp (malloc'ed) index set
393 * @return 0 on success
395 static int dbt2set(dbiIndex dbi, DBT * data, /*@out@*/ dbiIndexSet * setp)
396 /*@modifies dbi, *setp @*/
398 int _dbbyteswapped = dbiByteSwapped(dbi);
403 if (dbi == NULL || data == NULL || setp == NULL)
406 if ((sdbir = data->data) == NULL) {
411 set = xmalloc(sizeof(*set));
412 set->count = data->size / dbi->dbi_jlen;
413 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
415 /*@-bounds -sizeoftype @*/
416 switch (dbi->dbi_jlen) {
418 case 2*sizeof(int_32):
419 for (i = 0; i < set->count; i++) {
420 union _dbswap hdrNum, tagNum;
422 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
423 sdbir += sizeof(hdrNum.ui);
424 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
425 sdbir += sizeof(tagNum.ui);
426 if (_dbbyteswapped) {
430 set->recs[i].hdrNum = hdrNum.ui;
431 set->recs[i].tagNum = tagNum.ui;
432 set->recs[i].fpNum = 0;
435 case 1*sizeof(int_32):
436 for (i = 0; i < set->count; i++) {
437 union _dbswap hdrNum;
439 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
440 sdbir += sizeof(hdrNum.ui);
441 if (_dbbyteswapped) {
444 set->recs[i].hdrNum = hdrNum.ui;
445 set->recs[i].tagNum = 0;
446 set->recs[i].fpNum = 0;
451 /*@=bounds =sizeoftype @*/
458 * Convert index set to database representation.
459 * @param dbi index database handle
460 * @param data retrieved data
461 * @param set index set
462 * @return 0 on success
464 static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
465 /*@modifies dbi, *data @*/
467 int _dbbyteswapped = dbiByteSwapped(dbi);
471 if (dbi == NULL || data == NULL || set == NULL)
474 data->size = set->count * (dbi->dbi_jlen);
475 if (data->size == 0) {
479 tdbir = data->data = xmalloc(data->size);
481 /*@-bounds -sizeoftype@*/
482 switch (dbi->dbi_jlen) {
484 case 2*sizeof(int_32):
485 for (i = 0; i < set->count; i++) {
486 union _dbswap hdrNum, tagNum;
488 memset(&hdrNum, 0, sizeof(hdrNum));
489 memset(&tagNum, 0, sizeof(tagNum));
490 hdrNum.ui = set->recs[i].hdrNum;
491 tagNum.ui = set->recs[i].tagNum;
492 if (_dbbyteswapped) {
496 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
497 tdbir += sizeof(hdrNum.ui);
498 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
499 tdbir += sizeof(tagNum.ui);
502 case 1*sizeof(int_32):
503 for (i = 0; i < set->count; i++) {
504 union _dbswap hdrNum;
506 memset(&hdrNum, 0, sizeof(hdrNum));
507 hdrNum.ui = set->recs[i].hdrNum;
508 if (_dbbyteswapped) {
511 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
512 tdbir += sizeof(hdrNum.ui);
516 /*@=bounds =sizeoftype@*/
523 /* XXX assumes hdrNum is first int in dbiIndexItem */
524 static int hdrNumCmp(const void * one, const void * two)
527 const int * a = one, * b = two;
532 * Append element(s) to set of index database items.
533 * @param set set of index database items
534 * @param recs array of items to append to set
535 * @param nrecs number of items
536 * @param recsize size of an array item
537 * @param sortset should resulting set be sorted?
538 * @return 0 success, 1 failure (bad args)
540 static int dbiAppendSet(dbiIndexSet set, const void * recs,
541 int nrecs, size_t recsize, int sortset)
544 const char * rptr = recs;
545 size_t rlen = (recsize < sizeof(*(set->recs)))
546 ? recsize : sizeof(*(set->recs));
548 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
551 set->recs = xrealloc(set->recs,
552 (set->count + nrecs) * sizeof(*(set->recs)));
554 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
556 while (nrecs-- > 0) {
557 /*@-mayaliasunique@*/
558 memcpy(set->recs + set->count, rptr, rlen);
559 /*@=mayaliasunique@*/
564 if (sortset && set->count > 1)
565 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
571 * Remove element(s) from set of index database items.
572 * @param set set of index database items
573 * @param recs array of items to remove from set
574 * @param nrecs number of items
575 * @param recsize size of an array item
576 * @param sorted array is already sorted?
577 * @return 0 success, 1 failure (no items found)
579 static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
580 size_t recsize, int sorted)
581 /*@modifies set, recs @*/
585 int num = set->count;
588 assert(set->count > 0);
589 if (nrecs > 1 && !sorted)
590 qsort(recs, nrecs, recsize, hdrNumCmp);
592 for (from = 0; from < num; from++) {
593 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
598 set->recs[to] = set->recs[from]; /* structure assignment */
602 return (numCopied == num);
605 /* XXX transaction.c */
606 unsigned int dbiIndexSetCount(dbiIndexSet set) {
610 /* XXX transaction.c */
611 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
612 return set->recs[recno].hdrNum;
615 /* XXX transaction.c */
616 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
617 return set->recs[recno].tagNum;
620 /* XXX transaction.c */
621 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) {
623 set->recs = _free(set->recs);
632 static sigset_t caught;
635 static void handler(int signum)
636 /*@globals caught @*/
637 /*@modifies caught @*/;
644 struct sigaction act;
645 struct sigaction oact;
647 { SIGHUP, 0, { {handler} } },
648 { SIGINT, 0, { {handler} } },
649 { SIGTERM, 0, { {handler} } },
650 { SIGQUIT, 0, { {handler} } },
651 { -1, 0, { {NULL} } },
656 static void handler(int signum)
659 struct sigtbl_s * tbl;
661 for(tbl = satbl; tbl->signum >= 0; tbl++) {
662 if (tbl->signum != signum)
666 sigaddset(&caught, signum);
672 * Enable all signal handlers
674 static int enableSignals(void)
675 /*@globals caught, satbl, fileSystem @*/
676 /*@modifies *oldMask, caught, satbl, fileSystem @*/
678 struct sigtbl_s * tbl;
679 sigset_t newMask, oldMask;
682 (void) sigfillset(&newMask); /* block all signals */
683 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
685 for(tbl = satbl; tbl->signum >= 0; tbl++) {
686 if (tbl->active++ > 0)
688 sigdelset(&caught, tbl->signum);
689 rc = sigaction(tbl->signum, &tbl->act, &tbl->oact);
692 return sigprocmask(SIG_SETMASK, &oldMask, NULL);
701 static int checkSignals(void)
702 /*@globals fileSystem @*/
703 /*@modifies fileSystem @*/
705 struct sigtbl_s * tbl;
706 sigset_t newMask, oldMask;
709 (void) sigfillset(&newMask); /* block all signals */
710 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
711 for(tbl = satbl; tbl->signum >= 0; tbl++) {
712 if (tbl->active == 0)
714 if (sigismember(&caught, tbl->signum))
720 rpmMessage(RPMMESS_WARNING, "Exiting on signal ...\n");
721 while ((db = dbrock) != NULL) {
722 dbrock = db->db_next;
724 (void) rpmdbClose(db);
728 return sigprocmask(SIG_SETMASK, &oldMask, NULL);
732 * Disable all signal handlers
734 static int disableSignals(void)
735 /*@globals caught, fileSystem @*/
736 /*@modifies db, caught, fileSystem @*/
738 struct sigtbl_s * tbl;
739 sigset_t newMask, oldMask;
742 (void) sigfillset(&newMask); /* block all signals */
743 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
745 for(tbl = satbl; tbl->signum >= 0; tbl++) {
746 if (--tbl->active > 0)
748 rc = sigaction(tbl->signum, &tbl->oact, NULL);
751 return sigprocmask(SIG_SETMASK, &oldMask, NULL);
756 * Block all signals, returning previous signal mask.
758 static int blockSignals(rpmdb db, /*@out@*/ sigset_t * oldMask)
759 /*@globals caught, satbl, fileSystem @*/
760 /*@modifies *oldMask, caught, satbl, fileSystem @*/
762 struct sigtbl_s * tbl;
765 (void) sigfillset(&newMask); /* block all signals */
766 (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
767 for(tbl = satbl; tbl->signum >= 0; tbl++) {
768 if (tbl->active == 0)
770 (void) sigdelset(&newMask, tbl->signum);
772 return sigprocmask(SIG_BLOCK, &newMask, NULL);
776 * Restore signal mask.
779 static int unblockSignals(rpmdb db, sigset_t * oldMask)
780 /*@globals caught, fileSystem @*/
781 /*@modifies db, caught, fileSystem @*/
784 return sigprocmask(SIG_SETMASK, oldMask, NULL);
788 #define _DB_HOME "%{_dbpath}"
791 #define _DB_PERMS 0644
794 #define _DB_ERRPFX "rpmdb"
797 /*@observer@*/ /*@unchecked@*/
798 static struct rpmdb_s dbTemplate = {
799 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
800 _DB_MAJOR, _DB_ERRPFX
804 int rpmdbOpenAll(rpmdb db)
809 if (db == NULL) return -2;
812 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
813 if (db->_dbi[dbix] != NULL)
815 (void) dbiOpen(db, dbiTags[dbix], db->db_flags);
820 int rpmdbCloseDBI(rpmdb db, int rpmtag)
825 if (db == NULL || db->_dbi == NULL || dbiTags == NULL)
828 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
829 if (dbiTags[dbix] != rpmtag)
832 if (db->_dbi[dbix] != NULL) {
834 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
835 xx = dbiClose(db->_dbi[dbix], 0);
836 if (xx && rc == 0) rc = xx;
837 db->_dbi[dbix] = NULL;
838 /*@=unqualifiedtrans@*/
846 /* XXX query.c, rpminstall.c, verify.c */
847 int rpmdbClose(rpmdb db)
856 (void) rpmdbUnlink(db, "rpmdbClose");
863 for (dbix = db->db_ndbi; --dbix >= 0; ) {
865 if (db->_dbi[dbix] == NULL)
867 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
868 xx = dbiClose(db->_dbi[dbix], 0);
869 if (xx && rc == 0) rc = xx;
870 db->_dbi[dbix] = NULL;
871 /*@=unqualifiedtrans@*/
873 db->db_errpfx = _free(db->db_errpfx);
874 db->db_root = _free(db->db_root);
875 db->db_home = _free(db->db_home);
876 db->db_bits = PBM_FREE(db->db_bits);
877 db->_dbi = _free(db->_dbi);
880 while ((next = *prev) != NULL && next != db)
881 prev = &next->db_next;
883 *prev = next->db_next;
884 next->db_next = NULL;
887 /*@-refcounttrans@*/ db = _free(db); /*@=refcounttrans@*/
891 (void) disableSignals();
895 int rpmdbSync(rpmdb db)
900 if (db == NULL) return 0;
901 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
903 if (db->_dbi[dbix] == NULL)
905 xx = dbiSync(db->_dbi[dbix], 0);
906 if (xx && rc == 0) rc = xx;
912 static /*@only@*/ /*@null@*/
913 rpmdb newRpmdb(/*@kept@*/ /*@null@*/ const char * root,
914 /*@kept@*/ /*@null@*/ const char * home,
915 int mode, int perms, int flags)
916 /*@globals _db_filter_dups, rpmGlobalMacroContext @*/
917 /*@modifies _db_filter_dups, rpmGlobalMacroContext @*/
919 rpmdb db = xcalloc(sizeof(*db), 1);
920 const char * epfx = _DB_ERRPFX;
921 static int _initialized = 0;
924 _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}");
930 *db = dbTemplate; /* structure assignment */
936 if (!(perms & 0600)) perms = 0644; /* XXX sanity */
938 if (mode >= 0) db->db_mode = mode;
939 if (perms >= 0) db->db_perms = perms;
940 if (flags >= 0) db->db_flags = flags;
943 db->db_root = rpmGetPath( (root && *root ? root : _DB_ROOT), NULL);
944 db->db_home = rpmGetPath( (home && *home ? home : _DB_HOME), NULL);
946 if (!(db->db_home && db->db_home[0] != '%')) {
947 rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
948 db->db_root = _free(db->db_root);
949 db->db_home = _free(db->db_home);
951 /*@-globstate@*/ return NULL; /*@=globstate@*/
953 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
954 db->db_remove_env = 0;
955 db->db_filter_dups = _db_filter_dups;
956 db->db_ndbi = dbiTagsMax;
957 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
960 return rpmdbLink(db, "rpmdbCreate");
965 static int openDatabase(/*@null@*/ const char * prefix,
966 /*@null@*/ const char * dbpath,
967 int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp,
968 int mode, int perms, int flags)
969 /*@globals rpmGlobalMacroContext,
971 /*@modifies *dbp, fileSystem @*/
972 /*@requires maxSet(dbp) >= 0 @*/
976 static int _tags_initialized = 0;
978 static int _dbenv_removed = 0;
980 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
981 int minimal = flags & RPMDB_FLAG_MINIMAL;
983 if (!_tags_initialized || dbiTagsMax == 0) {
990 /* Insure that _dbapi has one of -1, 1, 2, or 3 */
991 if (_dbapi < -1 || _dbapi > 3)
1002 db = newRpmdb(prefix, dbpath, mode, perms, flags);
1008 if (!_dbenv_removed) {
1009 static int _enable_cdb = -1;
1011 /* XXX hack in suoport for CDB, otherwise nuke the state. */
1013 if (_enable_cdb < 0)
1014 _enable_cdb = rpmExpandNumeric("%{?__dbi_cdb:1}");
1021 i = sizeof("//__db.000");
1022 if (db->db_root) i += strlen(db->db_root);
1023 if (db->db_home) i += strlen(db->db_home);
1025 for (i = 0; i < 16; i++) {
1026 sprintf(fn, "%s/%s/__db.%03d",
1027 (db->db_root ? db->db_root : ""),
1028 (db->db_home ? db->db_home : ""), i);
1029 (void) rpmCleanPath(fn);
1036 (void) enableSignals();
1039 db->db_api = _dbapi;
1044 if (dbiTags != NULL)
1045 for (dbix = 0; rc == 0 && dbix < dbiTagsMax; dbix++) {
1049 /* Filter out temporary databases */
1050 switch ((rpmtag = dbiTags[dbix])) {
1051 case RPMDBI_AVAILABLE:
1053 case RPMDBI_REMOVED:
1054 case RPMDBI_DEPENDS:
1056 /*@notreached@*/ /*@switchbreak@*/ break;
1058 /*@switchbreak@*/ break;
1061 dbi = dbiOpen(db, rpmtag, 0);
1068 case RPMDBI_PACKAGES:
1069 if (dbi == NULL) rc |= 1;
1070 /* XXX open only Packages, indices created on the fly. */
1072 if (db->db_api == 3)
1075 /*@notreached@*/ /*@switchbreak@*/ break;
1077 if (dbi == NULL) rc |= 1;
1080 /*@switchbreak@*/ break;
1082 /*@switchbreak@*/ break;
1088 if (rc || justCheck || dbp == NULL)
1089 xx = rpmdbClose(db);
1091 db->db_next = dbrock;
1099 rpmdb XrpmdbUnlink(rpmdb db, const char * msg, const char * fn, unsigned ln)
1103 fprintf(stderr, "--> db %p -- %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
1109 rpmdb XrpmdbLink(rpmdb db, const char * msg, const char * fn, unsigned ln)
1114 fprintf(stderr, "--> db %p ++ %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
1116 /*@-refcounttrans@*/ return db; /*@=refcounttrans@*/
1119 /* XXX python/rpmmodule.c */
1120 /*@-globs@*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
1121 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
1124 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1127 return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
1131 int rpmdbInit (const char * prefix, int perms)
1135 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1140 rc = openDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
1141 perms, RPMDB_FLAG_JUSTCHECK);
1145 xx = rpmdbOpenAll(db);
1146 if (xx && rc == 0) rc = xx;
1147 xx = rpmdbClose(db);
1148 if (xx && rc == 0) rc = xx;
1154 int rpmdbVerify(const char * prefix)
1158 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1163 rc = openDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
1169 rc = rpmdbOpenAll(db);
1171 for (dbix = db->db_ndbi; --dbix >= 0; ) {
1172 if (db->_dbi[dbix] == NULL)
1174 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
1175 xx = dbiVerify(db->_dbi[dbix], 0);
1176 if (xx && rc == 0) rc = xx;
1177 db->_dbi[dbix] = NULL;
1178 /*@=unqualifiedtrans@*/
1181 /*@-nullstate@*/ /* FIX: db->_dbi[] may be NULL. */
1182 xx = rpmdbClose(db);
1184 if (xx && rc == 0) rc = xx;
1191 static int rpmdbFindByFile(rpmdb db, /*@null@*/ const char * filespec,
1192 DBT * key, DBT * data, /*@out@*/ dbiIndexSet * matches)
1193 /*@globals fileSystem @*/
1194 /*@modifies db, *key, *data, *matches, fileSystem @*/
1196 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
1197 HFD_t hfd = headerFreeData;
1198 const char * dirName;
1199 const char * baseName;
1200 rpmTagType bnt, dnt;
1201 fingerPrintCache fpc;
1203 dbiIndex dbi = NULL;
1205 dbiIndexSet allMatches = NULL;
1206 dbiIndexItem rec = NULL;
1214 if (filespec == NULL) return -2;
1217 if ((baseName = strrchr(filespec, '/')) != NULL) {
1221 len = baseName - filespec + 1;
1223 t = strncpy(alloca(len + 1), filespec, len);
1230 baseName = filespec;
1233 if (baseName == NULL)
1236 fpc = fpCacheCreate(20);
1237 fp1 = fpLookup(fpc, dirName, baseName, 1);
1239 dbi = dbiOpen(db, RPMTAG_BASENAMES, 0);
1243 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1246 key->data = (void *) baseName;
1248 key->size = strlen(baseName);
1249 if (key->size == 0) key->size++; /* XXX "/" fixup. */
1251 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1253 rpmError(RPMERR_DBGETINDEX,
1254 _("error(%d) getting \"%s\" records from %s index\n"),
1255 rc, key->data, tagName(dbi->dbi_rpmtag));
1259 (void) dbt2set(dbi, data, &allMatches);
1261 xx = dbiCclose(dbi, dbcursor, 0);
1268 allMatches = dbiFreeIndexSet(allMatches);
1269 fpc = fpCacheFree(fpc);
1274 *matches = xcalloc(1, sizeof(**matches));
1276 rec = dbiIndexNewItem(0, 0);
1278 if (allMatches != NULL)
1279 while (i < allMatches->count) {
1280 const char ** baseNames, ** dirNames;
1281 int_32 * dirIndexes;
1282 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
1283 unsigned int prevoff;
1286 { rpmdbMatchIterator mi;
1287 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset));
1288 h = rpmdbNextIterator(mi);
1291 mi = rpmdbFreeIterator(mi);
1299 xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, NULL);
1300 xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
1301 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
1305 int num = dbiIndexRecordFileNumber(allMatches, i);
1307 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
1309 if (FP_EQUAL(fp1, fp2)) {
1311 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
1312 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
1313 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
1318 offset = dbiIndexRecordOffset(allMatches, i);
1319 } while (i < allMatches->count &&
1320 (i == 0 || offset == prevoff));
1322 baseNames = hfd(baseNames, bnt);
1323 dirNames = hfd(dirNames, dnt);
1328 allMatches = dbiFreeIndexSet(allMatches);
1330 fpc = fpCacheFree(fpc);
1332 if ((*matches)->count == 0) {
1334 *matches = dbiFreeIndexSet(*matches);
1342 /* XXX python/upgrade.c, install.c, uninstall.c */
1343 int rpmdbCountPackages(rpmdb db, const char * name)
1345 DBC * dbcursor = NULL;
1346 DBT * key = alloca(sizeof(*key));
1347 DBT * data = alloca(sizeof(*data));
1355 memset(key, 0, sizeof(*key));
1356 memset(data, 0, sizeof(*data));
1358 dbi = dbiOpen(db, RPMTAG_NAME, 0);
1363 key->data = (void *) name;
1365 key->size = strlen(name);
1367 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1368 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1369 xx = dbiCclose(dbi, dbcursor, 0);
1372 if (rc == 0) { /* success */
1373 dbiIndexSet matches;
1374 /*@-nullpass@*/ /* FIX: matches might be NULL */
1376 (void) dbt2set(dbi, data, &matches);
1378 rc = dbiIndexSetCount(matches);
1379 matches = dbiFreeIndexSet(matches);
1383 if (rc == DB_NOTFOUND) { /* not found */
1385 } else { /* error */
1386 rpmError(RPMERR_DBGETINDEX,
1387 _("error(%d) getting \"%s\" records from %s index\n"),
1388 rc, key->data, tagName(dbi->dbi_rpmtag));
1396 * Attempt partial matches on name[-version[-release]] strings.
1397 * @param dbi index database handle (always RPMTAG_NAME)
1398 * @param dbcursor index database cursor
1399 * @param key search key/length/flags
1400 * @param data search data/length/flags
1401 * @param name package name
1402 * @param version package version (can be a pattern)
1403 * @param release package release (can be a pattern)
1404 * @retval matches set of header instances that match
1405 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
1407 static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
1408 DBT * key, DBT * data,
1410 /*@null@*/ const char * version,
1411 /*@null@*/ const char * release,
1412 /*@out@*/ dbiIndexSet * matches)
1413 /*@globals fileSystem @*/
1414 /*@modifies dbi, *dbcursor, *key, *data, *matches, fileSystem @*/
1415 /*@requires maxSet(*matches) >= 0 @*/
1422 key->data = (void *) name;
1424 key->size = strlen(name);
1426 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1428 if (rc == 0) { /* success */
1429 (void) dbt2set(dbi, data, matches);
1430 if (version == NULL && release == NULL)
1433 if (rc == DB_NOTFOUND) { /* not found */
1434 return RPMRC_NOTFOUND;
1435 } else { /* error */
1436 rpmError(RPMERR_DBGETINDEX,
1437 _("error(%d) getting \"%s\" records from %s index\n"),
1438 rc, key->data, tagName(dbi->dbi_rpmtag));
1442 /* Make sure the version and release match. */
1444 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
1445 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
1446 rpmdbMatchIterator mi;
1452 mi = rpmdbInitIterator(dbi->dbi_rpmdb,
1453 RPMDBI_PACKAGES, &recoff, sizeof(recoff));
1455 /* Set iterator selectors for version/release if available. */
1457 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
1463 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
1469 h = rpmdbNextIterator(mi);
1472 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
1474 (*matches)->recs[i].hdrNum = 0;
1476 mi = rpmdbFreeIterator(mi);
1482 (*matches)->count = gotMatches;
1486 rc = RPMRC_NOTFOUND;
1490 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1491 if (rc && matches && *matches)
1492 *matches = dbiFreeIndexSet(*matches);
1493 /*@=unqualifiedtrans@*/
1499 * Lookup by name, name-version, and finally by name-version-release.
1500 * Both version and release can be patterns.
1501 * @todo Name must be an exact match, as name is a db key.
1502 * @param dbi index database handle (always RPMTAG_NAME)
1503 * @param dbcursor index database cursor
1504 * @param key search key/length/flags
1505 * @param data search data/length/flags
1506 * @param arg name[-version[-release]] string
1507 * @retval matches set of header instances that match
1508 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
1510 static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
1511 /*@null@*/ const char * arg, /*@out@*/ dbiIndexSet * matches)
1512 /*@globals fileSystem @*/
1513 /*@modifies dbi, *dbcursor, *key, *data, *matches, fileSystem @*/
1514 /*@requires maxSet(*matches) >= 0 @*/
1516 const char * release;
1523 if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND;
1525 /* did they give us just a name? */
1526 rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches);
1527 if (rc != RPMRC_NOTFOUND) return rc;
1530 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1531 *matches = dbiFreeIndexSet(*matches);
1532 /*@=unqualifiedtrans@*/
1535 /* maybe a name and a release */
1536 localarg = alloca(strlen(arg) + 1);
1537 s = stpcpy(localarg, arg);
1541 for (s -= 1; s > localarg; s--) {
1545 /*@switchbreak@*/ break;
1547 if (c != '[') brackets = 0;
1548 /*@switchbreak@*/ break;
1551 if (!brackets && *s == '-')
1555 /*@-nullstate@*/ /* FIX: *matches may be NULL. */
1556 if (s == localarg) return RPMRC_NOTFOUND;
1560 rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches);
1563 if (rc != RPMRC_NOTFOUND) return rc;
1566 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1567 *matches = dbiFreeIndexSet(*matches);
1568 /*@=unqualifiedtrans@*/
1571 /* how about name-version-release? */
1577 for (; s > localarg; s--) {
1581 /*@switchbreak@*/ break;
1583 if (c != '[') brackets = 0;
1584 /*@switchbreak@*/ break;
1587 if (!brackets && *s == '-')
1591 if (s == localarg) return RPMRC_NOTFOUND;
1595 /*@-nullstate@*/ /* FIX: *matches may be NULL. */
1596 return dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches);
1601 typedef struct miRE_s {
1602 rpmTag tag; /*!< header tag */
1603 rpmMireMode mode; /*!< pattern match mode */
1604 /*@only@*/ const char * pattern; /*!< pattern string */
1605 int notmatch; /*!< like "grep -v" */
1606 /*@only@*/ regex_t * preg; /*!< regex compiled pattern buffer */
1607 int cflags; /*!< regcomp(3) flags */
1608 int eflags; /*!< regexec(3) flags */
1609 int fnflags; /*!< fnmatch(3) flags */
1612 struct _rpmdbMatchIterator {
1614 const void * mi_keyp;
1624 /*@refcounted@*/ /*@null@*/
1629 unsigned int mi_prevoffset;
1630 unsigned int mi_offset;
1631 unsigned int mi_filenum;
1633 /*@only@*/ /*@null@*/
1638 rpmRC (*mi_hdrchk) (rpmts ts, const void * uh, size_t uc, const char ** msg)
1639 /*@modifies ts, *msg @*/;
1644 * Rewrite a header into packages (if necessary) and free the header.
1645 * Note: this is called from a markReplacedFiles iteration, and *must*
1646 * preserve the "join key" (i.e. offset) for the header.
1647 * @param mi database iterator
1648 * @param dbi index database handle
1649 * @return 0 on success
1651 static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
1652 /*@globals fileSystem @*/
1653 /*@modifies mi, fileSystem @*/
1657 if (mi == NULL || mi->mi_h == NULL)
1660 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
1661 DBT * key = &mi->mi_key;
1662 DBT * data = &mi->mi_data;
1663 sigset_t signalMask;
1666 /*@i@*/ key->data = (void *) &mi->mi_prevoffset;
1667 key->size = sizeof(mi->mi_prevoffset);
1668 data->data = headerUnload(mi->mi_h);
1669 data->size = headerSizeof(mi->mi_h, HEADER_MAGIC_NO);
1672 /* Check header digest/signature (if requested). */
1673 if (mi->mi_ts && mi->mi_hdrchk) {
1674 const char * msg = NULL;
1676 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, data->data, data->size, &msg);
1681 if (data->data != NULL) {
1682 (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
1683 rc = dbiPut(dbi, mi->mi_dbc, key, data, DB_KEYLAST);
1685 rpmError(RPMERR_DBPUTINDEX,
1686 _("error(%d) storing record #%d into %s\n"),
1687 rc, mi->mi_prevoffset, tagName(dbi->dbi_rpmtag));
1689 xx = dbiSync(dbi, 0);
1690 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
1692 data->data = _free(data->data);
1696 mi->mi_h = headerFree(mi->mi_h);
1703 rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
1712 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
1713 if (dbi == NULL) /* XXX can't happen */
1716 xx = miFreeHeader(mi, dbi);
1719 xx = dbiCclose(dbi, mi->mi_dbc, 0);
1722 if (mi->mi_re != NULL)
1723 for (i = 0; i < mi->mi_nre; i++) {
1724 miRE mire = mi->mi_re + i;
1725 mire->pattern = _free(mire->pattern);
1726 if (mire->preg != NULL) {
1727 regfree(mire->preg);
1728 /*@+voidabstract -usereleased @*/ /* LCL: regfree has bogus only */
1729 mire->preg = _free(mire->preg);
1730 /*@=voidabstract =usereleased @*/
1733 mi->mi_re = _free(mi->mi_re);
1735 mi->mi_set = dbiFreeIndexSet(mi->mi_set);
1736 mi->mi_keyp = _free(mi->mi_keyp);
1737 mi->mi_db = rpmdbUnlink(mi->mi_db, "matchIterator");
1745 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
1746 return (mi ? mi->mi_offset : 0);
1749 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
1750 return (mi ? mi->mi_filenum : 0);
1753 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
1754 return (mi && mi->mi_set ? mi->mi_set->count : 0);
1758 * Return pattern match.
1759 * @param mire match iterator regex
1760 * @param val value to match
1761 * @return 0 if pattern matches, >0 on nomatch, <0 on error
1763 static int miregexec(miRE mire, const char * val)
1768 switch (mire->mode) {
1769 case RPMMIRE_STRCMP:
1770 rc = strcmp(mire->pattern, val);
1773 case RPMMIRE_DEFAULT:
1776 rc = regexec(mire->preg, val, 0, NULL, mire->eflags);
1778 if (rc && rc != REG_NOMATCH) {
1780 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
1781 msg[sizeof(msg)-1] = '\0';
1782 rpmError(RPMERR_REGEXEC, "%s: regexec failed: %s\n",
1783 mire->pattern, msg);
1788 rc = fnmatch(mire->pattern, val, mire->fnflags);
1789 if (rc && rc != FNM_NOMATCH)
1801 * Compare iterator selectors by rpm tag (qsort/bsearch).
1802 * @param a 1st iterator selector
1803 * @param b 2nd iterator selector
1804 * @return result of comparison
1806 static int mireCmp(const void * a, const void * b)
1808 const miRE mireA = (const miRE) a;
1809 const miRE mireB = (const miRE) b;
1810 return (mireA->tag - mireB->tag);
1814 * Copy pattern, escaping for appropriate mode.
1815 * @param tag rpm tag
1816 * @retval modep type of pattern match
1817 * @param pattern pattern to duplicate
1818 * @return duplicated pattern
1820 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep,
1821 const char * pattern)
1822 /*@modifies *modep @*/
1823 /*@requires maxSet(modep) >= 0 @*/
1835 case RPMMIRE_DEFAULT:
1836 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
1837 *modep = RPMMIRE_GLOB;
1838 pat = xstrdup(pattern);
1842 nb = strlen(pattern) + sizeof("^$");
1844 /* Find no. of bytes needed for pattern. */
1845 /* periods are escaped, splats become '.*' */
1848 for (s = pattern; *s != '\0'; s++) {
1852 if (!brackets) nb++;
1853 /*@switchbreak@*/ break;
1856 /*@switchbreak@*/ break;
1859 /*@switchbreak@*/ break;
1861 if (c != '[') brackets = 0;
1862 /*@switchbreak@*/ break;
1867 pat = t = xmalloc(nb);
1869 if (pattern[0] != '^') *t++ = '^';
1871 /* Copy pattern, escaping periods, prefixing splats with period. */
1874 for (s = pattern; *s != '\0'; s++, t++) {
1877 if (!brackets) *t++ = '\\';
1878 /*@switchbreak@*/ break;
1880 if (!brackets) *t++ = '.';
1881 /*@switchbreak@*/ break;
1884 /*@switchbreak@*/ break;
1887 /*@switchbreak@*/ break;
1889 if (c != '[') brackets = 0;
1890 /*@switchbreak@*/ break;
1895 if (s > pattern && s[-1] != '$') *t++ = '$';
1897 *modep = RPMMIRE_REGEX;
1899 case RPMMIRE_STRCMP:
1902 pat = xstrdup(pattern);
1910 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag,
1911 rpmMireMode mode, const char * pattern)
1913 static rpmMireMode defmode = (rpmMireMode)-1;
1915 const char * allpat = NULL;
1917 regex_t * preg = NULL;
1924 if (defmode == (rpmMireMode)-1) {
1926 const char *t = rpmExpand("%{?_query_selector_match}", NULL);
1928 if (*t == '\0' || !strcmp(t, "default"))
1929 defmode = RPMMIRE_DEFAULT;
1930 else if (!strcmp(t, "strcmp"))
1931 defmode = RPMMIRE_STRCMP;
1932 else if (!strcmp(t, "regex"))
1933 defmode = RPMMIRE_REGEX;
1934 else if (!strcmp(t, "glob"))
1935 defmode = RPMMIRE_GLOB;
1937 defmode = RPMMIRE_DEFAULT;
1941 if (mi == NULL || pattern == NULL)
1944 /* Leading '!' inverts pattern match sense, like "grep -v". */
1945 if (*pattern == '!') {
1952 allpat = mireDup(tag, &mode, pattern);
1955 if (mode == RPMMIRE_DEFAULT)
1960 case RPMMIRE_DEFAULT:
1961 case RPMMIRE_STRCMP:
1965 preg = xcalloc(1, sizeof(*preg));
1967 cflags = (REG_EXTENDED | REG_NOSUB);
1968 rc = regcomp(preg, allpat, cflags);
1971 (void) regerror(rc, preg, msg, sizeof(msg)-1);
1972 msg[sizeof(msg)-1] = '\0';
1973 rpmError(RPMERR_REGCOMP, "%s: regcomp failed: %s\n", allpat, msg);
1977 fnflags = FNM_PATHNAME | FNM_PERIOD;
1986 /*@=kepttrans@*/ /* FIX: mire has kept values */
1987 allpat = _free(allpat);
1990 /*@+voidabstract -usereleased @*/ /* LCL: regfree has bogus only */
1992 /*@=voidabstract =usereleased @*/
1998 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
1999 mire = mi->mi_re + mi->mi_nre;
2004 mire->pattern = allpat;
2005 mire->notmatch = notmatch;
2007 mire->cflags = cflags;
2008 mire->eflags = eflags;
2009 mire->fnflags = fnflags;
2013 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
2020 * Return iterator selector match.
2021 * @param mi rpm database iterator
2022 * @return 1 if header should be skipped
2024 static int mireSkip (const rpmdbMatchIterator mi)
2027 HGE_t hge = (HGE_t) headerGetEntryMinMemory;
2028 HFD_t hfd = (HFD_t) headerFreeData;
2046 if (mi->mi_h == NULL) /* XXX can't happen */
2050 * Apply tag tests, implicitly "||" for multiple patterns/values of a
2051 * single tag, implicitly "&&" between multiple tag patterns.
2054 if ((mire = mi->mi_re) != NULL)
2055 for (i = 0; i < mi->mi_nre; i++, mire++) {
2058 if (!hge(mi->mi_h, mire->tag, &t, (void **)&u, &c))
2061 anymatch = 0; /* no matches yet */
2066 sprintf(numbuf, "%d", (int) *u.i8p);
2067 rc = miregexec(mire, numbuf);
2068 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2070 /*@switchbreak@*/ break;
2071 case RPM_INT16_TYPE:
2072 sprintf(numbuf, "%d", (int) *u.i16p);
2073 rc = miregexec(mire, numbuf);
2074 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2076 /*@switchbreak@*/ break;
2077 case RPM_INT32_TYPE:
2078 sprintf(numbuf, "%d", (int) *u.i32p);
2079 rc = miregexec(mire, numbuf);
2080 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2082 /*@switchbreak@*/ break;
2083 case RPM_STRING_TYPE:
2084 rc = miregexec(mire, u.str);
2085 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
2087 /*@switchbreak@*/ break;
2088 case RPM_I18NSTRING_TYPE:
2089 case RPM_STRING_ARRAY_TYPE:
2090 for (j = 0; j < c; j++) {
2091 rc = miregexec(mire, u.argv[j]);
2092 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) {
2094 /*@innerbreak@*/ break;
2097 /*@switchbreak@*/ break;
2101 /*@switchbreak@*/ break;
2103 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
2106 /*@innercontinue@*/ continue;
2108 /*@innerbreak@*/ break;
2112 u.ptr = hfd(u.ptr, t);
2119 return (ntags == nmatches ? 0 : 1);
2122 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite)
2127 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
2129 mi->mi_cflags |= DB_WRITECURSOR;
2131 mi->mi_cflags &= ~DB_WRITECURSOR;
2135 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified)
2140 rc = mi->mi_modified;
2141 mi->mi_modified = modified;
2145 int rpmdbSetHdrChk(rpmdbMatchIterator mi, rpmts ts,
2146 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
2151 /*@-assignexpose -newreftrans @*/
2152 /*@i@*/ mi->mi_ts = ts;
2153 mi->mi_hdrchk = hdrchk;
2154 /*@=assignexpose =newreftrans @*/
2159 /*@-nullstate@*/ /* FIX: mi->mi_key.data may be NULL */
2160 Header rpmdbNextIterator(rpmdbMatchIterator mi)
2175 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
2180 * Cursors are per-iterator, not per-dbi, so get a cursor for the
2181 * iterator on 1st call. If the iteration is to rewrite headers, and the
2182 * CDB model is used for the database, then the cursor needs to
2183 * marked with DB_WRITECURSOR as well.
2185 if (mi->mi_dbc == NULL)
2186 xx = dbiCopen(dbi, dbi->dbi_txnid, &mi->mi_dbc, mi->mi_cflags);
2190 memset(key, 0, sizeof(*key));
2191 data = &mi->mi_data;
2192 memset(data, 0, sizeof(*data));
2200 /*@-branchstate -compmempass @*/
2202 if (!(mi->mi_setx < mi->mi_set->count))
2204 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
2205 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
2206 keyp = &mi->mi_offset;
2207 keylen = sizeof(mi->mi_offset);
2210 key->data = keyp = (void *)mi->mi_keyp;
2211 key->size = keylen = mi->mi_keylen;
2214 #if !defined(_USE_COPY_LOAD)
2215 data->flags |= DB_DBT_MALLOC;
2217 rc = dbiGet(dbi, mi->mi_dbc, key, data,
2218 (key->data == NULL ? DB_NEXT : DB_SET));
2226 * If we got the next key, save the header instance number.
2228 * For db3 Packages, instance 0 (i.e. mi->mi_setx == 0) is the
2229 * largest header instance in the database, and should be
2233 if (keyp && mi->mi_setx && rc == 0)
2234 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
2237 /* Terminate on error or end of keys */
2238 if (rc || (mi->mi_setx && mi->mi_offset == 0))
2241 /*@=branchstate =compmempass @*/
2243 } while (mi->mi_offset == 0);
2245 /* If next header is identical, return it now. */
2246 /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
2247 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
2249 /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
2251 /* Retrieve next header blob for index iterator. */
2252 /*@-branchstate -compmempass -immediatetrans @*/
2256 #if !defined(_USE_COPY_LOAD)
2257 data->flags |= DB_DBT_MALLOC;
2259 rc = dbiGet(dbi, mi->mi_dbc, key, data, DB_SET);
2268 /*@=branchstate =compmempass =immediatetrans @*/
2270 /* Rewrite current header (if necessary) and unlink. */
2271 xx = miFreeHeader(mi, dbi);
2273 /* Is this the end of the iteration? */
2277 /* Check header digest/signature once (if requested). */
2278 /*@-boundsread -branchstate -sizeoftype @*/
2279 if (mi->mi_hdrchk && mi->mi_ts) {
2280 const char * msg = NULL;
2281 pbm_set * set = NULL;
2282 rpmRC rpmrc = RPMRC_NOTFOUND;
2284 if (mi->mi_db->db_bits) {
2285 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
2286 &mi->mi_db->db_nbits, mi->mi_offset);
2287 if (PBM_ISSET(mi->mi_offset, set)) {
2289 rpmMessage(RPMMESS_DEBUG, _("h#%7u: already checked.\n"),
2295 if (rpmrc == RPMRC_NOTFOUND) {
2296 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg);
2298 rpmMessage(RPMMESS_DEBUG, _("h#%7u: %s"),
2299 mi->mi_offset, msg);
2300 if (set && rpmrc == RPMRC_OK)
2301 PBM_SET(mi->mi_offset, set);
2303 if (rpmrc == RPMRC_FAIL) {
2304 rpmError(RPMERR_BADHEADER, _("rpmdb: header #%u: %s -- skipping.\n"),
2305 mi->mi_offset, (msg ? msg : ""));
2311 /*@=boundsread =branchstate =sizeoftype @*/
2313 /* Did the header blob load correctly? */
2314 #if !defined(_USE_COPY_LOAD)
2316 mi->mi_h = headerLoad(uh);
2319 mi->mi_h->flags |= HEADERFLAG_ALLOCATED;
2321 mi->mi_h = headerCopyLoad(uh);
2323 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
2324 rpmError(RPMERR_BADHEADER,
2325 _("rpmdb: damaged header #%u retrieved -- skipping.\n"),
2331 * Skip this header if iterator selector (if any) doesn't match.
2334 /* XXX hack, can't restart with Packages locked on single instance. */
2335 if (mi->mi_set || mi->mi_keyp == NULL)
2340 mi->mi_prevoffset = mi->mi_offset;
2341 mi->mi_modified = 0;
2343 /*@-compdef -retalias -retexpose -usereleased @*/
2345 /*@=compdef =retalias =retexpose =usereleased @*/
2349 static void rpmdbSortIterator(/*@null@*/ rpmdbMatchIterator mi)
2352 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
2354 * mergesort is much (~10x with lots of identical basenames) faster
2355 * than pure quicksort, but glibc uses msort_with_tmp() on stack.
2357 #if defined(__GLIBC__)
2359 qsort(mi->mi_set->recs, mi->mi_set->count,
2360 sizeof(*mi->mi_set->recs), hdrNumCmp);
2363 mergesort(mi->mi_set->recs, mi->mi_set->count,
2364 sizeof(*mi->mi_set->recs), hdrNumCmp);
2370 /*@-bounds@*/ /* LCL: segfault */
2371 static int rpmdbGrowIterator(/*@null@*/ rpmdbMatchIterator mi, int fpNum)
2372 /*@globals fileSystem @*/
2373 /*@modifies mi, fileSystem @*/
2378 dbiIndex dbi = NULL;
2387 dbcursor = mi->mi_dbc;
2389 data = &mi->mi_data;
2390 if (key->data == NULL)
2393 dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
2397 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2398 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2399 xx = dbiCclose(dbi, dbcursor, 0);
2402 if (rc) { /* error/not found */
2403 if (rc != DB_NOTFOUND)
2404 rpmError(RPMERR_DBGETINDEX,
2405 _("error(%d) getting \"%s\" records from %s index\n"),
2406 rc, key->data, tagName(dbi->dbi_rpmtag));
2411 (void) dbt2set(dbi, data, &set);
2412 for (i = 0; i < set->count; i++)
2413 set->recs[i].fpNum = fpNum;
2416 if (mi->mi_set == NULL) {
2419 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
2420 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
2421 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
2422 set->count * sizeof(*(mi->mi_set->recs)));
2423 mi->mi_set->count += set->count;
2424 set = dbiFreeIndexSet(set);
2432 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
2433 int nHdrNums, int sorted)
2435 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2439 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
2443 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
2445 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2448 if (mi->mi_set == NULL)
2449 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
2450 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
2454 rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmTag rpmtag,
2455 const void * keyp, size_t keylen)
2457 rpmdbMatchIterator mi;
2460 dbiIndexSet set = NULL;
2462 const void * mi_keyp = NULL;
2470 /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */
2471 if (rpmtag == RPMDBI_LABEL) {
2472 rpmtag = RPMTAG_NAME;
2476 dbi = dbiOpen(db, rpmtag, 0);
2480 mi = xcalloc(1, sizeof(*mi));
2482 data = &mi->mi_data;
2485 if (rpmtag != RPMDBI_PACKAGES && keyp) {
2486 DBC * dbcursor = NULL;
2491 /* XXX HACK to get rpmdbFindByLabel out of the API */
2492 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2493 rc = dbiFindByLabel(dbi, dbcursor, key, data, keyp, &set);
2494 xx = dbiCclose(dbi, dbcursor, 0);
2496 } else if (rpmtag == RPMTAG_BASENAMES) {
2497 rc = rpmdbFindByFile(db, keyp, key, data, &set);
2499 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2502 key->data = (void *) keyp;
2505 if (key->data && key->size == 0) key->size = strlen((char *)key->data);
2506 if (key->data && key->size == 0) key->size++; /* XXX "/" fixup. */
2509 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2512 rpmError(RPMERR_DBGETINDEX,
2513 _("error(%d) getting \"%s\" records from %s index\n"),
2514 rc, (key->data ? key->data : "???"), tagName(dbi->dbi_rpmtag));
2518 (void) dbt2set(dbi, data, &set);
2520 xx = dbiCclose(dbi, dbcursor, 0);
2523 if (rc) { /* error/not found */
2524 set = dbiFreeIndexSet(set);
2534 if (rpmtag != RPMDBI_PACKAGES && keylen == 0)
2535 keylen = strlen(keyp);
2536 k = xmalloc(keylen + 1);
2538 memcpy(k, keyp, keylen);
2540 k[keylen] = '\0'; /* XXX for strings */
2544 mi->mi_keyp = mi_keyp;
2545 mi->mi_keylen = keylen;
2547 mi->mi_db = rpmdbLink(db, "matchIterator");
2548 mi->mi_rpmtag = rpmtag;
2556 mi->mi_modified = 0;
2557 mi->mi_prevoffset = 0;
2564 mi->mi_hdrchk = NULL;
2566 /*@-nullret@*/ /* FIX: mi->mi_key.data may be NULL */
2572 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum,
2573 /*@unused@*/ rpmts ts,
2574 /*@unused@*/ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
2576 DBC * dbcursor = NULL;
2577 DBT * key = alloca(sizeof(*key));
2578 DBT * data = alloca(sizeof(*data));
2579 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
2580 HFD_t hfd = headerFreeData;
2582 sigset_t signalMask;
2589 memset(key, 0, sizeof(*key));
2590 memset(data, 0, sizeof(*data));
2592 { rpmdbMatchIterator mi;
2593 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
2594 h = rpmdbNextIterator(mi);
2597 mi = rpmdbFreeIterator(mi);
2601 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
2602 "rpmdbRemove", hdrNum);
2607 /* Add remove transaction id to header. */
2608 if (rid != 0 && rid != -1) {
2610 (void) headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
2614 { const char *n, *v, *r;
2615 (void) headerNVR(h, &n, &v, &r);
2616 rpmMessage(RPMMESS_DEBUG, " --- %10u %s-%s-%s\n", hdrNum, n, v, r);
2619 (void) blockSignals(db, &signalMask);
2621 /*@-nullpass -nullptrarith -nullderef @*/ /* FIX: rpmvals heartburn */
2623 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
2625 if (dbiTags != NULL)
2626 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
2629 const char ** rpmvals = NULL;
2630 rpmTagType rpmtype = 0;
2638 rpmtag = dbiTags[dbix];
2643 /* Filter out temporary databases */
2644 case RPMDBI_AVAILABLE:
2646 case RPMDBI_REMOVED:
2647 case RPMDBI_DEPENDS:
2649 /*@notreached@*/ /*@switchbreak@*/ break;
2650 case RPMDBI_PACKAGES:
2651 dbi = dbiOpen(db, rpmtag, 0);
2652 if (dbi == NULL) /* XXX shouldn't happen */
2655 /*@-immediatetrans@*/
2656 key->data = &hdrNum;
2657 /*@=immediatetrans@*/
2658 key->size = sizeof(hdrNum);
2660 rc = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2661 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2663 rpmError(RPMERR_DBGETINDEX,
2664 _("error(%d) setting header #%d record for %s removal\n"),
2665 rc, hdrNum, tagName(dbi->dbi_rpmtag));
2667 rc = dbiDel(dbi, dbcursor, key, data, 0);
2668 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2670 if (!dbi->dbi_no_dbsync)
2671 xx = dbiSync(dbi, 0);
2673 /*@notreached@*/ /*@switchbreak@*/ break;
2677 if (!hge(h, rpmtag, &rpmtype, (void **) &rpmvals, &rpmcnt))
2680 dbi = dbiOpen(db, rpmtag, 0);
2684 if (rpmtype == RPM_STRING_TYPE) {
2685 /* XXX force uniform headerGetEntry return */
2686 av[0] = (const char *) rpmvals;
2692 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2694 for (i = 0; i < rpmcnt; i++) {
2699 switch (dbi->dbi_rpmtag) {
2700 case RPMTAG_FILEMD5S:
2701 /* Filter out empty MD5 strings. */
2702 if (!(rpmvals[i] && *rpmvals[i] != '\0'))
2703 /*@innercontinue@*/ continue;
2704 /*@switchbreak@*/ break;
2706 /*@switchbreak@*/ break;
2709 /* Identify value pointer and length. */
2715 key->size = sizeof(RPM_CHAR_TYPE);
2716 key->data = rpmvals + i;
2717 /*@switchbreak@*/ break;
2718 case RPM_INT16_TYPE:
2719 key->size = sizeof(int_16);
2720 key->data = rpmvals + i;
2721 /*@switchbreak@*/ break;
2722 case RPM_INT32_TYPE:
2723 key->size = sizeof(int_32);
2724 key->data = rpmvals + i;
2725 /*@switchbreak@*/ break;
2729 key->data = rpmvals;
2730 rpmcnt = 1; /* XXX break out of loop. */
2731 /*@switchbreak@*/ break;
2732 case RPM_STRING_TYPE:
2733 case RPM_I18NSTRING_TYPE:
2734 rpmcnt = 1; /* XXX break out of loop. */
2736 case RPM_STRING_ARRAY_TYPE:
2737 /* Convert from hex to binary. */
2739 if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
2745 for (j = 0; j < 16; j++, t++, s += 2)
2746 *t = (nibble(s[0]) << 4) | nibble(s[1]);
2749 /*@switchbreak@*/ break;
2751 /* Extract the pubkey id from the base64 blob. */
2752 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
2753 pgpDig dig = pgpNewDig();
2757 if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
2758 /*@innercontinue@*/ continue;
2759 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
2760 memcpy(bin, dig->pubkey.signid, 8);
2765 /*@switchbreak@*/ break;
2770 /*@i@*/ key->data = (void *) rpmvals[i];
2771 key->size = strlen(rpmvals[i]);
2773 /*@switchbreak@*/ break;
2777 if (rpmcnt == 1 && stringvalued) {
2778 rpmMessage(RPMMESS_DEBUG,
2779 _("removing \"%s\" from %s index.\n"),
2780 (char *)key->data, tagName(dbi->dbi_rpmtag));
2782 rpmMessage(RPMMESS_DEBUG,
2783 _("removing %d entries from %s index.\n"),
2784 rpmcnt, tagName(dbi->dbi_rpmtag));
2790 * This is almost right, but, if there are duplicate tag
2791 * values, there will be duplicate attempts to remove
2792 * the header instance. It's faster to just ignore errors
2793 * than to do things correctly.
2796 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */
2800 if (key->size == 0) key->size = strlen((char *)key->data);
2801 if (key->size == 0) key->size++; /* XXX "/" fixup. */
2804 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2805 if (rc == 0) { /* success */
2806 (void) dbt2set(dbi, data, &set);
2807 } else if (rc == DB_NOTFOUND) { /* not found */
2808 /*@innercontinue@*/ continue;
2809 } else { /* error */
2810 rpmError(RPMERR_DBGETINDEX,
2811 _("error(%d) setting \"%s\" records from %s index\n"),
2812 rc, key->data, tagName(dbi->dbi_rpmtag));
2814 /*@innercontinue@*/ continue;
2818 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
2820 /* If nothing was pruned, then don't bother updating. */
2822 set = dbiFreeIndexSet(set);
2823 /*@innercontinue@*/ continue;
2827 if (set->count > 0) {
2828 (void) set2dbt(dbi, data, set);
2829 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
2831 rpmError(RPMERR_DBPUTINDEX,
2832 _("error(%d) storing record \"%s\" into %s\n"),
2833 rc, key->data, tagName(dbi->dbi_rpmtag));
2836 data->data = _free(data->data);
2839 rc = dbiDel(dbi, dbcursor, key, data, 0);
2841 rpmError(RPMERR_DBPUTINDEX,
2842 _("error(%d) removing record \"%s\" from %s\n"),
2843 rc, key->data, tagName(dbi->dbi_rpmtag));
2848 set = dbiFreeIndexSet(set);
2852 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2855 if (!dbi->dbi_no_dbsync)
2856 xx = dbiSync(dbi, 0);
2859 if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */
2860 rpmvals = hfd(rpmvals, rpmtype);
2867 /*@=nullpass =nullptrarith =nullderef @*/
2869 (void) unblockSignals(db, &signalMask);
2873 /* XXX return ret; */
2878 int rpmdbAdd(rpmdb db, int iid, Header h,
2879 /*@unused@*/ rpmts ts,
2880 /*@unused@*/ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
2882 DBC * dbcursor = NULL;
2883 DBT * key = alloca(sizeof(*key));
2884 DBT * data = alloca(sizeof(*data));
2885 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
2886 HFD_t hfd = headerFreeData;
2887 sigset_t signalMask;
2888 const char ** baseNames;
2893 unsigned int hdrNum = 0;
2901 memset(key, 0, sizeof(*key));
2902 memset(data, 0, sizeof(*data));
2904 #ifdef NOTYET /* XXX headerRemoveEntry() broken on dribbles. */
2905 xx = headerRemoveEntry(h, RPMTAG_REMOVETID);
2907 if (iid != 0 && iid != -1) {
2909 if (!headerIsEntry(h, RPMTAG_INSTALLTID))
2910 xx = headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
2914 * If old style filename tags is requested, the basenames need to be
2915 * retrieved early, and the header needs to be converted before
2916 * being written to the package header database.
2919 xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &count);
2924 (void) blockSignals(db, &signalMask);
2927 unsigned int firstkey = 0;
2928 void * keyp = &firstkey;
2929 size_t keylen = sizeof(firstkey);
2930 void * datap = NULL;
2933 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
2937 /* XXX db0: hack to pass sizeof header to fadAlloc */
2939 datalen = headerSizeof(h, HEADER_MAGIC_NO);
2941 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2943 /* Retrieve join key for next header instance. */
2948 /*@i@*/ data->data = datap;
2949 data->size = datalen;
2950 ret = dbiGet(dbi, dbcursor, key, data, DB_SET);
2954 datalen = data->size;
2959 if (ret == 0 && datap)
2960 memcpy(&hdrNum, datap, sizeof(hdrNum));
2962 if (ret == 0 && datap) {
2963 memcpy(datap, &hdrNum, sizeof(hdrNum));
2966 datalen = sizeof(hdrNum);
2975 data->size = datalen;
2978 ret = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
2980 xx = dbiSync(dbi, 0);
2982 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2990 rpmError(RPMERR_DBCORRUPT,
2991 _("error(%d) allocating new package instance\n"), ret);
2995 /* Now update the indexes */
2998 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
3000 if (dbiTags != NULL)
3001 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
3003 const char **rpmvals = NULL;
3004 rpmTagType rpmtype = 0;
3007 int_32 * requireFlags;
3011 requireFlags = NULL;
3013 rpmtag = dbiTags[dbix];
3017 /* Filter out temporary databases */
3018 case RPMDBI_AVAILABLE:
3020 case RPMDBI_REMOVED:
3021 case RPMDBI_DEPENDS:
3023 /*@notreached@*/ /*@switchbreak@*/ break;
3024 case RPMDBI_PACKAGES:
3025 dbi = dbiOpen(db, rpmtag, 0);
3026 if (dbi == NULL) /* XXX shouldn't happen */
3028 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3029 key->data = (void *) &hdrNum;
3030 key->size = sizeof(hdrNum);
3031 data->data = headerUnload(h);
3032 data->size = headerSizeof(h, HEADER_MAGIC_NO);
3033 if (data->data != NULL) {
3035 xx = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
3037 xx = dbiSync(dbi, 0);
3039 data->data = _free(data->data);
3041 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3043 if (!dbi->dbi_no_dbsync)
3044 xx = dbiSync(dbi, 0);
3045 { const char *n, *v, *r;
3046 xx = headerNVR(h, &n, &v, &r);
3047 rpmMessage(RPMMESS_DEBUG, " +++ %10u %s-%s-%s\n", hdrNum, n, v, r);
3050 /*@notreached@*/ /*@switchbreak@*/ break;
3051 /* XXX preserve legacy behavior */
3052 case RPMTAG_BASENAMES:
3054 rpmvals = baseNames;
3056 /*@switchbreak@*/ break;
3057 case RPMTAG_REQUIRENAME:
3058 xx = hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
3059 xx = hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **)&requireFlags, NULL);
3060 /*@switchbreak@*/ break;
3062 xx = hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
3063 /*@switchbreak@*/ break;
3068 if (rpmtag != RPMTAG_GROUP)
3071 /* XXX preserve legacy behavior */
3072 rpmtype = RPM_STRING_TYPE;
3073 rpmvals = (const char **) "Unknown";
3078 dbi = dbiOpen(db, rpmtag, 0);
3082 if (rpmtype == RPM_STRING_TYPE) {
3083 /* XXX force uniform headerGetEntry return */
3084 /*@-observertrans@*/
3085 av[0] = (const char *) rpmvals;
3086 /*@=observertrans@*/
3092 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3094 for (i = 0; i < rpmcnt; i++) {
3101 * Include the tagNum in all indices. rpm-3.0.4 and earlier
3102 * included the tagNum only for files.
3105 switch (dbi->dbi_rpmtag) {
3106 case RPMTAG_PUBKEYS:
3107 /*@switchbreak@*/ break;
3108 case RPMTAG_FILEMD5S:
3109 /* Filter out empty MD5 strings. */
3110 if (!(rpmvals[i] && *rpmvals[i] != '\0'))
3111 /*@innercontinue@*/ continue;
3112 /*@switchbreak@*/ break;
3113 case RPMTAG_REQUIRENAME:
3114 /* Filter out install prerequisites. */
3115 if (requireFlags && isInstallPreReq(requireFlags[i]))
3116 /*@innercontinue@*/ continue;
3117 /*@switchbreak@*/ break;
3118 case RPMTAG_TRIGGERNAME:
3119 if (i) { /* don't add duplicates */
3121 for (j = 0; j < i; j++) {
3122 if (!strcmp(rpmvals[i], rpmvals[j]))
3123 /*@innerbreak@*/ break;
3127 /*@innercontinue@*/ continue;
3129 /*@switchbreak@*/ break;
3131 /*@switchbreak@*/ break;
3134 /* Identify value pointer and length. */
3141 key->size = sizeof(int_8);
3142 /*@i@*/ key->data = rpmvals + i;
3143 /*@switchbreak@*/ break;
3144 case RPM_INT16_TYPE:
3145 key->size = sizeof(int_16);
3146 /*@i@*/ key->data = rpmvals + i;
3147 /*@switchbreak@*/ break;
3148 case RPM_INT32_TYPE:
3149 key->size = sizeof(int_32);
3150 /*@i@*/ key->data = rpmvals + i;
3151 /*@switchbreak@*/ break;
3155 /*@i@*/ key->data = rpmvals;
3156 rpmcnt = 1; /* XXX break out of loop. */
3157 /*@switchbreak@*/ break;
3158 case RPM_STRING_TYPE:
3159 case RPM_I18NSTRING_TYPE:
3160 rpmcnt = 1; /* XXX break out of loop. */
3162 case RPM_STRING_ARRAY_TYPE:
3163 /* Convert from hex to binary. */
3165 if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
3170 for (j = 0; j < 16; j++, t++, s += 2)
3171 *t = (nibble(s[0]) << 4) | nibble(s[1]);
3174 /*@switchbreak@*/ break;
3176 /* Extract the pubkey id from the base64 blob. */
3177 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
3178 pgpDig dig = pgpNewDig();
3182 if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
3183 /*@innercontinue@*/ continue;
3184 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
3185 memcpy(bin, dig->pubkey.signid, 8);
3190 /*@switchbreak@*/ break;
3195 /*@i@*/ key->data = (void *) rpmvals[i];
3196 key->size = strlen(rpmvals[i]);
3198 /*@switchbreak@*/ break;
3203 if (rpmcnt == 1 && stringvalued) {
3204 rpmMessage(RPMMESS_DEBUG,
3205 _("adding \"%s\" to %s index.\n"),
3206 (char *)key->data, tagName(dbi->dbi_rpmtag));
3208 rpmMessage(RPMMESS_DEBUG,
3209 _("adding %d entries to %s index.\n"),
3210 rpmcnt, tagName(dbi->dbi_rpmtag));
3215 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */
3219 if (key->size == 0) key->size = strlen((char *)key->data);
3220 if (key->size == 0) key->size++; /* XXX "/" fixup. */
3223 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
3224 if (rc == 0) { /* success */
3225 /* With duplicates, cursor is positioned, discard the record. */
3226 if (!dbi->dbi_permit_dups)
3227 (void) dbt2set(dbi, data, &set);
3228 } else if (rc != DB_NOTFOUND) { /* error */
3229 rpmError(RPMERR_DBGETINDEX,
3230 _("error(%d) getting \"%s\" records from %s index\n"),
3231 rc, key->data, tagName(dbi->dbi_rpmtag));
3233 /*@innercontinue@*/ continue;
3237 if (set == NULL) /* not found or duplicate */
3238 set = xcalloc(1, sizeof(*set));
3240 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
3243 (void) set2dbt(dbi, data, set);
3244 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
3248 rpmError(RPMERR_DBPUTINDEX,
3249 _("error(%d) storing record %s into %s\n"),
3250 rc, key->data, tagName(dbi->dbi_rpmtag));
3253 /*@-unqualifiedtrans@*/
3254 data->data = _free(data->data);
3255 /*@=unqualifiedtrans@*/
3257 set = dbiFreeIndexSet(set);
3260 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3263 if (!dbi->dbi_no_dbsync)
3264 xx = dbiSync(dbi, 0);
3267 /*@-observertrans@*/
3268 if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */
3269 rpmvals = hfd(rpmvals, rpmtype);
3270 /*@=observertrans@*/
3274 /*@=nullpass =nullptrarith =nullderef @*/
3280 (void) unblockSignals(db, &signalMask);
3285 /* XXX transaction.c */
3287 int rpmdbFindFpList(rpmdb db, fingerPrint * fpList, dbiIndexSet * matchList,
3292 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
3293 HFD_t hfd = headerFreeData;
3294 rpmdbMatchIterator mi;
3295 fingerPrintCache fpc;
3299 if (db == NULL) return 0;
3301 mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, NULL, 0);
3302 if (mi == NULL) /* XXX should never happen */
3306 data = &mi->mi_data;
3308 /* Gather all installed headers with matching basename's. */
3309 for (i = 0; i < numItems; i++) {
3311 /*@-boundsread -dependenttrans@*/
3312 key->data = (void *) fpList[i].baseName;
3313 /*@=boundsread =dependenttrans@*/
3314 key->size = strlen((char *)key->data);
3315 if (key->size == 0) key->size++; /* XXX "/" fixup. */
3317 xx = rpmdbGrowIterator(mi, i);
3319 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
3324 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
3325 mi = rpmdbFreeIterator(mi);
3328 fpc = fpCacheCreate(i);
3330 rpmdbSortIterator(mi);
3331 /* iterator is now sorted by (recnum, filenum) */
3333 /* For all installed headers with matching basename's ... */
3335 while ((h = rpmdbNextIterator(mi)) != NULL) {
3336 const char ** dirNames;
3337 const char ** baseNames;
3338 const char ** fullBaseNames;
3339 rpmTagType bnt, dnt;
3340 int_32 * dirIndexes;
3341 int_32 * fullDirIndexes;
3348 start = mi->mi_setx - 1;
3349 im = mi->mi_set->recs + start;
3351 /* Find the end of the set of matched basename's in this package. */
3353 for (end = start + 1; end < mi->mi_set->count; end++) {
3354 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
3355 /*@innerbreak@*/ break;
3360 /* Compute fingerprints for this installed header's matches */
3361 xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &fullBaseNames, NULL);
3362 xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
3363 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fullDirIndexes, NULL);
3365 baseNames = xcalloc(num, sizeof(*baseNames));
3366 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
3368 for (i = 0; i < num; i++) {
3369 baseNames[i] = fullBaseNames[im[i].tagNum];
3370 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
3374 fps = xcalloc(num, sizeof(*fps));
3375 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
3377 /* Add db (recnum,filenum) to list for fingerprint matches. */
3379 for (i = 0; i < num; i++, im++) {
3380 /*@-nullpass@*/ /* FIX: fpList[].subDir may be NULL */
3381 if (!FP_EQUAL(fps[i], fpList[im->fpNum]))
3382 /*@innercontinue@*/ continue;
3384 xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
3389 dirNames = hfd(dirNames, dnt);
3390 fullBaseNames = hfd(fullBaseNames, bnt);
3391 baseNames = _free(baseNames);
3392 dirIndexes = _free(dirIndexes);
3397 mi = rpmdbFreeIterator(mi);
3399 fpc = fpCacheFree(fpc);
3407 * Check if file esists using stat(2).
3408 * @param urlfn file name (may be URL)
3409 * @return 1 if file exists, 0 if not
3411 static int rpmioFileExists(const char * urlfn)
3412 /*@globals fileSystem, internalState @*/
3413 /*@modifies fileSystem, internalState @*/
3416 int urltype = urlPath(urlfn, &fn);
3420 if (*fn == '\0') fn = "/";
3423 case URL_IS_FTP: /* XXX WRONG WRONG WRONG */
3424 case URL_IS_HTTP: /* XXX WRONG WRONG WRONG */
3426 case URL_IS_UNKNOWN:
3427 if (Stat(fn, &buf)) {
3438 /*@notreached@*/ break;
3444 static int rpmdbRemoveDatabase(const char * prefix,
3445 const char * dbpath, int _dbapi)
3446 /*@globals fileSystem, internalState @*/
3447 /*@modifies fileSystem, internalState @*/
3454 /*@-bounds -branchstate@*/
3455 if (dbpath[i - 1] != '/') {
3456 filename = alloca(i);
3457 strcpy(filename, dbpath);
3459 filename[i + 1] = '\0';
3462 /*@=bounds =branchstate@*/
3464 filename = alloca(strlen(prefix) + strlen(dbpath) + 40);
3468 if (dbiTags != NULL)
3469 for (i = 0; i < dbiTagsMax; i++) {
3471 const char * base = tagName(dbiTags[i]);
3473 sprintf(filename, "%s/%s/%s", prefix, dbpath, base);
3474 (void)rpmCleanPath(filename);
3475 if (!rpmioFileExists(filename))
3477 xx = unlink(filename);
3479 for (i = 0; i < 16; i++) {
3480 sprintf(filename, "%s/%s/__db.%03d", prefix, dbpath, i);
3481 (void)rpmCleanPath(filename);
3482 if (!rpmioFileExists(filename))
3484 xx = unlink(filename);
3493 sprintf(filename, "%s/%s", prefix, dbpath);
3494 (void)rpmCleanPath(filename);
3495 xx = rmdir(filename);
3500 static int rpmdbMoveDatabase(const char * prefix,
3501 const char * olddbpath, int _olddbapi,
3502 const char * newdbpath, int _newdbapi)
3503 /*@globals fileSystem, internalState @*/
3504 /*@modifies fileSystem, internalState @*/
3507 char * ofilename, * nfilename;
3508 struct stat * nst = alloca(sizeof(*nst));
3512 i = strlen(olddbpath);
3514 if (olddbpath[i - 1] != '/') {
3515 ofilename = alloca(i + 2);
3516 strcpy(ofilename, olddbpath);
3518 ofilename[i + 1] = '\0';
3519 olddbpath = ofilename;
3523 i = strlen(newdbpath);
3525 if (newdbpath[i - 1] != '/') {
3526 nfilename = alloca(i + 2);
3527 strcpy(nfilename, newdbpath);
3529 nfilename[i + 1] = '\0';
3530 newdbpath = nfilename;
3534 ofilename = alloca(strlen(prefix) + strlen(olddbpath) + 40);
3535 nfilename = alloca(strlen(prefix) + strlen(newdbpath) + 40);
3537 switch (_olddbapi) {
3539 if (dbiTags != NULL)
3540 for (i = 0; i < dbiTagsMax; i++) {
3544 /* Filter out temporary databases */
3545 switch ((rpmtag = dbiTags[i])) {
3546 case RPMDBI_AVAILABLE:
3548 case RPMDBI_REMOVED:
3549 case RPMDBI_DEPENDS:
3551 /*@notreached@*/ /*@switchbreak@*/ break;
3553 /*@switchbreak@*/ break;
3556 base = tagName(rpmtag);
3557 sprintf(ofilename, "%s/%s/%s", prefix, olddbpath, base);
3558 (void)rpmCleanPath(ofilename);
3559 if (!rpmioFileExists(ofilename))
3561 sprintf(nfilename, "%s/%s/%s", prefix, newdbpath, base);
3562 (void)rpmCleanPath(nfilename);
3563 if (Stat(nfilename, nst))
3565 if ((xx = Rename(ofilename, nfilename)) != 0) {
3569 xx = chown(nfilename, nst->st_uid, nst->st_gid);
3570 xx = chmod(nfilename, (nst->st_mode & 07777));
3571 { struct utimbuf stamp;
3572 stamp.actime = nst->st_atime;
3573 stamp.modtime = nst->st_mtime;
3574 xx = utime(nfilename, &stamp);
3577 for (i = 0; i < 16; i++) {
3578 sprintf(ofilename, "%s/%s/__db.%03d", prefix, olddbpath, i);
3579 (void)rpmCleanPath(ofilename);
3580 if (!rpmioFileExists(ofilename))
3582 xx = unlink(ofilename);
3583 sprintf(nfilename, "%s/%s/__db.%03d", prefix, newdbpath, i);
3584 (void)rpmCleanPath(nfilename);
3586 if ((xx = Rename(ofilename, nfilename)) != 0)
3589 xx = unlink(nfilename);
3598 if (rc || _olddbapi == _newdbapi)
3601 rc = rpmdbRemoveDatabase(prefix, newdbpath, _newdbapi);
3604 /* Remove /etc/rpm/macros.db1 configuration file if db3 rebuilt. */
3605 if (rc == 0 && _newdbapi == 1 && _olddbapi == 3) {
3606 const char * mdb1 = "/etc/rpm/macros.db1";
3608 if (!stat(mdb1, &st) && S_ISREG(st.st_mode) && !unlink(mdb1))
3609 rpmMessage(RPMMESS_DEBUG,
3610 _("removing %s after successful db3 rebuild.\n"), mdb1);
3615 int rpmdbRebuild(const char * prefix, rpmts ts,
3616 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
3617 /*@globals _rebuildinprogress @*/
3618 /*@modifies _rebuildinprogress @*/
3621 const char * dbpath = NULL;
3622 const char * rootdbpath = NULL;
3624 const char * newdbpath = NULL;
3625 const char * newrootdbpath = NULL;
3635 if (prefix == NULL) prefix = "/";
3638 _dbapi = rpmExpandNumeric("%{_dbapi}");
3639 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
3642 tfn = rpmGetPath("%{?_dbpath}", NULL);
3645 if (!(tfn && tfn[0] != '\0'))
3648 rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
3652 dbpath = rootdbpath = rpmGetPath(prefix, tfn, NULL);
3653 if (!(prefix[0] == '/' && prefix[1] == '\0'))
3654 dbpath += strlen(prefix);
3658 tfn = rpmGetPath("%{?_dbpath_rebuild}", NULL);
3661 if (!(tfn && tfn[0] != '\0' && strcmp(tfn, dbpath)))
3666 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
3667 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
3669 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
3675 newdbpath = newrootdbpath = rpmGetPath(prefix, tfn, NULL);
3676 if (!(prefix[0] == '/' && prefix[1] == '\0'))
3677 newdbpath += strlen(prefix);
3680 rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
3681 rootdbpath, newrootdbpath);
3683 if (!access(newrootdbpath, F_OK)) {
3684 rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
3690 rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
3691 if (Mkdir(newrootdbpath, 0755)) {
3692 rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
3693 newrootdbpath, strerror(errno));
3699 rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
3701 _rebuildinprogress = 1;
3703 if (openDatabase(prefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
3704 RPMDB_FLAG_MINIMAL)) {
3709 _dbapi = olddb->db_api;
3710 _rebuildinprogress = 0;
3712 rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
3714 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
3716 if (openDatabase(prefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
3721 _dbapi_rebuild = newdb->db_api;
3724 rpmdbMatchIterator mi;
3725 #define _RECNUM rpmdbGetIteratorOffset(mi)
3727 /* RPMDBI_PACKAGES */
3728 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
3730 (void) rpmdbSetHdrChk(mi, ts, hdrchk);
3732 while ((h = rpmdbNextIterator(mi)) != NULL) {
3734 /* let's sanity check this record a bit, otherwise just skip it */
3735 if (!(headerIsEntry(h, RPMTAG_NAME) &&
3736 headerIsEntry(h, RPMTAG_VERSION) &&
3737 headerIsEntry(h, RPMTAG_RELEASE) &&
3738 headerIsEntry(h, RPMTAG_BUILDTIME)))
3740 rpmError(RPMERR_INTERNAL,
3741 _("header #%u in the database is bad -- skipping.\n"),
3746 /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
3747 if (_db_filter_dups || newdb->db_filter_dups) {
3748 const char * name, * version, * release;
3751 (void) headerNVR(h, &name, &version, &release);
3754 { rpmdbMatchIterator mi;
3755 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
3756 (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
3757 RPMMIRE_DEFAULT, version);
3758 (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
3759 RPMMIRE_DEFAULT, release);
3760 while (rpmdbNextIterator(mi)) {
3762 /*@innerbreak@*/ break;
3764 mi = rpmdbFreeIterator(mi);
3772 /* Deleted entries are eliminated in legacy headers by copy. */
3773 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
3774 ? headerCopy(h) : NULL);
3775 rc = rpmdbAdd(newdb, -1, (nh ? nh : h), ts, hdrchk);
3776 nh = headerFree(nh);
3780 rpmError(RPMERR_INTERNAL,
3781 _("cannot add record originally at %u\n"), _RECNUM);
3787 mi = rpmdbFreeIterator(mi);
3792 olddb->db_remove_env = 1;
3793 newdb->db_remove_env = 1;
3795 xx = rpmdbClose(olddb);
3796 xx = rpmdbClose(newdb);
3799 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
3800 "remains in place\n"));
3802 xx = rpmdbRemoveDatabase(prefix, newdbpath, _dbapi_rebuild);
3805 } else if (!nocleanup) {
3806 if (rpmdbMoveDatabase(prefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
3807 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
3809 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
3810 "to recover"), dbpath, newdbpath);
3818 if (removedir && !(rc == 0 && nocleanup)) {
3819 rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
3820 if (Rmdir(newrootdbpath))
3821 rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
3822 newrootdbpath, strerror(errno));
3824 newrootdbpath = _free(newrootdbpath);
3825 rootdbpath = _free(rootdbpath);