7 #define _USE_COPY_LOAD /* XXX don't use DB_DBT_MALLOC (yet) */
11 #ifndef DYING /* XXX already in "system.h" */
17 #include <rpm/rpmtypes.h>
18 #include <rpm/rpmurl.h>
19 #include <rpm/rpmpgp.h>
20 #include <rpm/rpmpgp.h>
21 #include <rpm/rpmmacro.h>
22 #include <rpm/rpmsq.h>
23 #include <rpm/rpmstring.h>
24 #include <rpm/rpmfileutil.h>
25 #include <rpm/rpmds.h> /* XXX isInstallPreReq macro only */
26 #include <rpm/rpmlog.h>
27 #include <rpm/rpmdb.h>
30 #include "lib/rpmdb_internal.h"
31 #include "lib/fprint.h"
32 #include "lib/header_internal.h" /* XXX for HEADERFLAG_ALLOCATED */
37 static int _rebuildinprogress = 0;
38 static int _db_filter_dups = 0;
41 #define _DBI_PERMS 0644
50 /* XXX should dbitags be per-db instead? */
51 static struct dbiTags_s dbiTags = { NULL, 0, 0 };
53 /* Bit mask macros. */
54 typedef unsigned int __pbm_bits;
55 #define __PBM_NBITS (8 * sizeof (__pbm_bits))
56 #define __PBM_IX(d) ((d) / __PBM_NBITS)
57 #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
61 #define __PBM_BITS(set) ((set)->bits)
63 #define PBM_FREE(s) _free(s);
64 #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
65 #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
66 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
68 #define PBM_ALLOC(d) xcalloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
71 * Reallocate a bit map.
72 * @retval sp address of bit map pointer
73 * @retval odp no. of bits in map
74 * @param nd desired no. of bits
76 static inline pbm_set * PBM_REALLOC(pbm_set ** sp, int * odp, int nd)
82 nb = __PBM_IX(nd) + 1;
83 *sp = xrealloc(*sp, nb * sizeof(__pbm_bits));
84 for (i = __PBM_IX(*odp) + 1; i < nb; i++)
85 __PBM_BITS(*sp)[i] = 0;
92 * Return dbi index used for rpm tag.
93 * @param rpmtag rpm header tag
94 * @return dbi index, -1 on error
96 static int dbiTagToDbix(rpmTag rpmtag)
100 if (dbiTags.tags != NULL)
101 for (dbix = 0; dbix < dbiTags.max; dbix++) {
102 if (rpmtag == dbiTags.tags[dbix])
109 * Initialize database (index, tag) tuple from configuration.
111 static void dbiTagsInit(void)
113 static const char * const _dbiTagStr_default =
114 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filemd5s:Depends:Pubkeys";
115 char * dbiTagStr = NULL;
120 if (dbiTags.tags != NULL && dbiTags.max > 0) {
124 dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL);
125 if (!(dbiTagStr && *dbiTagStr)) {
126 dbiTagStr = _free(dbiTagStr);
127 dbiTagStr = xstrdup(_dbiTagStr_default);
130 /* Discard previous values. */
131 dbiTags.tags = _free(dbiTags.tags);
134 /* Always allocate package index */
135 dbiTags.tags = xcalloc(1, sizeof(*dbiTags.tags));
136 dbiTags.tags[dbiTags.max++] = RPMDBI_PACKAGES;
138 for (o = dbiTagStr; o && *o; o = oe) {
139 while (*o && risspace(*o))
143 for (oe = o; oe && *oe; oe++) {
146 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
151 rpmtag = rpmTagGetValue(o);
152 if (rpmtag == RPMTAG_NOT_FOUND) {
153 rpmlog(RPMLOG_WARNING,
154 _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
157 if (dbiTagToDbix(rpmtag) >= 0)
160 dbiTags.tags = xrealloc(dbiTags.tags, (dbiTags.max + 1) * sizeof(*dbiTags.tags)); /* XXX memory leak */
161 dbiTags.tags[dbiTags.max++] = rpmtag;
164 dbiTagStr = _free(dbiTagStr);
167 static void dbiTagsFree(void)
169 if (--dbiTags.nlink > 0) {
172 dbiTags.tags = _free(dbiTags.tags);
180 extern struct _dbiVec db3vec;
181 #define DB3vec &db3vec
186 #ifdef HAVE_SQLITE3_H
187 extern struct _dbiVec sqlitevec;
188 #define SQLITEvec &sqlitevec
190 #define SQLITEvec NULL
193 static struct _dbiVec * const mydbvecs[] = {
194 DB1vec, DB1vec, DB2vec, DB3vec, SQLITEvec, NULL
197 dbiIndex dbiOpen(rpmdb db, rpmTag rpmtag, unsigned int flags)
201 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
207 dbix = dbiTagToDbix(rpmtag);
208 if (dbix < 0 || dbix >= dbiTags.max)
211 /* Is this index already open ? */
212 /* FIX: db->_dbi may be NULL */
213 if ((dbi = db->_dbi[dbix]) != NULL)
216 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
217 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 4)
219 /* _dbapi_wanted = (_rebuildinprogress ? -1 : db->db_api); */
220 _dbapi_wanted = (_rebuildinprogress ? _dbapi_rebuild : db->db_api);
222 switch (_dbapi_wanted) {
224 _dbapi = _dbapi_wanted;
225 if (_dbapi < 0 || _dbapi >= 5 || mydbvecs[_dbapi] == NULL) {
226 rpmlog(RPMLOG_ERR, _("dbiOpen: dbapi %d not available\n"), _dbapi);
231 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
233 static int _printed[32];
234 if (!_printed[dbix & 0x1f]++)
236 _("cannot open %s index using db%d - %s (%d)\n"),
237 rpmTagGetName(rpmtag), _dbapi,
238 (rc > 0 ? strerror(rc) : ""), rc);
244 while (_dbapi-- > 1) {
245 if (mydbvecs[_dbapi] == NULL)
249 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
254 static int _printed[32];
255 if (!_printed[dbix & 0x1f]++)
256 rpmlog(RPMLOG_ERR, _("cannot open %s index\n"),
257 rpmTagGetName(rpmtag));
261 if (db->db_api == -1 && _dbapi > 0)
266 /* We don't ever _REQUIRE_ conversion... */
268 #ifdef SQLITE_HACK_XXX
269 /* Require conversion. */
270 if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
271 rc = (_rebuildinprogress ? 0 : 1);
275 /* Suggest possible configuration */
276 if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
281 /* Suggest possible configuration */
282 if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
283 rc = (_rebuildinprogress ? 0 : 1);
289 if (dbi != NULL && rc == 0) {
290 db->_dbi[dbix] = dbi;
291 if (rpmtag == RPMDBI_PACKAGES && db->db_bits == NULL) {
293 if (!dbiStat(dbi, DB_FAST_STAT)) {
294 DB_HASH_STAT * hash = (DB_HASH_STAT *)dbi->dbi_stats;
296 db->db_nbits += hash->hash_nkeys;
298 db->db_bits = PBM_ALLOC(db->db_nbits);
306 /* FIX: db->_dbi may be NULL */
311 * Create and initialize item for index database set.
312 * @param hdrNum header instance in db
313 * @param tagNum tag index in header
316 static dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
318 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
319 rec->hdrNum = hdrNum;
320 rec->tagNum = tagNum;
329 #define _DBSWAP(_a) \
331 { unsigned char _b, *_c = (_a).uc; \
332 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
333 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
338 * Convert retrieved data to index set.
339 * @param dbi index database handle
340 * @param data retrieved data
341 * @retval setp (malloc'ed) index set
342 * @return 0 on success
344 static int dbt2set(dbiIndex dbi, DBT * data, dbiIndexSet * setp)
346 int _dbbyteswapped = dbiByteSwapped(dbi);
351 if (dbi == NULL || data == NULL || setp == NULL)
354 if ((sdbir = data->data) == NULL) {
359 set = xmalloc(sizeof(*set));
360 set->count = data->size / dbi->dbi_jlen;
361 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
363 switch (dbi->dbi_jlen) {
365 case 2*sizeof(int32_t):
366 for (i = 0; i < set->count; i++) {
367 union _dbswap hdrNum, tagNum;
369 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
370 sdbir += sizeof(hdrNum.ui);
371 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
372 sdbir += sizeof(tagNum.ui);
373 if (_dbbyteswapped) {
377 set->recs[i].hdrNum = hdrNum.ui;
378 set->recs[i].tagNum = tagNum.ui;
379 set->recs[i].fpNum = 0;
382 case 1*sizeof(int32_t):
383 for (i = 0; i < set->count; i++) {
384 union _dbswap hdrNum;
386 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
387 sdbir += sizeof(hdrNum.ui);
388 if (_dbbyteswapped) {
391 set->recs[i].hdrNum = hdrNum.ui;
392 set->recs[i].tagNum = 0;
393 set->recs[i].fpNum = 0;
402 * Convert index set to database representation.
403 * @param dbi index database handle
404 * @param data retrieved data
405 * @param set index set
406 * @return 0 on success
408 static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
410 int _dbbyteswapped = dbiByteSwapped(dbi);
414 if (dbi == NULL || data == NULL || set == NULL)
417 data->size = set->count * (dbi->dbi_jlen);
418 if (data->size == 0) {
422 tdbir = data->data = xmalloc(data->size);
424 switch (dbi->dbi_jlen) {
426 case 2*sizeof(int32_t):
427 for (i = 0; i < set->count; i++) {
428 union _dbswap hdrNum, tagNum;
430 memset(&hdrNum, 0, sizeof(hdrNum));
431 memset(&tagNum, 0, sizeof(tagNum));
432 hdrNum.ui = set->recs[i].hdrNum;
433 tagNum.ui = set->recs[i].tagNum;
434 if (_dbbyteswapped) {
438 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
439 tdbir += sizeof(hdrNum.ui);
440 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
441 tdbir += sizeof(tagNum.ui);
444 case 1*sizeof(int32_t):
445 for (i = 0; i < set->count; i++) {
446 union _dbswap hdrNum;
448 memset(&hdrNum, 0, sizeof(hdrNum));
449 hdrNum.ui = set->recs[i].hdrNum;
450 if (_dbbyteswapped) {
453 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
454 tdbir += sizeof(hdrNum.ui);
462 /* XXX assumes hdrNum is first int in dbiIndexItem */
463 static int hdrNumCmp(const void * one, const void * two)
465 const int * a = one, * b = two;
470 * Append element(s) to set of index database items.
471 * @param set set of index database items
472 * @param recs array of items to append to set
473 * @param nrecs number of items
474 * @param recsize size of an array item
475 * @param sortset should resulting set be sorted?
476 * @return 0 success, 1 failure (bad args)
478 static int dbiAppendSet(dbiIndexSet set, const void * recs,
479 int nrecs, size_t recsize, int sortset)
481 const char * rptr = recs;
482 size_t rlen = (recsize < sizeof(*(set->recs)))
483 ? recsize : sizeof(*(set->recs));
485 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
488 set->recs = xrealloc(set->recs,
489 (set->count + nrecs) * sizeof(*(set->recs)));
491 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
493 while (nrecs-- > 0) {
494 memcpy(set->recs + set->count, rptr, rlen);
499 if (sortset && set->count > 1)
500 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
506 * Remove element(s) from set of index database items.
507 * @param set set of index database items
508 * @param recs array of items to remove from set
509 * @param nrecs number of items
510 * @param recsize size of an array item
511 * @param sorted array is already sorted?
512 * @return 0 success, 1 failure (no items found)
514 static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
515 size_t recsize, int sorted)
519 int num = set->count;
522 assert(set->count > 0);
523 if (nrecs > 1 && !sorted)
524 qsort(recs, nrecs, recsize, hdrNumCmp);
526 for (from = 0; from < num; from++) {
527 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
532 set->recs[to] = set->recs[from]; /* structure assignment */
536 return (numCopied == num);
539 /* XXX transaction.c */
540 unsigned int dbiIndexSetCount(dbiIndexSet set) {
544 /* XXX transaction.c */
545 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
546 return set->recs[recno].hdrNum;
549 /* XXX transaction.c */
550 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
551 return set->recs[recno].tagNum;
554 /* XXX transaction.c */
555 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) {
557 set->recs = _free(set->recs);
563 typedef struct miRE_s {
564 rpmTag tag; /*!< header tag */
565 rpmMireMode mode; /*!< pattern match mode */
566 char * pattern; /*!< pattern string */
567 int notmatch; /*!< like "grep -v" */
568 regex_t * preg; /*!< regex compiled pattern buffer */
569 int cflags; /*!< regcomp(3) flags */
570 int eflags; /*!< regexec(3) flags */
571 int fnflags; /*!< fnmatch(3) flags */
574 struct rpmdbMatchIterator_s {
575 rpmdbMatchIterator mi_next;
589 unsigned int mi_prevoffset; /* header instance (native endian) */
590 unsigned int mi_offset; /* header instance (native endian) */
591 unsigned int mi_filenum; /* tag element (native endian) */
595 rpmRC (*mi_hdrchk) (rpmts ts, const void * uh, size_t uc, char ** msg);
599 static rpmdb rpmdbRock;
601 static rpmdbMatchIterator rpmmiRock;
603 int rpmdbCheckTerminate(int terminate)
605 sigset_t newMask, oldMask;
606 static int terminating = 0;
608 if (terminating) return 0;
610 (void) sigfillset(&newMask); /* block all signals */
611 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
613 if (sigismember(&rpmsqCaught, SIGINT)
614 || sigismember(&rpmsqCaught, SIGQUIT)
615 || sigismember(&rpmsqCaught, SIGHUP)
616 || sigismember(&rpmsqCaught, SIGTERM)
617 || sigismember(&rpmsqCaught, SIGPIPE)
623 rpmdbMatchIterator mi;
625 while ((mi = rpmmiRock) != NULL) {
626 rpmmiRock = mi->mi_next;
628 mi = rpmdbFreeIterator(mi);
631 while ((db = rpmdbRock) != NULL) {
632 rpmdbRock = db->db_next;
634 (void) rpmdbClose(db);
637 sigprocmask(SIG_SETMASK, &oldMask, NULL);
641 int rpmdbCheckSignals(void)
643 if (rpmdbCheckTerminate(0)) {
644 /* sigset_t is abstract type */
645 rpmlog(RPMLOG_DEBUG, "Exiting on signal(0x%lx) ...\n",
646 *((unsigned long *)&rpmsqCaught));
653 * Block all signals, returning previous signal mask.
655 static int blockSignals(sigset_t * oldMask)
659 (void) sigfillset(&newMask); /* block all signals */
660 (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
661 (void) sigdelset(&newMask, SIGINT);
662 (void) sigdelset(&newMask, SIGQUIT);
663 (void) sigdelset(&newMask, SIGHUP);
664 (void) sigdelset(&newMask, SIGTERM);
665 (void) sigdelset(&newMask, SIGPIPE);
666 return sigprocmask(SIG_BLOCK, &newMask, NULL);
670 * Restore signal mask.
672 static int unblockSignals(sigset_t * oldMask)
674 (void) rpmdbCheckSignals();
675 return sigprocmask(SIG_SETMASK, oldMask, NULL);
679 #define _DB_HOME "%{_dbpath}"
682 #define _DB_PERMS 0644
685 #define _DB_ERRPFX "rpmdb"
687 static struct rpmdb_s const dbTemplate = {
688 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
689 _DB_MAJOR, _DB_ERRPFX
692 static int isTemporaryDB(rpmTag rpmtag)
696 case RPMDBI_AVAILABLE:
708 rpmop rpmdbOp(rpmdb rpmdb, rpmdbOpX opx)
713 op = &rpmdb->db_getops;
716 op = &rpmdb->db_putops;
719 op = &rpmdb->db_delops;
727 int rpmdbSetChrootDone(rpmdb db, int chrootDone)
731 ochrootDone = db->db_chrootDone;
732 db->db_chrootDone = chrootDone;
737 int rpmdbOpenAll(rpmdb db)
742 if (db == NULL) return -2;
744 if (dbiTags.tags != NULL)
745 for (dbix = 0; dbix < dbiTags.max; dbix++) {
746 if (db->_dbi[dbix] != NULL)
748 /* Filter out temporary databases */
749 if (isTemporaryDB(dbiTags.tags[dbix]))
751 (void) dbiOpen(db, dbiTags.tags[dbix], db->db_flags);
756 int rpmdbCloseDBI(rpmdb db, rpmTag rpmtag)
761 if (db == NULL || db->_dbi == NULL || dbiTags.tags == NULL)
764 for (dbix = 0; dbix < dbiTags.max; dbix++) {
765 if (dbiTags.tags[dbix] != rpmtag)
767 if (db->_dbi[dbix] != NULL) {
769 /* FIX: double indirection. */
770 xx = dbiClose(db->_dbi[dbix], 0);
771 if (xx && rc == 0) rc = xx;
772 db->_dbi[dbix] = NULL;
779 /* XXX query.c, rpminstall.c, verify.c */
780 int rpmdbClose(rpmdb db)
789 (void) rpmdbUnlink(db, RPMDBG_M("rpmdbClose"));
795 for (dbix = db->db_ndbi; --dbix >= 0; ) {
797 if (db->_dbi[dbix] == NULL)
799 xx = dbiClose(db->_dbi[dbix], 0);
800 if (xx && rc == 0) rc = xx;
801 db->_dbi[dbix] = NULL;
803 db->db_errpfx = _free(db->db_errpfx);
804 db->db_root = _free(db->db_root);
805 db->db_home = _free(db->db_home);
806 db->db_bits = PBM_FREE(db->db_bits);
807 db->_dbi = _free(db->_dbi);
810 while ((next = *prev) != NULL && next != db)
811 prev = &next->db_next;
813 *prev = next->db_next;
814 next->db_next = NULL;
822 (void) rpmsqEnable(-SIGHUP, NULL);
823 (void) rpmsqEnable(-SIGINT, NULL);
824 (void) rpmsqEnable(-SIGTERM,NULL);
825 (void) rpmsqEnable(-SIGQUIT,NULL);
826 (void) rpmsqEnable(-SIGPIPE,NULL);
830 int rpmdbSync(rpmdb db)
835 if (db == NULL) return 0;
836 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
838 if (db->_dbi[dbix] == NULL)
840 if (db->_dbi[dbix]->dbi_no_dbsync)
842 xx = dbiSync(db->_dbi[dbix], 0);
843 if (xx && rc == 0) rc = xx;
848 /* FIX: dbTemplate structure assignment */
850 rpmdb newRpmdb(const char * root,
852 int mode, int perms, int flags)
854 rpmdb db = xcalloc(sizeof(*db), 1);
855 const char * epfx = _DB_ERRPFX;
856 static int _initialized = 0;
859 _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}");
863 *db = dbTemplate; /* structure assignment */
867 if (!(perms & 0600)) perms = 0644; /* XXX sanity */
869 if (mode >= 0) db->db_mode = mode;
870 if (perms >= 0) db->db_perms = perms;
871 if (flags >= 0) db->db_flags = flags;
874 db->db_root = rpmGetPath(root, NULL);
876 db->db_root = rpmGetPath(_DB_ROOT, NULL);
878 db->db_home = rpmGetPath( (home && *home ? home : _DB_HOME), NULL);
879 if (!(db->db_home && db->db_home[0] != '%')) {
880 rpmlog(RPMLOG_ERR, _("no dbpath has been set\n"));
881 db->db_root = _free(db->db_root);
882 db->db_home = _free(db->db_home);
886 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
887 db->db_remove_env = 0;
888 db->db_filter_dups = _db_filter_dups;
889 db->db_ndbi = dbiTags.max;
890 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
892 return rpmdbLink(db, RPMDBG_M("rpmdbCreate"));
895 static int openDatabase(const char * prefix,
897 int _dbapi, rpmdb *dbp,
898 int mode, int perms, int flags)
902 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
903 int minimal = flags & RPMDB_FLAG_MINIMAL;
907 /* Insure that _dbapi has one of -1, 1, 2, or 3 */
908 if (_dbapi < -1 || _dbapi > 4)
918 db = newRpmdb(prefix, dbpath, mode, perms, flags);
922 (void) rpmsqEnable(SIGHUP, NULL);
923 (void) rpmsqEnable(SIGINT, NULL);
924 (void) rpmsqEnable(SIGTERM,NULL);
925 (void) rpmsqEnable(SIGQUIT,NULL);
926 (void) rpmsqEnable(SIGPIPE,NULL);
933 if (dbiTags.tags != NULL)
934 for (dbix = 0; rc == 0 && dbix < dbiTags.max; dbix++) {
938 /* Filter out temporary databases */
939 if (isTemporaryDB((rpmtag = dbiTags.tags[dbix])))
942 dbi = dbiOpen(db, rpmtag, 0);
949 case RPMDBI_PACKAGES:
950 if (dbi == NULL) rc |= 1;
952 /* XXX open only Packages, indices created on the fly. */
958 if (dbi == NULL) rc |= 1;
969 if (rc || justCheck || dbp == NULL)
972 db->db_next = rpmdbRock;
980 rpmdb rpmdbUnlink(rpmdb db, const char * msg)
983 fprintf(stderr, "--> db %p -- %d %s\n", db, db->nrefs, msg);
988 rpmdb rpmdbLink(rpmdb db, const char * msg)
992 fprintf(stderr, "--> db %p ++ %d %s\n", db, db->nrefs, msg);
996 /* XXX python/rpmmodule.c */
997 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
999 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1000 return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
1003 int rpmdbInit (const char * prefix, int perms)
1006 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1009 rc = openDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
1010 perms, RPMDB_FLAG_JUSTCHECK);
1013 xx = rpmdbOpenAll(db);
1014 if (xx && rc == 0) rc = xx;
1015 xx = rpmdbClose(db);
1016 if (xx && rc == 0) rc = xx;
1022 int rpmdbVerify(const char * prefix)
1025 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1028 rc = openDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
1033 rc = rpmdbOpenAll(db);
1035 for (dbix = db->db_ndbi; --dbix >= 0; ) {
1036 if (db->_dbi[dbix] == NULL)
1038 /* FIX: double indirection. */
1039 xx = dbiVerify(db->_dbi[dbix], 0);
1040 if (xx && rc == 0) rc = xx;
1041 db->_dbi[dbix] = NULL;
1044 /* FIX: db->_dbi[] may be NULL. */
1045 xx = rpmdbClose(db);
1046 if (xx && rc == 0) rc = xx;
1053 * Find file matches in database.
1054 * @param db rpm database
1059 * @return 0 on success, 1 on not found, -2 on error
1061 static int rpmdbFindByFile(rpmdb db, const char * filespec,
1062 DBT * key, DBT * data, dbiIndexSet * matches)
1065 const char * baseName;
1066 fingerPrintCache fpc;
1068 dbiIndex dbi = NULL;
1070 dbiIndexSet allMatches = NULL;
1071 dbiIndexItem rec = NULL;
1077 if (filespec == NULL) return -2;
1079 if ((baseName = strrchr(filespec, '/')) != NULL) {
1080 size_t len = baseName - filespec + 1;
1081 dirName = strncpy(xmalloc(len + 1), filespec, len);
1082 dirName[len] = '\0';
1085 dirName = xstrdup("");
1086 baseName = filespec;
1088 if (baseName == NULL)
1091 fpc = fpCacheCreate(20);
1092 fp1 = fpLookup(fpc, dirName, baseName, 1);
1095 dbi = dbiOpen(db, RPMTAG_BASENAMES, 0);
1098 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1100 key->data = (void *) baseName;
1101 key->size = strlen(baseName);
1103 key->size++; /* XXX "/" fixup. */
1105 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1108 _("error(%d) getting \"%s\" records from %s index\n"),
1109 rc, (char*)key->data, rpmTagGetName(dbi->dbi_rpmtag));
1113 (void) dbt2set(dbi, data, &allMatches);
1115 xx = dbiCclose(dbi, dbcursor, 0);
1121 allMatches = dbiFreeIndexSet(allMatches);
1122 fpc = fpCacheFree(fpc);
1126 *matches = xcalloc(1, sizeof(**matches));
1127 rec = dbiIndexNewItem(0, 0);
1129 if (allMatches != NULL)
1130 while (i < allMatches->count) {
1131 struct rpmtd_s bn, dn, di;
1132 const char ** baseNames, ** dirNames;
1133 uint32_t * dirIndexes;
1134 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
1135 unsigned int prevoff;
1138 { rpmdbMatchIterator mi;
1139 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset));
1140 h = rpmdbNextIterator(mi);
1143 mi = rpmdbFreeIterator(mi);
1151 headerGet(h, RPMTAG_BASENAMES, &bn, HEADERGET_MINMEM);
1152 headerGet(h, RPMTAG_DIRNAMES, &dn, HEADERGET_MINMEM);
1153 headerGet(h, RPMTAG_DIRINDEXES, &di, HEADERGET_MINMEM);
1154 baseNames = bn.data;
1156 dirIndexes = di.data;
1160 int num = dbiIndexRecordFileNumber(allMatches, i);
1162 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
1163 if (FP_EQUAL(fp1, fp2)) {
1164 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
1165 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
1166 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
1171 if (i < allMatches->count)
1172 offset = dbiIndexRecordOffset(allMatches, i);
1173 } while (i < allMatches->count && offset == prevoff);
1182 allMatches = dbiFreeIndexSet(allMatches);
1184 fpc = fpCacheFree(fpc);
1186 if ((*matches)->count == 0) {
1187 *matches = dbiFreeIndexSet(*matches);
1194 /* XXX python/upgrade.c, install.c, uninstall.c */
1195 int rpmdbCountPackages(rpmdb db, const char * name)
1197 DBC * dbcursor = NULL;
1207 memset(&key, 0, sizeof(key));
1208 memset(&data, 0, sizeof(data));
1210 dbi = dbiOpen(db, RPMTAG_NAME, 0);
1214 key.data = (void *) name;
1215 key.size = strlen(name);
1217 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1218 rc = dbiGet(dbi, dbcursor, &key, &data, DB_SET);
1220 xx = dbiCclose(dbi, dbcursor, 0);
1224 if (rc == 0) { /* success */
1225 dbiIndexSet matches;
1226 /* FIX: matches might be NULL */
1228 (void) dbt2set(dbi, &data, &matches);
1230 rc = dbiIndexSetCount(matches);
1231 matches = dbiFreeIndexSet(matches);
1234 if (rc == DB_NOTFOUND) { /* not found */
1236 } else { /* error */
1238 _("error(%d) getting \"%s\" records from %s index\n"),
1239 rc, (char*)key.data, rpmTagGetName(dbi->dbi_rpmtag));
1244 xx = dbiCclose(dbi, dbcursor, 0);
1252 * Attempt partial matches on name[-version[-release]] strings.
1253 * @param dbi index database handle (always RPMTAG_NAME)
1254 * @param dbcursor index database cursor
1255 * @param key search key/length/flags
1256 * @param data search data/length/flags
1257 * @param name package name
1258 * @param version package version (can be a pattern)
1259 * @param release package release (can be a pattern)
1260 * @retval matches set of header instances that match
1261 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
1263 static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
1264 DBT * key, DBT * data,
1266 const char * version,
1267 const char * release,
1268 dbiIndexSet * matches)
1274 key->data = (void *) name;
1275 key->size = strlen(name);
1277 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1279 if (rc == 0) { /* success */
1280 (void) dbt2set(dbi, data, matches);
1281 if (version == NULL && release == NULL)
1284 if (rc == DB_NOTFOUND) { /* not found */
1285 return RPMRC_NOTFOUND;
1286 } else { /* error */
1288 _("error(%d) getting \"%s\" records from %s index\n"),
1289 rc, (char*)key->data, rpmTagGetName(dbi->dbi_rpmtag));
1293 /* Make sure the version and release match. */
1294 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
1295 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
1296 rpmdbMatchIterator mi;
1302 mi = rpmdbInitIterator(dbi->dbi_rpmdb,
1303 RPMDBI_PACKAGES, &recoff, sizeof(recoff));
1305 /* Set iterator selectors for version/release if available. */
1307 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
1313 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
1319 h = rpmdbNextIterator(mi);
1321 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
1323 (*matches)->recs[i].hdrNum = 0;
1324 mi = rpmdbFreeIterator(mi);
1328 (*matches)->count = gotMatches;
1331 rc = RPMRC_NOTFOUND;
1334 /* FIX: double indirection */
1335 if (rc && matches && *matches)
1336 *matches = dbiFreeIndexSet(*matches);
1341 * Lookup by name, name-version, and finally by name-version-release.
1342 * Both version and release can be patterns.
1343 * @todo Name must be an exact match, as name is a db key.
1344 * @param dbi index database handle (always RPMTAG_NAME)
1345 * @param dbcursor index database cursor
1346 * @param key search key/length/flags
1347 * @param data search data/length/flags
1348 * @param arg name[-version[-release]] string
1349 * @retval matches set of header instances that match
1350 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
1352 static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
1353 const char * arg, dbiIndexSet * matches)
1355 const char * release;
1362 if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND;
1364 /* did they give us just a name? */
1365 rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches);
1366 if (rc != RPMRC_NOTFOUND) return rc;
1368 /* FIX: double indirection */
1369 *matches = dbiFreeIndexSet(*matches);
1371 /* maybe a name and a release */
1372 localarg = xmalloc(strlen(arg) + 1);
1373 s = stpcpy(localarg, arg);
1377 for (s -= 1; s > localarg; s--) {
1383 if (c != '[') brackets = 0;
1387 if (!brackets && *s == '-')
1391 /* FIX: *matches may be NULL. */
1392 if (s == localarg) {
1393 rc = RPMRC_NOTFOUND;
1398 rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches);
1399 if (rc != RPMRC_NOTFOUND) goto exit;
1401 /* FIX: double indirection */
1402 *matches = dbiFreeIndexSet(*matches);
1404 /* how about name-version-release? */
1410 for (; s > localarg; s--) {
1416 if (c != '[') brackets = 0;
1420 if (!brackets && *s == '-')
1424 if (s == localarg) {
1425 rc = RPMRC_NOTFOUND;
1430 /* FIX: *matches may be NULL. */
1431 rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches);
1438 * Rewrite a header into packages (if necessary) and free the header.
1439 * Note: this is called from a markReplacedFiles iteration, and *must*
1440 * preserve the "join key" (i.e. offset) for the header.
1441 * @param mi database iterator
1442 * @param dbi index database handle
1443 * @return 0 on success
1445 static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
1449 if (mi == NULL || mi->mi_h == NULL)
1452 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
1453 DBT * key = &mi->mi_key;
1454 DBT * data = &mi->mi_data;
1455 sigset_t signalMask;
1456 rpmRC rpmrc = RPMRC_NOTFOUND;
1459 key->data = (void *) &mi->mi_prevoffset;
1460 key->size = sizeof(mi->mi_prevoffset);
1461 data->data = headerUnload(mi->mi_h);
1462 data->size = headerSizeof(mi->mi_h, HEADER_MAGIC_NO);
1464 /* Check header digest/signature on blob export (if requested). */
1465 if (mi->mi_hdrchk && mi->mi_ts) {
1469 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, data->data, data->size, &msg);
1470 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
1471 rpmlog(lvl, "%s h#%8u %s",
1472 (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping") : "write"),
1473 mi->mi_prevoffset, (msg ? msg : "\n"));
1477 if (data->data != NULL && rpmrc != RPMRC_FAIL) {
1478 (void) blockSignals(&signalMask);
1479 rc = dbiPut(dbi, mi->mi_dbc, key, data, DB_KEYLAST);
1482 _("error(%d) storing record #%d into %s\n"),
1483 rc, mi->mi_prevoffset, rpmTagGetName(dbi->dbi_rpmtag));
1485 xx = dbiSync(dbi, 0);
1486 (void) unblockSignals(&signalMask);
1488 data->data = _free(data->data);
1492 mi->mi_h = headerFree(mi->mi_h);
1497 rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
1499 rpmdbMatchIterator * prev, next;
1508 while ((next = *prev) != NULL && next != mi)
1509 prev = &next->mi_next;
1511 *prev = next->mi_next;
1512 next->mi_next = NULL;
1515 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
1516 if (dbi == NULL) /* XXX can't happen */
1519 xx = miFreeHeader(mi, dbi);
1522 xx = dbiCclose(dbi, mi->mi_dbc, 0);
1525 if (mi->mi_re != NULL)
1526 for (i = 0; i < mi->mi_nre; i++) {
1527 miRE mire = mi->mi_re + i;
1528 mire->pattern = _free(mire->pattern);
1529 if (mire->preg != NULL) {
1530 regfree(mire->preg);
1531 /* LCL: regfree has bogus only */
1532 mire->preg = _free(mire->preg);
1535 mi->mi_re = _free(mi->mi_re);
1537 mi->mi_set = dbiFreeIndexSet(mi->mi_set);
1538 mi->mi_keyp = _free(mi->mi_keyp);
1539 mi->mi_db = rpmdbUnlink(mi->mi_db, RPMDBG_M("matchIterator"));
1543 (void) rpmdbCheckSignals();
1548 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
1549 return (mi ? mi->mi_offset : 0);
1552 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
1553 return (mi ? mi->mi_filenum : 0);
1556 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
1557 return (mi && mi->mi_set ? mi->mi_set->count : 0);
1561 * Return pattern match.
1562 * @param mire match iterator regex
1563 * @param val value to match
1564 * @return 0 if pattern matches, >0 on nomatch, <0 on error
1566 static int miregexec(miRE mire, const char * val)
1570 switch (mire->mode) {
1571 case RPMMIRE_STRCMP:
1572 rc = strcmp(mire->pattern, val);
1575 case RPMMIRE_DEFAULT:
1577 rc = regexec(mire->preg, val, 0, NULL, mire->eflags);
1578 if (rc && rc != REG_NOMATCH) {
1580 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
1581 msg[sizeof(msg)-1] = '\0';
1582 rpmlog(RPMLOG_ERR, _("%s: regexec failed: %s\n"),
1583 mire->pattern, msg);
1588 rc = fnmatch(mire->pattern, val, mire->fnflags);
1589 if (rc && rc != FNM_NOMATCH)
1601 * Compare iterator selectors by rpm tag (qsort/bsearch).
1602 * @param a 1st iterator selector
1603 * @param b 2nd iterator selector
1604 * @return result of comparison
1606 static int mireCmp(const void * a, const void * b)
1608 const miRE mireA = (const miRE) a;
1609 const miRE mireB = (const miRE) b;
1610 return (mireA->tag - mireB->tag);
1614 * Copy pattern, escaping for appropriate mode.
1615 * @param tag rpm tag
1616 * @retval modep type of pattern match
1617 * @param pattern pattern to duplicate
1618 * @return duplicated pattern
1620 static char * mireDup(rpmTag tag, rpmMireMode *modep,
1621 const char * pattern)
1632 case RPMMIRE_DEFAULT:
1633 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
1634 *modep = RPMMIRE_GLOB;
1635 pat = xstrdup(pattern);
1639 nb = strlen(pattern) + sizeof("^$");
1641 /* Find no. of bytes needed for pattern. */
1642 /* periods and plusses are escaped, splats become '.*' */
1645 for (s = pattern; *s != '\0'; s++) {
1650 if (!brackets) nb++;
1659 if (c != '[') brackets = 0;
1665 pat = t = xmalloc(nb);
1667 if (pattern[0] != '^') *t++ = '^';
1669 /* Copy pattern, escaping periods, prefixing splats with period. */
1672 for (s = pattern; *s != '\0'; s++, t++) {
1676 if (!brackets) *t++ = '\\';
1679 if (!brackets) *t++ = '.';
1688 if (c != '[') brackets = 0;
1694 if (s > pattern && s[-1] != '$') *t++ = '$';
1696 *modep = RPMMIRE_REGEX;
1698 case RPMMIRE_STRCMP:
1701 pat = xstrdup(pattern);
1708 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag,
1709 rpmMireMode mode, const char * pattern)
1711 static rpmMireMode defmode = (rpmMireMode)-1;
1713 char * allpat = NULL;
1715 regex_t * preg = NULL;
1721 if (defmode == (rpmMireMode)-1) {
1722 char *t = rpmExpand("%{?_query_selector_match}", NULL);
1724 if (*t == '\0' || !strcmp(t, "default"))
1725 defmode = RPMMIRE_DEFAULT;
1726 else if (!strcmp(t, "strcmp"))
1727 defmode = RPMMIRE_STRCMP;
1728 else if (!strcmp(t, "regex"))
1729 defmode = RPMMIRE_REGEX;
1730 else if (!strcmp(t, "glob"))
1731 defmode = RPMMIRE_GLOB;
1733 defmode = RPMMIRE_DEFAULT;
1737 if (mi == NULL || pattern == NULL)
1740 /* Leading '!' inverts pattern match sense, like "grep -v". */
1741 if (*pattern == '!') {
1746 allpat = mireDup(tag, &mode, pattern);
1748 if (mode == RPMMIRE_DEFAULT)
1752 case RPMMIRE_DEFAULT:
1753 case RPMMIRE_STRCMP:
1756 preg = xcalloc(1, sizeof(*preg));
1757 cflags = (REG_EXTENDED | REG_NOSUB);
1758 rc = regcomp(preg, allpat, cflags);
1761 (void) regerror(rc, preg, msg, sizeof(msg)-1);
1762 msg[sizeof(msg)-1] = '\0';
1763 rpmlog(RPMLOG_ERR, _("%s: regcomp failed: %s\n"), allpat, msg);
1767 fnflags = FNM_PATHNAME | FNM_PERIOD;
1775 /* FIX: mire has kept values */
1776 allpat = _free(allpat);
1779 /* LCL: regfree has bogus only */
1785 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
1786 mire = mi->mi_re + mi->mi_nre;
1791 mire->pattern = allpat;
1792 mire->notmatch = notmatch;
1794 mire->cflags = cflags;
1795 mire->eflags = eflags;
1796 mire->fnflags = fnflags;
1799 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
1805 * Return iterator selector match.
1806 * @param mi rpm database iterator
1807 * @return 1 if header should be skipped
1809 static int mireSkip (const rpmdbMatchIterator mi)
1812 static int32_t zero = 0;
1817 if (mi->mi_h == NULL) /* XXX can't happen */
1821 * Apply tag tests, implicitly "||" for multiple patterns/values of a
1822 * single tag, implicitly "&&" between multiple tag patterns.
1824 if ((mire = mi->mi_re) != NULL)
1825 for (int i = 0; i < mi->mi_nre; i++, mire++) {
1829 if (!headerGet(mi->mi_h, mire->tag, &td, HEADERGET_MINMEM)) {
1830 if (mire->tag != RPMTAG_EPOCH) {
1834 /* "is package already installed" checks rely on this behavior */
1836 td.type = RPM_INT32_TYPE;
1840 anymatch = 0; /* no matches yet */
1843 while (rpmtdNext(&td) >= 0) {
1844 char *str = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL);
1846 rc = miregexec(mire, str);
1847 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
1852 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
1866 return (ntags == nmatches ? 0 : 1);
1869 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite)
1874 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
1876 mi->mi_cflags |= DB_WRITECURSOR;
1878 mi->mi_cflags &= ~DB_WRITECURSOR;
1882 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified)
1887 rc = mi->mi_modified;
1888 mi->mi_modified = modified;
1892 int rpmdbSetHdrChk(rpmdbMatchIterator mi, rpmts ts,
1893 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
1898 /* XXX forward linkage prevents rpmtsLink */
1900 mi->mi_hdrchk = hdrchk;
1905 /* FIX: mi->mi_key.data may be NULL */
1906 Header rpmdbNextIterator(rpmdbMatchIterator mi)
1921 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
1926 * Cursors are per-iterator, not per-dbi, so get a cursor for the
1927 * iterator on 1st call. If the iteration is to rewrite headers, and the
1928 * CDB model is used for the database, then the cursor needs to
1929 * marked with DB_WRITECURSOR as well.
1931 if (mi->mi_dbc == NULL)
1932 xx = dbiCopen(dbi, dbi->dbi_txnid, &mi->mi_dbc, mi->mi_cflags);
1935 memset(key, 0, sizeof(*key));
1936 data = &mi->mi_data;
1937 memset(data, 0, sizeof(*data));
1944 union _dbswap mi_offset;
1947 if (!(mi->mi_setx < mi->mi_set->count))
1949 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
1950 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
1951 mi_offset.ui = mi->mi_offset;
1952 if (dbiByteSwapped(dbi) == 1)
1955 keylen = sizeof(mi_offset.ui);
1958 key->data = keyp = (void *)mi->mi_keyp;
1959 key->size = keylen = mi->mi_keylen;
1962 #if !defined(_USE_COPY_LOAD)
1963 data->flags |= DB_DBT_MALLOC;
1965 rc = dbiGet(dbi, mi->mi_dbc, key, data,
1966 (key->data == NULL ? DB_NEXT : DB_SET));
1974 * If we got the next key, save the header instance number.
1976 * For db3 Packages, instance 0 (i.e. mi->mi_setx == 0) is the
1977 * largest header instance in the database, and should be
1980 if (keyp && mi->mi_setx && rc == 0) {
1981 memcpy(&mi_offset, keyp, sizeof(mi_offset.ui));
1982 if (dbiByteSwapped(dbi) == 1)
1984 mi->mi_offset = mi_offset.ui;
1987 /* Terminate on error or end of keys */
1988 if (rc || (mi->mi_setx && mi->mi_offset == 0))
1992 } while (mi->mi_offset == 0);
1994 /* If next header is identical, return it now. */
1995 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
1998 /* Retrieve next header blob for index iterator. */
2002 #if !defined(_USE_COPY_LOAD)
2003 data->flags |= DB_DBT_MALLOC;
2005 rc = dbiGet(dbi, mi->mi_dbc, key, data, DB_SET);
2015 /* Rewrite current header (if necessary) and unlink. */
2016 xx = miFreeHeader(mi, dbi);
2018 /* Is this the end of the iteration? */
2022 /* Check header digest/signature once (if requested). */
2023 if (mi->mi_hdrchk && mi->mi_ts) {
2024 rpmRC rpmrc = RPMRC_NOTFOUND;
2026 /* Don't bother re-checking a previously read header. */
2027 if (mi->mi_db->db_bits) {
2030 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
2031 &mi->mi_db->db_nbits, mi->mi_offset);
2032 if (PBM_ISSET(mi->mi_offset, set))
2036 /* If blob is unchecked, check blob import consistency now. */
2037 if (rpmrc != RPMRC_OK) {
2041 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg);
2042 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
2043 rpmlog(lvl, "%s h#%8u %s",
2044 (rpmrc == RPMRC_FAIL ? _("rpmdbNextIterator: skipping") : " read"),
2045 mi->mi_offset, (msg ? msg : "\n"));
2048 /* Mark header checked. */
2049 if (mi->mi_db && mi->mi_db->db_bits && rpmrc == RPMRC_OK) {
2052 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
2053 &mi->mi_db->db_nbits, mi->mi_offset);
2054 PBM_SET(mi->mi_offset, set);
2057 /* Skip damaged and inconsistent headers. */
2058 if (rpmrc == RPMRC_FAIL)
2063 /* Did the header blob load correctly? */
2064 #if !defined(_USE_COPY_LOAD)
2065 mi->mi_h = headerLoad(uh);
2067 mi->mi_h->flags |= HEADERFLAG_ALLOCATED;
2069 mi->mi_h = headerCopyLoad(uh);
2071 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
2073 _("rpmdb: damaged header #%u retrieved -- skipping.\n"),
2079 * Skip this header if iterator selector (if any) doesn't match.
2082 /* XXX hack, can't restart with Packages locked on single instance. */
2083 if (mi->mi_set || mi->mi_keyp == NULL)
2088 mi->mi_prevoffset = mi->mi_offset;
2089 mi->mi_modified = 0;
2094 static void rpmdbSortIterator(rpmdbMatchIterator mi)
2096 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
2098 * mergesort is much (~10x with lots of identical basenames) faster
2099 * than pure quicksort, but glibc uses msort_with_tmp() on stack.
2101 #if defined(__GLIBC__)
2102 qsort(mi->mi_set->recs, mi->mi_set->count,
2103 sizeof(*mi->mi_set->recs), hdrNumCmp);
2105 mergesort(mi->mi_set->recs, mi->mi_set->count,
2106 sizeof(*mi->mi_set->recs), hdrNumCmp);
2113 static int rpmdbGrowIterator(rpmdbMatchIterator mi, int fpNum)
2118 dbiIndex dbi = NULL;
2127 dbcursor = mi->mi_dbc;
2129 data = &mi->mi_data;
2130 if (key->data == NULL)
2133 dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
2137 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2138 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2140 xx = dbiCclose(dbi, dbcursor, 0);
2144 if (rc) { /* error/not found */
2145 if (rc != DB_NOTFOUND)
2147 _("error(%d) getting \"%s\" records from %s index\n"),
2148 rc, (char*)key->data, rpmTagGetName(dbi->dbi_rpmtag));
2150 xx = dbiCclose(dbi, dbcursor, 0);
2157 (void) dbt2set(dbi, data, &set);
2158 for (i = 0; i < set->count; i++)
2159 set->recs[i].fpNum = fpNum;
2162 xx = dbiCclose(dbi, dbcursor, 0);
2166 if (mi->mi_set == NULL) {
2170 fprintf(stderr, "+++ %d = %d + %d\t\"%s\"\n", (mi->mi_set->count + set->count), mi->mi_set->count, set->count, ((char *)key->data));
2172 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
2173 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
2174 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
2175 set->count * sizeof(*(mi->mi_set->recs)));
2176 mi->mi_set->count += set->count;
2177 set = dbiFreeIndexSet(set);
2183 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
2184 int nHdrNums, int sorted)
2186 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2190 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
2194 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
2196 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2199 if (mi->mi_set == NULL)
2200 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
2201 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
2205 rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmTag rpmtag,
2206 const void * keyp, size_t keylen)
2208 rpmdbMatchIterator mi;
2211 dbiIndexSet set = NULL;
2213 void * mi_keyp = NULL;
2219 (void) rpmdbCheckSignals();
2221 /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */
2222 if (rpmtag == RPMDBI_LABEL) {
2223 rpmtag = RPMTAG_NAME;
2227 dbi = dbiOpen(db, rpmtag, 0);
2231 /* Chain cursors for teardown on abnormal exit. */
2232 mi = xcalloc(1, sizeof(*mi));
2233 mi->mi_next = rpmmiRock;
2237 data = &mi->mi_data;
2240 * Handle label and file name special cases.
2241 * Otherwise, retrieve join keys for secondary lookup.
2243 if (rpmtag != RPMDBI_PACKAGES && keyp) {
2244 DBC * dbcursor = NULL;
2249 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2250 rc = dbiFindByLabel(dbi, dbcursor, key, data, keyp, &set);
2251 xx = dbiCclose(dbi, dbcursor, 0);
2253 } else if (rpmtag == RPMTAG_BASENAMES) {
2254 rc = rpmdbFindByFile(db, keyp, key, data, &set);
2256 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2258 key->data = (void *) keyp;
2260 if (key->data && key->size == 0)
2261 key->size = strlen((char *)key->data);
2262 if (key->data && key->size == 0)
2263 key->size++; /* XXX "/" fixup. */
2265 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2268 _("error(%d) getting \"%s\" records from %s index\n"),
2269 rc, (key->data ? (char *)key->data : "???"),
2270 rpmTagGetName(dbi->dbi_rpmtag));
2273 /* Join keys need to be native endian internally. */
2275 (void) dbt2set(dbi, data, &set);
2277 xx = dbiCclose(dbi, dbcursor, 0);
2280 if (rc) { /* error/not found */
2281 set = dbiFreeIndexSet(set);
2282 rpmmiRock = mi->mi_next;
2289 /* Copy the retrieval key, byte swapping header instance if necessary. */
2292 case RPMDBI_PACKAGES:
2295 assert(keylen == sizeof(k->ui)); /* xxx programmer error */
2296 k = xmalloc(sizeof(*k));
2297 memcpy(k, keyp, keylen);
2298 if (dbiByteSwapped(dbi) == 1)
2305 keylen = strlen(keyp);
2306 k = xmalloc(keylen + 1);
2307 memcpy(k, keyp, keylen);
2308 k[keylen] = '\0'; /* XXX assumes strings */
2314 mi->mi_keyp = mi_keyp;
2315 mi->mi_keylen = keylen;
2317 mi->mi_db = rpmdbLink(db, RPMDBG_M("matchIterator"));
2318 mi->mi_rpmtag = rpmtag;
2326 mi->mi_modified = 0;
2327 mi->mi_prevoffset = 0;
2334 mi->mi_hdrchk = NULL;
2340 int rpmdbRemove(rpmdb db, int rid, unsigned int hdrNum,
2342 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
2344 DBC * dbcursor = NULL;
2347 union _dbswap mi_offset;
2348 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
2349 HFD_t hfd = headerFreeData;
2351 sigset_t signalMask;
2358 memset(&key, 0, sizeof(key));
2359 memset(&data, 0, sizeof(data));
2361 { rpmdbMatchIterator mi;
2362 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
2363 h = rpmdbNextIterator(mi);
2366 mi = rpmdbFreeIterator(mi);
2370 rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n"),
2371 "rpmdbRemove", hdrNum);
2376 char *nevra = headerGetNEVRA(h, NULL);
2377 rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", hdrNum, nevra);
2381 (void) blockSignals(&signalMask);
2383 /* FIX: rpmvals heartburn */
2385 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
2387 if (dbiTags.tags != NULL)
2388 for (dbix = 0; dbix < dbiTags.max; dbix++) {
2391 const char ** rpmvals = NULL;
2392 rpmTagType rpmtype = 0;
2393 rpm_count_t rpmcnt = 0;
2399 rpmtag = dbiTags.tags[dbix];
2401 /* Filter out temporary databases */
2402 if (isTemporaryDB(rpmtag))
2405 switch ((rpm_tag_t) rpmtag) {
2406 case RPMDBI_PACKAGES:
2407 dbi = dbiOpen(db, rpmtag, 0);
2408 if (dbi == NULL) /* XXX shouldn't happen */
2411 mi_offset.ui = hdrNum;
2412 if (dbiByteSwapped(dbi) == 1)
2414 key.data = &mi_offset;
2415 key.size = sizeof(mi_offset.ui);
2417 rc = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2418 rc = dbiGet(dbi, dbcursor, &key, &data, DB_SET);
2421 _("error(%d) setting header #%d record for %s removal\n"),
2422 rc, hdrNum, rpmTagGetName(dbi->dbi_rpmtag));
2424 rc = dbiDel(dbi, dbcursor, &key, &data, 0);
2425 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2427 if (!dbi->dbi_no_dbsync)
2428 xx = dbiSync(dbi, 0);
2433 if (!hge(h, rpmtag, &rpmtype, (rpm_data_t *) &rpmvals, &rpmcnt))
2436 dbi = dbiOpen(db, rpmtag, 0);
2440 if (rpmtype == RPM_STRING_TYPE) {
2441 /* XXX force uniform headerGetEntry return */
2442 av[0] = (const char *) rpmvals;
2448 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2449 for (i = 0; i < rpmcnt; i++) {
2454 switch (dbi->dbi_rpmtag) {
2455 case RPMTAG_FILEMD5S:
2456 /* Filter out empty MD5 strings. */
2457 if (!(rpmvals[i] && *rpmvals[i] != '\0'))
2464 /* Identify value pointer and length. */
2469 key.size = sizeof(RPM_CHAR_TYPE);
2470 key.data = rpmvals + i;
2472 case RPM_INT16_TYPE:
2473 key.size = sizeof(int16_t);
2474 key.data = rpmvals + i;
2476 case RPM_INT32_TYPE:
2477 key.size = sizeof(int32_t);
2478 key.data = rpmvals + i;
2483 rpmcnt = 1; /* XXX break out of loop. */
2485 case RPM_STRING_TYPE:
2486 case RPM_I18NSTRING_TYPE:
2487 rpmcnt = 1; /* XXX break out of loop. */
2488 case RPM_STRING_ARRAY_TYPE:
2489 /* Convert from hex to binary. */
2490 if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
2496 for (j = 0; j < 16; j++, t++, s += 2)
2497 *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
2502 /* Extract the pubkey id from the base64 blob. */
2503 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
2504 int nbin = pgpExtractPubkeyFingerprint(rpmvals[i], bin);
2512 key.data = (void *) rpmvals[i];
2513 key.size = strlen(rpmvals[i]);
2519 if (rpmcnt == 1 && stringvalued) {
2520 rpmlog(RPMLOG_DEBUG,
2521 "removing \"%s\" from %s index.\n",
2522 (char *)key.data, rpmTagGetName(dbi->dbi_rpmtag));
2524 rpmlog(RPMLOG_DEBUG,
2525 "removing %d entries from %s index.\n",
2526 rpmcnt, rpmTagGetName(dbi->dbi_rpmtag));
2532 * This is almost right, but, if there are duplicate tag
2533 * values, there will be duplicate attempts to remove
2534 * the header instance. It's faster to just ignore errors
2535 * than to do things correctly.
2539 * XXX with duplicates, an accurate data value and
2540 * DB_GET_BOTH is needed.
2545 key.size = strlen((char *)key.data);
2547 key.size++; /* XXX "/" fixup. */
2549 rc = dbiGet(dbi, dbcursor, &key, &data, DB_SET);
2550 if (rc == 0) { /* success */
2551 (void) dbt2set(dbi, &data, &set);
2552 } else if (rc == DB_NOTFOUND) { /* not found */
2554 } else { /* error */
2556 _("error(%d) setting \"%s\" records from %s index\n"),
2557 rc, (char*)key.data, rpmTagGetName(dbi->dbi_rpmtag));
2562 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
2564 /* If nothing was pruned, then don't bother updating. */
2566 set = dbiFreeIndexSet(set);
2570 if (set->count > 0) {
2571 (void) set2dbt(dbi, &data, set);
2572 rc = dbiPut(dbi, dbcursor, &key, &data, DB_KEYLAST);
2575 _("error(%d) storing record \"%s\" into %s\n"),
2576 rc, (char*)key.data, rpmTagGetName(dbi->dbi_rpmtag));
2579 data.data = _free(data.data);
2582 rc = dbiDel(dbi, dbcursor, &key, &data, 0);
2585 _("error(%d) removing record \"%s\" from %s\n"),
2586 rc, (char*)key.data, rpmTagGetName(dbi->dbi_rpmtag));
2590 set = dbiFreeIndexSet(set);
2593 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2596 if (!dbi->dbi_no_dbsync)
2597 xx = dbiSync(dbi, 0);
2600 if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */
2601 rpmvals = hfd(rpmvals, rpmtype);
2609 (void) unblockSignals(&signalMask);
2613 /* XXX return ret; */
2618 int rpmdbAdd(rpmdb db, int iid, Header h,
2620 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
2622 DBC * dbcursor = NULL;
2625 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
2626 HFD_t hfd = headerFreeData;
2627 sigset_t signalMask;
2628 const char ** baseNames;
2630 rpm_count_t count = 0;
2633 union _dbswap mi_offset;
2634 unsigned int hdrNum = 0;
2642 memset(&key, 0, sizeof(key));
2643 memset(&data, 0, sizeof(data));
2645 #ifdef NOTYET /* XXX headerRemoveEntry() broken on dribbles. */
2646 xx = headerRemoveEntry(h, RPMTAG_REMOVETID);
2648 if (iid != 0 && iid != -1) {
2649 rpm_tid_t tid = iid;
2650 if (!headerIsEntry(h, RPMTAG_INSTALLTID))
2651 xx = headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
2655 * If old style filename tags is requested, the basenames need to be
2656 * retrieved early, and the header needs to be converted before
2657 * being written to the package header database.
2660 xx = hge(h, RPMTAG_BASENAMES, &bnt, (rpm_data_t *) &baseNames, &count);
2662 (void) blockSignals(&signalMask);
2665 unsigned int firstkey = 0;
2666 void * keyp = &firstkey;
2667 size_t keylen = sizeof(firstkey);
2668 void * datap = NULL;
2671 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
2674 /* XXX db0: hack to pass sizeof header to fadAlloc */
2676 datalen = headerSizeof(h, HEADER_MAGIC_NO);
2678 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2680 /* Retrieve join key for next header instance. */
2685 data.size = datalen;
2686 ret = dbiGet(dbi, dbcursor, &key, &data, DB_SET);
2690 datalen = data.size;
2693 if (ret == 0 && datap) {
2694 memcpy(&mi_offset, datap, sizeof(mi_offset.ui));
2695 if (dbiByteSwapped(dbi) == 1)
2697 hdrNum = mi_offset.ui;
2700 mi_offset.ui = hdrNum;
2701 if (dbiByteSwapped(dbi) == 1)
2703 if (ret == 0 && datap) {
2704 memcpy(datap, &mi_offset, sizeof(mi_offset.ui));
2707 datalen = sizeof(mi_offset.ui);
2713 data.size = datalen;
2715 ret = dbiPut(dbi, dbcursor, &key, &data, DB_KEYLAST);
2716 xx = dbiSync(dbi, 0);
2718 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2726 _("error(%d) allocating new package instance\n"), ret);
2730 /* Now update the indexes */
2734 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
2736 if (dbiTags.tags != NULL)
2737 for (dbix = 0; dbix < dbiTags.max; dbix++) {
2739 const char **rpmvals = NULL;
2740 rpmTagType rpmtype = 0;
2741 rpm_count_t rpmcnt = 0;
2743 rpm_flag_t * requireFlags;
2747 rpmrc = RPMRC_NOTFOUND;
2749 requireFlags = NULL;
2750 rpmtag = dbiTags.tags[dbix];
2752 /* Filter out temporary databases */
2753 if (isTemporaryDB(rpmtag))
2757 case RPMDBI_PACKAGES:
2758 dbi = dbiOpen(db, rpmtag, 0);
2759 if (dbi == NULL) /* XXX shouldn't happen */
2761 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2763 mi_offset.ui = hdrNum;
2764 if (dbiByteSwapped(dbi) == 1)
2766 key.data = (void *) &mi_offset;
2767 key.size = sizeof(mi_offset.ui);
2768 data.data = headerUnload(h);
2769 data.size = headerSizeof(h, HEADER_MAGIC_NO);
2771 /* Check header digest/signature on blob export. */
2776 rpmrc = (*hdrchk) (ts, data.data, data.size, &msg);
2777 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
2778 rpmlog(lvl, "%s h#%8u %s",
2779 (rpmrc == RPMRC_FAIL ? _("rpmdbAdd: skipping") : " +++"),
2780 hdrNum, (msg ? msg : "\n"));
2784 if (data.data != NULL && rpmrc != RPMRC_FAIL) {
2785 xx = dbiPut(dbi, dbcursor, &key, &data, DB_KEYLAST);
2786 xx = dbiSync(dbi, 0);
2788 data.data = _free(data.data);
2790 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2792 if (!dbi->dbi_no_dbsync)
2793 xx = dbiSync(dbi, 0);
2796 case RPMTAG_BASENAMES: /* XXX preserve legacy behavior */
2798 rpmvals = baseNames;
2801 case RPMTAG_REQUIRENAME:
2802 xx = hge(h, rpmtag, &rpmtype, (rpm_data_t *)&rpmvals, &rpmcnt);
2803 xx = hge(h, RPMTAG_REQUIREFLAGS, NULL, (rpm_data_t *)&requireFlags, NULL);
2806 xx = hge(h, rpmtag, &rpmtype, (rpm_data_t *)&rpmvals, &rpmcnt);
2811 if (rpmtag != RPMTAG_GROUP)
2814 /* XXX preserve legacy behavior */
2815 rpmtype = RPM_STRING_TYPE;
2816 rpmvals = (const char **) "Unknown";
2820 dbi = dbiOpen(db, rpmtag, 0);
2824 if (rpmtype == RPM_STRING_TYPE) {
2825 /* XXX force uniform headerGetEntry return */
2826 av[0] = (const char *) rpmvals;
2832 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
2834 for (i = 0; i < rpmcnt; i++) {
2841 * Include the tagNum in all indices. rpm-3.0.4 and earlier
2842 * included the tagNum only for files.
2845 switch (dbi->dbi_rpmtag) {
2846 case RPMTAG_PUBKEYS:
2848 case RPMTAG_FILEMD5S:
2849 /* Filter out empty MD5 strings. */
2850 if (!(rpmvals[i] && *rpmvals[i] != '\0'))
2853 case RPMTAG_REQUIRENAME:
2854 /* Filter out install prerequisites. */
2855 if (requireFlags && isInstallPreReq(requireFlags[i]))
2858 case RPMTAG_TRIGGERNAME:
2859 if (i) { /* don't add duplicates */
2860 for (j = 0; j < i; j++) {
2861 if (!strcmp(rpmvals[i], rpmvals[j]))
2872 /* Identify value pointer and length. */
2877 key.size = sizeof(int8_t);
2878 key.data = rpmvals + i;
2880 case RPM_INT16_TYPE:
2881 key.size = sizeof(int16_t);
2882 key.data = rpmvals + i;
2884 case RPM_INT32_TYPE:
2885 key.size = sizeof(int32_t);
2886 key.data = rpmvals + i;
2891 rpmcnt = 1; /* XXX break out of loop. */
2893 case RPM_STRING_TYPE:
2894 case RPM_I18NSTRING_TYPE:
2895 rpmcnt = 1; /* XXX break out of loop. */
2896 case RPM_STRING_ARRAY_TYPE:
2897 /* Convert from hex to binary. */
2898 if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
2903 for (j = 0; j < 16; j++, t++, s += 2)
2904 *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
2909 /* Extract the pubkey id from the base64 blob. */
2910 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
2911 int nbin = pgpExtractPubkeyFingerprint(rpmvals[i], bin);
2919 key.data = (void *) rpmvals[i];
2920 key.size = strlen(rpmvals[i]);
2926 if (rpmcnt == 1 && stringvalued) {
2927 rpmlog(RPMLOG_DEBUG,
2928 "adding \"%s\" to %s index.\n",
2929 (char *)key.data, rpmTagGetName(dbi->dbi_rpmtag));
2931 rpmlog(RPMLOG_DEBUG,
2932 "adding %d entries to %s index.\n",
2933 rpmcnt, rpmTagGetName(dbi->dbi_rpmtag));
2939 * XXX with duplicates, an accurate data value and
2940 * DB_GET_BOTH is needed.
2946 key.size = strlen((char *)key.data);
2948 key.size++; /* XXX "/" fixup. */
2950 rc = dbiGet(dbi, dbcursor, &key, &data, DB_SET);
2951 if (rc == 0) { /* success */
2952 /* With duplicates, cursor is positioned, discard the record. */
2953 if (!dbi->dbi_permit_dups)
2954 (void) dbt2set(dbi, &data, &set);
2955 } else if (rc != DB_NOTFOUND) { /* error */
2957 _("error(%d) getting \"%s\" records from %s index\n"),
2958 rc, (char*)key.data, rpmTagGetName(dbi->dbi_rpmtag));
2963 if (set == NULL) /* not found or duplicate */
2964 set = xcalloc(1, sizeof(*set));
2966 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
2968 (void) set2dbt(dbi, &data, set);
2969 rc = dbiPut(dbi, dbcursor, &key, &data, DB_KEYLAST);
2973 _("error(%d) storing record %s into %s\n"),
2974 rc, (char*)key.data, rpmTagGetName(dbi->dbi_rpmtag));
2977 data.data = _free(data.data);
2979 set = dbiFreeIndexSet(set);
2982 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
2985 if (!dbi->dbi_no_dbsync)
2986 xx = dbiSync(dbi, 0);
2989 if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */
2990 rpmvals = hfd(rpmvals, rpmtype);
2999 (void) unblockSignals(&signalMask);
3004 #define _skip(_dn) { sizeof(_dn)-1, (_dn) }
3006 static struct skipDir_s {
3013 static int skipDir(const char * dn)
3015 struct skipDir_s * sd = skipDirs;
3019 for (sd = skipDirs; sd->dn != NULL; sd++) {
3020 if (dnlen < sd->dnlen)
3022 if (strncmp(dn, sd->dn, sd->dnlen))
3029 /* XXX transaction.c */
3030 int rpmdbFindFpList(rpmdb db, fingerPrint * fpList, dbiIndexSet * matchList,
3035 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
3036 HFD_t hfd = headerFreeData;
3037 rpmdbMatchIterator mi;
3038 fingerPrintCache fpc;
3042 if (db == NULL) return 1;
3044 mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, NULL, 0);
3045 if (mi == NULL) /* XXX should never happen */
3049 data = &mi->mi_data;
3051 /* Gather all installed headers with matching basename's. */
3052 for (i = 0; i < numItems; i++) {
3054 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
3056 key->data = (void *) fpList[i].baseName;
3057 key->size = strlen((char *)key->data);
3059 key->size++; /* XXX "/" fixup. */
3061 if (skipDir(fpList[i].entry->dirName))
3064 xx = rpmdbGrowIterator(mi, i);
3068 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
3069 mi = rpmdbFreeIterator(mi);
3072 fpc = fpCacheCreate(i);
3074 rpmdbSortIterator(mi);
3075 /* iterator is now sorted by (recnum, filenum) */
3077 /* For all installed headers with matching basename's ... */
3079 while ((h = rpmdbNextIterator(mi)) != NULL) {
3080 const char ** dirNames;
3081 const char ** baseNames;
3082 const char ** fullBaseNames;
3083 rpmTagType bnt, dnt;
3084 uint32_t * dirIndexes;
3085 uint32_t * fullDirIndexes;
3092 start = mi->mi_setx - 1;
3093 im = mi->mi_set->recs + start;
3095 /* Find the end of the set of matched basename's in this package. */
3096 for (end = start + 1; end < mi->mi_set->count; end++) {
3097 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
3102 /* Compute fingerprints for this installed header's matches */
3103 xx = hge(h, RPMTAG_BASENAMES, &bnt, (rpm_data_t *) &fullBaseNames, NULL);
3104 xx = hge(h, RPMTAG_DIRNAMES, &dnt, (rpm_data_t *) &dirNames, NULL);
3105 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (rpm_data_t *) &fullDirIndexes, NULL);
3107 baseNames = xcalloc(num, sizeof(*baseNames));
3108 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
3109 for (i = 0; i < num; i++) {
3110 baseNames[i] = fullBaseNames[im[i].tagNum];
3111 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
3114 fps = xcalloc(num, sizeof(*fps));
3115 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
3117 /* Add db (recnum,filenum) to list for fingerprint matches. */
3118 for (i = 0; i < num; i++, im++) {
3119 /* FIX: fpList[].subDir may be NULL */
3120 if (!FP_EQUAL(fps[i], fpList[im->fpNum]))
3122 xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
3126 dirNames = hfd(dirNames, dnt);
3127 fullBaseNames = hfd(fullBaseNames, bnt);
3128 baseNames = _free(baseNames);
3129 dirIndexes = _free(dirIndexes);
3134 mi = rpmdbFreeIterator(mi);
3136 fpc = fpCacheFree(fpc);
3143 * Remove DB4 environment (and lock), ie the equivalent of
3144 * rm -f <prefix>/<dbpath>/__db.???
3145 * Environment files not existing is not an error, failure to unlink is,
3146 * return zero on success.
3147 * Only useful for BDB, dbapi 3 and 4.
3148 * TODO/FIX: push this down to db3.c where it belongs
3150 static int cleanDbenv(const char *prefix, const char *dbpath)
3152 ARGV_t paths = NULL, p;
3154 char *pattern = rpmGetPath(prefix, "/", dbpath, "/__db.???", NULL);
3156 if (rpmGlob(pattern, NULL, &paths) == 0) {
3157 for (p = paths; *p; p++) {
3166 static int rpmdbRemoveDatabase(const char * prefix,
3167 const char * dbpath, int _dbapi)
3176 if (dbiTags.tags != NULL)
3177 for (i = 0; i < dbiTags.max; i++) {
3178 const char * base = rpmTagGetName(dbiTags.tags[i]);
3179 path = rpmGetPath(prefix, "/", dbpath, "/", base, NULL);
3180 if (access(path, F_OK) == 0)
3184 cleanDbenv(prefix, dbpath);
3192 path = rpmGetPath(prefix, "/", dbpath, NULL);
3199 static int rpmdbMoveDatabase(const char * prefix,
3200 const char * olddbpath, int _olddbapi,
3201 const char * newdbpath, int _newdbapi)
3207 int selinux = is_selinux_enabled() && (matchpathcon_init(NULL) != -1);
3210 blockSignals(&sigMask);
3211 switch (_olddbapi) {
3215 if (dbiTags.tags != NULL)
3216 for (i = 0; i < dbiTags.max; i++) {
3221 /* Filter out temporary databases */
3222 if (isTemporaryDB((rpmtag = dbiTags.tags[i])))
3225 base = rpmTagGetName(rpmtag);
3226 src = rpmGetPath(prefix, "/", olddbpath, "/", base, NULL);
3227 dest = rpmGetPath(prefix, "/", newdbpath, "/", base, NULL);
3229 if (access(src, F_OK) != 0)
3233 * Restore uid/gid/mode/mtime/security context if possible.
3235 if (stat(dest, &st) < 0)
3236 if (stat(src, &st) < 0)
3239 if ((xx = rename(src, dest)) != 0) {
3243 xx = chown(dest, st.st_uid, st.st_gid);
3244 xx = chmod(dest, (st.st_mode & 07777));
3245 { struct utimbuf stamp;
3246 stamp.actime = st.st_atime;
3247 stamp.modtime = st.st_mtime;
3248 xx = utime(dest, &stamp);
3252 security_context_t scon = NULL;
3253 if (matchpathcon(dest, st.st_mode, &scon) != -1) {
3254 (void) setfilecon(dest, scon);
3264 cleanDbenv(prefix, olddbpath);
3265 cleanDbenv(prefix, newdbpath);
3272 unblockSignals(&sigMask);
3274 #ifdef SQLITE_HACK_XXX
3275 if (rc || _olddbapi == _newdbapi)
3278 rc = rpmdbRemoveDatabase(prefix, newdbpath, _newdbapi);
3282 (void) matchpathcon_fini();
3287 int rpmdbRebuild(const char * prefix, rpmts ts,
3288 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
3291 char * dbpath = NULL;
3292 char * rootdbpath = NULL;
3294 char * newdbpath = NULL;
3295 char * newrootdbpath = NULL;
3304 if (prefix == NULL) prefix = "/";
3306 _dbapi = rpmExpandNumeric("%{_dbapi}");
3307 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
3309 tfn = rpmGetPath("%{?_dbpath}", NULL);
3310 if (!(tfn && tfn[0] != '\0'))
3312 rpmlog(RPMLOG_ERR, _("no dbpath has been set"));
3316 dbpath = rootdbpath = rpmGetPath(prefix, tfn, NULL);
3317 if (!(prefix[0] == '/' && prefix[1] == '\0'))
3318 dbpath += strlen(prefix) - 1;
3321 tfn = rpmGetPath("%{?_dbpath_rebuild}", NULL);
3322 if (!(tfn && tfn[0] != '\0' && strcmp(tfn, dbpath)))
3325 rasprintf(&tfn, "%srebuilddb.%d", dbpath, (int) getpid());
3328 newdbpath = newrootdbpath = rpmGetPath(prefix, tfn, NULL);
3329 if (!(prefix[0] == '/' && prefix[1] == '\0'))
3330 newdbpath += strlen(prefix) - 1;
3333 rpmlog(RPMLOG_DEBUG, "rebuilding database %s into %s\n",
3334 rootdbpath, newrootdbpath);
3336 if (!access(newrootdbpath, F_OK)) {
3337 rpmlog(RPMLOG_ERR, _("temporary database %s already exists\n"),
3343 rpmlog(RPMLOG_DEBUG, "creating directory %s\n", newrootdbpath);
3344 if (mkdir(newrootdbpath, 0755)) {
3345 rpmlog(RPMLOG_ERR, _("failed to create directory %s: %s\n"),
3346 newrootdbpath, strerror(errno));
3352 _rebuildinprogress = 0;
3354 rpmlog(RPMLOG_DEBUG, "opening old database with dbapi %d\n",
3356 if (openDatabase(prefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
3357 RPMDB_FLAG_MINIMAL)) {
3361 _dbapi = olddb->db_api;
3362 _rebuildinprogress = 1;
3363 rpmlog(RPMLOG_DEBUG, "opening new database with dbapi %d\n",
3365 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
3366 if (openDatabase(prefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
3371 _rebuildinprogress = 0;
3373 _dbapi_rebuild = newdb->db_api;
3376 rpmdbMatchIterator mi;
3377 #define _RECNUM rpmdbGetIteratorOffset(mi)
3379 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
3381 (void) rpmdbSetHdrChk(mi, ts, hdrchk);
3383 while ((h = rpmdbNextIterator(mi)) != NULL) {
3385 /* let's sanity check this record a bit, otherwise just skip it */
3386 if (!(headerIsEntry(h, RPMTAG_NAME) &&
3387 headerIsEntry(h, RPMTAG_VERSION) &&
3388 headerIsEntry(h, RPMTAG_RELEASE) &&
3389 headerIsEntry(h, RPMTAG_BUILDTIME)))
3392 _("header #%u in the database is bad -- skipping.\n"),
3397 /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
3398 if (_db_filter_dups || newdb->db_filter_dups) {
3399 const char * name, * version, * release;
3402 (void) headerNVR(h, &name, &version, &release);
3404 { rpmdbMatchIterator mi;
3405 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
3406 (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
3407 RPMMIRE_DEFAULT, version);
3408 (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
3409 RPMMIRE_DEFAULT, release);
3410 while (rpmdbNextIterator(mi)) {
3414 mi = rpmdbFreeIterator(mi);
3421 /* Deleted entries are eliminated in legacy headers by copy. */
3422 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
3423 ? headerCopy(h) : NULL);
3424 rc = rpmdbAdd(newdb, -1, (nh ? nh : h), ts, hdrchk);
3425 nh = headerFree(nh);
3430 _("cannot add record originally at %u\n"), _RECNUM);
3436 mi = rpmdbFreeIterator(mi);
3440 xx = rpmdbClose(olddb);
3441 xx = rpmdbClose(newdb);
3444 rpmlog(RPMLOG_NOTICE, _("failed to rebuild database: original database "
3445 "remains in place\n"));
3447 xx = rpmdbRemoveDatabase(prefix, newdbpath, _dbapi_rebuild);
3450 } else if (!nocleanup) {
3451 if (rpmdbMoveDatabase(prefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
3452 rpmlog(RPMLOG_ERR, _("failed to replace old database with new "
3454 rpmlog(RPMLOG_ERR, _("replace files in %s with files from %s "
3455 "to recover"), dbpath, newdbpath);
3463 if (removedir && !(rc == 0 && nocleanup)) {
3464 rpmlog(RPMLOG_DEBUG, "removing directory %s\n", newrootdbpath);
3465 if (rmdir(newrootdbpath))
3466 rpmlog(RPMLOG_ERR, _("failed to remove directory %s: %s\n"),
3467 newrootdbpath, strerror(errno));
3469 newrootdbpath = _free(newrootdbpath);
3470 rootdbpath = _free(rootdbpath);