12 #include <sys/signal.h>
15 #include <rpmmacro.h> /* XXX for rpmGetPath/rpmGenPath */
22 /*@access dbiIndexSet@*/
23 /*@access dbiIndexItem@*/
24 /*@access Header@*/ /* XXX compared with NULL */
25 /*@access rpmdbMatchIterator@*/
27 extern int _noDirTokens;
28 static int _rebuildinprogress = 0;
29 static int _db_filter_dups = 0;
31 int _filterDbDups = 0; /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
34 #define _DBI_PERMS 0644
37 static int dbiTagsMax = 0;
38 /*@only@*/ static int *dbiTags = NULL;
41 * Return dbi index used for rpm tag.
42 * @param rpmtag rpm header tag
43 * @return dbi index, -1 on error
45 static int dbiTagToDbix(int rpmtag)
49 if (!(dbiTagsMax > 0 && dbiTags))
51 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
52 if (rpmtag == dbiTags[dbix])
59 * Initialize database (index, tag) tuple from configuration.
61 static void dbiTagsInit(void)
63 /*@observer@*/ static const char * const _dbiTagStr_default =
64 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername";
65 char * dbiTagStr = NULL;
69 dbiTagStr = rpmExpand("%{_dbi_tags}", NULL);
70 if (!(dbiTagStr && *dbiTagStr && *dbiTagStr != '%')) {
71 free((void *)dbiTagStr);
72 dbiTagStr = xstrdup(_dbiTagStr_default);
75 if (dbiTagsMax || dbiTags) {
81 /* Always allocate package index */
83 dbiTags = xcalloc(1, dbiTagsMax * sizeof(*dbiTags));
85 for (o = dbiTagStr; o && *o; o = oe) {
86 while (*o && isspace(*o))
90 for (oe = o; oe && *oe; oe++) {
93 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
101 fprintf(stderr, _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
104 if (dbiTagToDbix(rpmtag) >= 0)
107 dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags)); /* XXX memory leak */
108 dbiTags[dbiTagsMax++] = rpmtag;
116 extern struct _dbiVec db1vec;
117 #define DB1vec &db1vec
123 extern struct _dbiVec db2vec;
124 #define DB2vec &db2vec
130 extern struct _dbiVec db3vec;
131 #define DB3vec &db3vec
136 static struct _dbiVec *mydbvecs[] = {
137 DB1vec, DB1vec, DB2vec, DB3vec, NULL
140 INLINE int dbiSync(dbiIndex dbi, unsigned int flags) {
141 if (_debug < 0 || dbi->dbi_debug)
142 fprintf(stderr, " Sync %s\n", tagName(dbi->dbi_rpmtag));
143 return (*dbi->dbi_vec->sync) (dbi, flags);
146 INLINE int dbiByteSwapped(dbiIndex dbi) {
147 return (*dbi->dbi_vec->byteswapped) (dbi);
150 INLINE int XdbiCopen(dbiIndex dbi, /*@out@*/ DBC ** dbcp, unsigned int flags,
151 const char * f, unsigned int l)
153 if (_debug < 0 || dbi->dbi_debug)
154 fprintf(stderr, "+++ RMW %s (%s:%u)\n", tagName(dbi->dbi_rpmtag), f, l);
155 return (*dbi->dbi_vec->copen) (dbi, dbcp, flags);
158 INLINE int XdbiCclose(dbiIndex dbi, /*@only@*/ DBC * dbcursor, unsigned int flags,
159 const char * f, unsigned int l)
161 if (_debug < 0 || dbi->dbi_debug)
162 fprintf(stderr, "--- RMW %s (%s:%u)\n", tagName(dbi->dbi_rpmtag), f, l);
163 return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags);
166 INLINE int dbiDel(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen, unsigned int flags)
171 /* XXX make sure that keylen is correct for "" lookup */
172 NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
173 if (NULkey) keylen++;
174 rc = (*dbi->dbi_vec->cdel) (dbi, dbcursor, keyp, keylen, flags);
175 if (NULkey) keylen--;
177 if (_debug < 0 || dbi->dbi_debug)
178 fprintf(stderr, " Del %s key (%p,%ld) %s rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)keyp : ""), rc);
183 INLINE int dbiGet(dbiIndex dbi, DBC * dbcursor, void ** keypp, size_t * keylenp,
184 void ** datapp, size_t * datalenp, unsigned int flags)
189 /* XXX make sure that keylen is correct for "" lookup */
190 NULkey = (keypp && *keypp && *((char *)(*keypp)) == '\0' && keylenp && *keylenp == 0);
191 if (NULkey) (*keylenp)++;
192 rc = (*dbi->dbi_vec->cget) (dbi, dbcursor, keypp, keylenp, datapp, datalenp, flags);
193 if (NULkey) (*keylenp)--;
195 if (_debug < 0 || dbi->dbi_debug) {
197 int dataval = 0xdeadbeef;
198 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES && keypp && *keypp && keylenp && *keylenp >= sizeof(keyval)) {
200 memcpy(&keyint, *keypp, sizeof(keyint));
201 sprintf(keyval, "%d", keyint);
202 } else keyval[0] = '\0';
203 if (rc == 0 && datapp && *datapp && datalenp && *datalenp >= sizeof(dataval))
204 memcpy(&dataval, *datapp, sizeof(dataval));
205 fprintf(stderr, " Get %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n",
206 tagName(dbi->dbi_rpmtag), *keypp, (long)*keylenp, *datapp, (long)*datalenp,
207 (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)*keypp : keyval), (unsigned)dataval, rc);
212 INLINE int dbiPut(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen,
213 const void * datap, size_t datalen, unsigned int flags)
218 /* XXX make sure that keylen is correct for "" lookup */
219 NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
220 if (NULkey) keylen++;
221 rc = (*dbi->dbi_vec->cput) (dbi, dbcursor, keyp, keylen, datap, datalen, flags);
222 if (NULkey) keylen--;
224 if (_debug < 0 || dbi->dbi_debug) {
225 int dataval = 0xdeadbeef;
226 if (datap) memcpy(&dataval, datap, sizeof(dataval));
227 fprintf(stderr, " Put %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, datap, (long)datalen, (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)keyp : ""), (unsigned)dataval, rc);
233 INLINE int dbiClose(dbiIndex dbi, unsigned int flags) {
234 if (_debug < 0 || dbi->dbi_debug)
235 fprintf(stderr, " %s Close\n", tagName(dbi->dbi_rpmtag));
236 return (*dbi->dbi_vec->close) (dbi, flags);
239 dbiIndex dbiOpen(rpmdb rpmdb, int rpmtag, /*@unused@*/ unsigned int flags)
243 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
246 dbix = dbiTagToDbix(rpmtag);
247 if (dbix < 0 || dbix >= dbiTagsMax)
250 /* Is this index already open ? */
251 if ((dbi = rpmdb->_dbi[dbix]) != NULL)
254 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
255 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 3)
257 _dbapi_wanted = (_rebuildinprogress ? -1 : rpmdb->db_api);
259 switch (_dbapi_wanted) {
261 _dbapi = _dbapi_wanted;
262 if (_dbapi < 0 || _dbapi >= 4 || mydbvecs[_dbapi] == NULL) {
267 rc = (*mydbvecs[_dbapi]->open) (rpmdb, rpmtag, &dbi);
269 static int _printed[32];
270 if (!_printed[dbix & 0x1f]++)
271 rpmError(RPMERR_DBOPEN,
272 _("cannot open %s index using db%d - %s (%d)\n"),
273 tagName(rpmtag), _dbapi,
274 (rc > 0 ? strerror(rc) : ""), rc);
280 while (_dbapi-- > 1) {
281 if (mydbvecs[_dbapi] == NULL)
285 rc = (*mydbvecs[_dbapi]->open) (rpmdb, rpmtag, &dbi);
290 static int _printed[32];
291 if (!_printed[dbix & 0x1f]++)
292 rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"),
297 if (rpmdb->db_api == -1 && _dbapi > 0)
298 rpmdb->db_api = _dbapi;
302 /* Require conversion. */
303 if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
304 rc = (_rebuildinprogress ? 0 : 1);
308 /* Suggest possible configuration */
309 if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
314 /* Suggest possible configuration */
315 if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
316 rc = (_rebuildinprogress ? 0 : 1);
321 if (rc == 0 && dbi) {
322 rpmdb->_dbi[dbix] = dbi;
332 * Create and initialize item for index database set.
333 * @param hdrNum header instance in db
334 * @param tagNum tag index in header
337 static INLINE dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum) {
338 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
339 rec->hdrNum = hdrNum;
340 rec->tagNum = tagNum;
349 #define _DBSWAP(_a) \
350 { unsigned char _b, *_c = (_a).uc; \
351 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
352 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
356 * Return items that match criteria.
357 * @param dbi index database handle
358 * @param dbcursor index database cursor
359 * @param keyp search key
360 * @param keylen search key length (0 will use strlen(key))
361 * @param setp address of items retrieved from index database
362 * @return -1 error, 0 success, 1 not found
364 static int dbiSearch(dbiIndex dbi, DBC * dbcursor,
365 const char * keyp, size_t keylen, dbiIndexSet * setp)
371 if (setp) *setp = NULL;
372 if (keylen == 0) keylen = strlen(keyp);
374 rc = dbiGet(dbi, dbcursor, (void **)&keyp, &keylen, &datap, &datalen, 0);
377 rpmError(RPMERR_DBGETINDEX,
378 _("error(%d) getting \"%s\" records from %s index\n"),
379 rc, keyp, tagName(dbi->dbi_rpmtag));
381 if (rc == 0 && setp) {
382 int _dbbyteswapped = dbiByteSwapped(dbi);
383 const char * sdbir = datap;
387 set = xmalloc(sizeof(*set));
389 /* Convert to database internal format */
390 switch (dbi->dbi_jlen) {
392 case 2*sizeof(int_32):
393 set->count = datalen / (2*sizeof(int_32));
394 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
395 for (i = 0; i < set->count; i++) {
396 union _dbswap hdrNum, tagNum;
398 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
399 sdbir += sizeof(hdrNum.ui);
400 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
401 sdbir += sizeof(tagNum.ui);
402 if (_dbbyteswapped) {
406 set->recs[i].hdrNum = hdrNum.ui;
407 set->recs[i].tagNum = tagNum.ui;
408 set->recs[i].fpNum = 0;
409 set->recs[i].dbNum = 0;
412 case 1*sizeof(int_32):
413 set->count = datalen / (1*sizeof(int_32));
414 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
415 for (i = 0; i < set->count; i++) {
416 union _dbswap hdrNum;
418 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
419 sdbir += sizeof(hdrNum.ui);
420 if (_dbbyteswapped) {
423 set->recs[i].hdrNum = hdrNum.ui;
424 set->recs[i].tagNum = 0;
425 set->recs[i].fpNum = 0;
426 set->recs[i].dbNum = 0;
436 * Change/delete items that match criteria.
437 * @param dbi index database handle
438 * @param dbcursor index database cursor
439 * @param keyp update key
440 * @param keylen update key length
441 * @param set items to update in index database
442 * @return 0 success, 1 not found
445 static int dbiUpdateIndex(dbiIndex dbi, DBC * dbcursor,
446 const void * keyp, size_t keylen, dbiIndexSet set)
455 int _dbbyteswapped = dbiByteSwapped(dbi);
457 /* Convert to database internal format */
459 switch (dbi->dbi_jlen) {
461 case 2*sizeof(int_32):
462 datalen = set->count * (2 * sizeof(int_32));
463 datap = tdbir = alloca(datalen);
464 for (i = 0; i < set->count; i++) {
465 union _dbswap hdrNum, tagNum;
467 hdrNum.ui = set->recs[i].hdrNum;
468 tagNum.ui = set->recs[i].tagNum;
469 if (_dbbyteswapped) {
473 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
474 tdbir += sizeof(hdrNum.ui);
475 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
476 tdbir += sizeof(tagNum.ui);
479 case 1*sizeof(int_32):
480 datalen = set->count * (1 * sizeof(int_32));
481 datap = tdbir = alloca(datalen);
482 for (i = 0; i < set->count; i++) {
483 union _dbswap hdrNum;
485 hdrNum.ui = set->recs[i].hdrNum;
486 if (_dbbyteswapped) {
489 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
490 tdbir += sizeof(hdrNum.ui);
495 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, 0);
498 rpmError(RPMERR_DBPUTINDEX,
499 _("error(%d) storing record %s into %s\n"),
500 rc, keyp, tagName(dbi->dbi_rpmtag));
505 rc = dbiDel(dbi, dbcursor, keyp, keylen, 0);
508 rpmError(RPMERR_DBPUTINDEX,
509 _("error(%d) removing record %s from %s\n"),
510 rc, keyp, tagName(dbi->dbi_rpmtag));
519 /* XXX assumes hdrNum is first int in dbiIndexItem */
520 static int hdrNumCmp(const void * one, const void * two) {
521 const int * a = one, * b = two;
526 * Append element(s) to set of index database items.
527 * @param set set of index database items
528 * @param recs array of items to append to set
529 * @param nrecs number of items
530 * @param recsize size of an array item
531 * @param sortset should resulting set be sorted?
532 * @return 0 success, 1 failure (bad args)
534 static INLINE int dbiAppendSet(dbiIndexSet set, const void * recs,
535 int nrecs, size_t recsize, int sortset)
537 const char * rptr = recs;
538 size_t rlen = (recsize < sizeof(*(set->recs)))
539 ? recsize : sizeof(*(set->recs));
541 if (set == NULL || recs == NULL || nrecs <= 0 || recsize <= 0)
544 set->recs = (set->count == 0)
545 ? xmalloc(nrecs * sizeof(*(set->recs)))
546 : xrealloc(set->recs, (set->count + nrecs) * sizeof(*(set->recs)));
548 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
550 while (nrecs-- > 0) {
551 memcpy(set->recs + set->count, rptr, rlen);
556 if (set->count > 1 && sortset)
557 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
563 * Remove element(s) from set of index database items.
564 * @param set set of index database items
565 * @param recs array of items to remove from set
566 * @param nrecs number of items
567 * @param recsize size of an array item
568 * @param sorted array is already sorted?
569 * @return 0 success, 1 failure (no items found)
571 static INLINE int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
572 size_t recsize, int sorted)
576 int num = set->count;
579 if (nrecs > 1 && !sorted)
580 qsort(recs, nrecs, recsize, hdrNumCmp);
582 for (from = 0; from < num; from++) {
583 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
588 set->recs[to] = set->recs[from]; /* structure assignment */
593 return (numCopied == num);
596 /* XXX transaction.c */
597 unsigned int dbiIndexSetCount(dbiIndexSet set) {
601 /* XXX transaction.c */
602 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
603 return set->recs[recno].hdrNum;
606 /* XXX transaction.c */
607 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
608 return set->recs[recno].tagNum;
611 /* XXX transaction.c */
612 void dbiFreeIndexSet(dbiIndexSet set) {
614 if (set->recs) free(set->recs);
620 * Disable all signals, returning previous signal mask.
622 static void blockSignals(rpmdb rpmdb, /*@out@*/ sigset_t * oldMask)
626 /* XXX HACK (disabled) permit ^C aborts for now ... */
627 if (!(rpmdb && rpmdb->db_api == 4)) {
628 sigfillset(&newMask); /* block all signals */
629 sigprocmask(SIG_BLOCK, &newMask, oldMask);
634 * Restore signal mask.
636 static void unblockSignals(rpmdb rpmdb, sigset_t * oldMask)
638 /* XXX HACK (disabled) permit ^C aborts for now ... */
639 if (!(rpmdb && rpmdb->db_api == 4)) {
640 sigprocmask(SIG_SETMASK, oldMask, NULL);
645 #define _DB_HOME "%{_dbpath}"
648 #define _DB_PERMS 0644
651 #define _DB_REMOVE_ENV 0
652 #define _DB_FILTER_DUPS 0
653 #define _DB_ERRPFX "rpmdb"
656 /*@observer@*/ static struct rpmdb_s dbTemplate = {
657 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
658 _DB_MAJOR, _DB_REMOVE_ENV, _DB_FILTER_DUPS, _DB_ERRPFX
662 int rpmdbOpenAll (rpmdb rpmdb)
666 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
667 if (rpmdb->_dbi[dbix] != NULL)
669 (void) dbiOpen(rpmdb, dbiTags[dbix], rpmdb->db_flags);
674 /* XXX query.c, rpminstall.c, verify.c */
675 int rpmdbClose (rpmdb rpmdb)
679 for (dbix = rpmdb->db_ndbi; --dbix >= 0; ) {
680 if (rpmdb->_dbi[dbix] == NULL)
682 dbiClose(rpmdb->_dbi[dbix], 0);
683 rpmdb->_dbi[dbix] = NULL;
685 if (rpmdb->db_errpfx) {
686 free((void *)rpmdb->db_errpfx);
687 rpmdb->db_errpfx = NULL;
689 if (rpmdb->db_root) {
690 free((void *)rpmdb->db_root);
691 rpmdb->db_root = NULL;
693 if (rpmdb->db_home) {
694 free((void *)rpmdb->db_home);
695 rpmdb->db_home = NULL;
698 free((void *)rpmdb->_dbi);
705 int rpmdbSync(rpmdb rpmdb)
709 for (dbix = 0; dbix < rpmdb->db_ndbi; dbix++) {
711 if (rpmdb->_dbi[dbix] == NULL)
713 xx = dbiSync(rpmdb->_dbi[dbix], 0);
718 static /*@only@*/ rpmdb newRpmdb(/*@kept@*/ const char * root,
719 /*@kept@*/ const char * home,
720 int mode, int perms, int flags)
722 rpmdb rpmdb = xcalloc(sizeof(*rpmdb), 1);
723 const char * epfx = _DB_ERRPFX;
724 static int _initialized = 0;
727 _filterDbDups = rpmExpandNumeric("%{_filterdbdups}");
731 *rpmdb = dbTemplate; /* structure assignment */
733 if (!(perms & 0600)) perms = 0644; /* XXX sanity */
735 if (mode >= 0) rpmdb->db_mode = mode;
736 if (perms >= 0) rpmdb->db_perms = perms;
737 if (flags >= 0) rpmdb->db_flags = flags;
739 rpmdb->db_root = rpmGetPath( (root && *root ? root : _DB_ROOT), NULL);
740 rpmdb->db_home = rpmGetPath( (home && *home ? home : _DB_HOME), NULL);
741 if (!(rpmdb->db_home && rpmdb->db_home[0] != '%')) {
742 rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
746 rpmdb->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
747 rpmdb->db_remove_env = 0;
748 rpmdb->db_filter_dups = _filterDbDups;
749 rpmdb->db_ndbi = dbiTagsMax;
750 rpmdb->_dbi = xcalloc(rpmdb->db_ndbi, sizeof(*rpmdb->_dbi));
754 static int openDatabase(const char * prefix, const char * dbpath, int _dbapi,
755 /*@out@*/ rpmdb *dbp, int mode, int perms, int flags)
759 static int _initialized = 0;
760 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
761 int minimal = flags & RPMDB_FLAG_MINIMAL;
763 if (!_initialized || dbiTagsMax == 0) {
768 /* Insure that _dbapi has one of -1, 1, 2, or 3 */
769 if (_dbapi < -1 || _dbapi > 3)
779 rpmdb = newRpmdb(prefix, dbpath, mode, perms, flags);
780 rpmdb->db_api = _dbapi;
785 for (dbix = 0; rc == 0 && dbix < dbiTagsMax; dbix++) {
789 /* Filter out temporary databases */
790 switch ((rpmtag = dbiTags[dbix])) {
791 case RPMDBI_AVAILABLE:
796 /*@notreached@*/ break;
801 dbi = dbiOpen(rpmdb, rpmtag, 0);
804 case RPMDBI_PACKAGES:
805 if (dbi == NULL) rc |= 1;
806 /* XXX open only Packages, indices created on the fly. */
808 if (rpmdb->db_api == 3)
811 /*@notreached@*/ break;
813 if (dbi == NULL) rc |= 1;
817 case RPMTAG_BASENAMES:
818 { void * keyp = NULL;
822 /* We used to store the fileindexes as complete paths, rather then
823 plain basenames. Let's see which version we are... */
825 * XXX FIXME: db->fileindex can be NULL under pathological (e.g. mixed
826 * XXX db1/db2 linkage) conditions.
831 xx = dbiCopen(dbi, &dbcursor, 0);
832 xx = dbiGet(dbi, dbcursor, &keyp, NULL, NULL, NULL, 0);
834 const char * akey = keyp;
835 if (strchr(akey, '/')) {
836 rpmError(RPMERR_OLDDB, _("old format database is present; "
837 "use --rebuilddb to generate a new format database\n"));
841 xx = dbiCclose(dbi, dbcursor, 0);
851 if (rc || justCheck || dbp == NULL)
859 /* XXX python/rpmmodule.c */
860 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
862 int _dbapi = rpmExpandNumeric("%{_dbapi}");
863 return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
866 int rpmdbInit (const char * prefix, int perms)
869 int _dbapi = rpmExpandNumeric("%{_dbapi}");
872 rc = openDatabase(prefix, NULL, _dbapi, &rpmdb, (O_CREAT | O_RDWR),
873 perms, RPMDB_FLAG_JUSTCHECK);
882 static int rpmdbFindByFile(rpmdb rpmdb, const char * filespec,
883 /*@out@*/ dbiIndexSet * matches)
885 const char * dirName;
886 const char * baseName;
887 fingerPrintCache fpc;
891 dbiIndexSet allMatches = NULL;
892 dbiIndexItem rec = NULL;
898 if ((baseName = strrchr(filespec, '/')) != NULL) {
902 len = baseName - filespec + 1;
903 t = strncpy(alloca(len + 1), filespec, len);
912 fpc = fpCacheCreate(20);
913 fp1 = fpLookup(fpc, dirName, baseName, 1);
915 dbi = dbiOpen(rpmdb, RPMTAG_BASENAMES, 0);
917 xx = dbiCopen(dbi, &dbcursor, 0);
918 rc = dbiSearch(dbi, dbcursor, baseName, strlen(baseName), &allMatches);
919 xx = dbiCclose(dbi, dbcursor, 0);
922 dbiFreeIndexSet(allMatches);
928 *matches = xcalloc(1, sizeof(**matches));
929 rec = dbiIndexNewItem(0, 0);
931 while (i < allMatches->count) {
932 const char ** baseNames, ** dirNames;
934 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
935 unsigned int prevoff;
938 { rpmdbMatchIterator mi;
939 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &offset, sizeof(offset));
940 h = rpmdbNextIterator(mi);
943 rpmdbFreeIterator(mi);
951 headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
952 (const void **) &baseNames, NULL);
953 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
954 (const void **) &dirNames, NULL);
955 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
956 (const void **) &dirIndexes, NULL);
960 int num = dbiIndexRecordFileNumber(allMatches, i);
962 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
963 if (FP_EQUAL(fp1, fp2)) {
964 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
965 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
966 dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
971 offset = dbiIndexRecordOffset(allMatches, i);
972 } while (i < allMatches->count &&
973 (i == 0 || offset == prevoff));
985 dbiFreeIndexSet(allMatches);
991 if ((*matches)->count == 0) {
992 dbiFreeIndexSet(*matches);
1000 /* XXX python/upgrade.c, install.c, uninstall.c */
1001 int rpmdbCountPackages(rpmdb rpmdb, const char * name)
1004 dbiIndexSet matches = NULL;
1008 dbi = dbiOpen(rpmdb, RPMTAG_NAME, 0);
1010 DBC * dbcursor = NULL;
1011 xx = dbiCopen(dbi, &dbcursor, 0);
1012 rc = dbiSearch(dbi, dbcursor, name, strlen(name), &matches);
1013 xx = dbiCclose(dbi, dbcursor, 0);
1017 if (rc == 0) /* success */
1018 rc = dbiIndexSetCount(matches);
1019 else if (rc > 0) /* error */
1020 rpmError(RPMERR_DBCORRUPT, _("error(%d) counting packages\n"), rc);
1021 else /* not found */
1025 dbiFreeIndexSet(matches);
1030 /* XXX transaction.c */
1031 /* 0 found matches */
1034 static int dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
1035 const char * name, const char * version, const char * release,
1036 /*@out@*/ dbiIndexSet * matches)
1042 rc = dbiSearch(dbi, dbcursor, name, strlen(name), matches);
1045 rc = ((rc == -1) ? 2 : 1);
1049 if (!version && !release) {
1056 /* make sure the version and releases match */
1057 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
1058 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
1059 int goodRelease, goodVersion;
1060 const char * pkgVersion;
1061 const char * pkgRelease;
1067 { rpmdbMatchIterator mi;
1068 mi = rpmdbInitIterator(dbi->dbi_rpmdb, RPMDBI_PACKAGES, &recoff, sizeof(recoff));
1069 h = rpmdbNextIterator(mi);
1072 rpmdbFreeIterator(mi);
1076 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
1077 "findMatches", recoff);
1082 headerNVR(h, NULL, &pkgVersion, &pkgRelease);
1084 goodRelease = goodVersion = 1;
1086 if (release && strcmp(release, pkgRelease)) goodRelease = 0;
1087 if (version && strcmp(version, pkgVersion)) goodVersion = 0;
1089 if (goodRelease && goodVersion) {
1090 /* structure assignment */
1091 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
1093 (*matches)->recs[i].hdrNum = 0;
1099 (*matches)->count = gotMatches;
1106 if (rc && matches && *matches) {
1107 dbiFreeIndexSet(*matches);
1114 * Lookup by name, name-version, and finally by name-version-release.
1115 * @param dbi index database handle (always RPMDBI_PACKAGES)
1116 * @param dbcursor index database cursor
1119 * @return 0 on success, 1 on no mtches, 2 on error
1121 static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, const char * arg, dbiIndexSet * matches)
1123 char * localarg, * chptr;
1127 if (!strlen(arg)) return 1;
1129 /* did they give us just a name? */
1130 rc = dbiFindMatches(dbi, dbcursor, arg, NULL, NULL, matches);
1131 if (rc != 1) return rc;
1133 dbiFreeIndexSet(*matches);
1137 /* maybe a name and a release */
1138 localarg = alloca(strlen(arg) + 1);
1139 strcpy(localarg, arg);
1141 chptr = (localarg + strlen(localarg)) - 1;
1142 while (chptr > localarg && *chptr != '-') chptr--;
1143 if (chptr == localarg) return 1;
1146 rc = dbiFindMatches(dbi, dbcursor, localarg, chptr + 1, NULL, matches);
1147 if (rc != 1) return rc;
1148 if (*matches) dbiFreeIndexSet(*matches);
1150 /* how about name-version-release? */
1152 release = chptr + 1;
1153 while (chptr > localarg && *chptr != '-') chptr--;
1154 if (chptr == localarg) return 1;
1157 return dbiFindMatches(dbi, dbcursor, localarg, chptr + 1, release, matches);
1161 * Rewrite a header in the database.
1162 * Note: this is called from a markReplacedFiles iteration, and *must*
1163 * preserve the "join key" (i.e. offset) for the header.
1164 * @param dbi index database handle (always RPMDBI_PACKAGES)
1165 * @param dbcursor index database cursor
1166 * @param offset join key
1167 * @param h rpm header
1168 * @return 0 on success
1170 static int dbiUpdateRecord(dbiIndex dbi, DBC * dbcursor, int offset, Header h)
1172 sigset_t signalMask;
1181 uhlen = headerSizeof(h, HEADER_MAGIC_NO);
1182 uh = headerUnload(h);
1183 blockSignals(dbi->dbi_rpmdb, &signalMask);
1184 rc = dbiPut(dbi, dbcursor, &offset, sizeof(offset), uh, uhlen, 0);
1185 xx = dbiSync(dbi, 0);
1186 unblockSignals(dbi->dbi_rpmdb, &signalMask);
1192 struct _rpmdbMatchIterator {
1193 /*@only@*/ const void * mi_keyp;
1195 /*@kept@*/ rpmdb mi_rpmdb;
1203 unsigned int mi_prevoffset;
1204 unsigned int mi_offset;
1205 unsigned int mi_filenum;
1206 unsigned int mi_fpnum;
1207 unsigned int mi_dbnum;
1208 /*@only@*/ const char *mi_version;
1209 /*@only@*/ const char *mi_release;
1212 void rpmdbFreeIterator(rpmdbMatchIterator mi)
1214 dbiIndex dbi = NULL;
1220 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
1222 if (mi->mi_modified && mi->mi_prevoffset) {
1223 DBC * dbcursor = NULL;
1224 xx = dbiCopen(dbi, &dbcursor, 0);
1225 dbiUpdateRecord(dbi, dbcursor, mi->mi_prevoffset, mi->mi_h);
1226 xx = dbiCclose(dbi, dbcursor, 0);
1229 headerFree(mi->mi_h);
1233 xx = dbiCclose(dbi, dbi->dbi_rmw, 0);
1234 dbi->dbi_rmw = NULL;
1237 if (mi->mi_release) {
1238 free((void *)mi->mi_release);
1239 mi->mi_release = NULL;
1241 if (mi->mi_version) {
1242 free((void *)mi->mi_version);
1243 mi->mi_version = NULL;
1246 xx = dbiCclose(dbi, mi->mi_dbc, 1);
1250 dbiFreeIndexSet(mi->mi_set);
1254 free((void *)mi->mi_keyp);
1260 rpmdb rpmdbGetIteratorRpmDB(rpmdbMatchIterator mi) {
1263 return mi->mi_rpmdb;
1266 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
1269 return mi->mi_offset;
1272 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
1275 return mi->mi_filenum;
1278 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
1279 if (!(mi && mi->mi_set))
1280 return 0; /* XXX W2DO? */
1281 return mi->mi_set->count;
1284 void rpmdbSetIteratorRelease(rpmdbMatchIterator mi, const char * release) {
1287 if (mi->mi_release) {
1288 free((void *)mi->mi_release);
1289 mi->mi_release = NULL;
1291 mi->mi_release = (release ? xstrdup(release) : NULL);
1294 void rpmdbSetIteratorVersion(rpmdbMatchIterator mi, const char * version) {
1297 if (mi->mi_version) {
1298 free((void *)mi->mi_version);
1299 mi->mi_version = NULL;
1301 mi->mi_version = (version ? xstrdup(version) : NULL);
1304 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified) {
1308 rc = mi->mi_modified;
1309 mi->mi_modified = modified;
1313 Header XrpmdbNextIterator(rpmdbMatchIterator mi, const char * f, unsigned l)
1326 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
1329 /* XXX cursors need to be per-iterator, not per-dbi. Get a cursor now. */
1330 if (mi->mi_dbc == NULL) {
1331 xx = XdbiCopen(dbi, &mi->mi_dbc, 1, f, l);
1333 dbi->dbi_lastoffset = mi->mi_prevoffset;
1336 /* XXX skip over instances with 0 join key */
1339 if (!(mi->mi_setx < mi->mi_set->count))
1341 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
1342 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
1343 keyp = &mi->mi_offset;
1344 keylen = sizeof(mi->mi_offset);
1346 keyp = (void *)mi->mi_keyp; /* XXX FIXME const */
1347 keylen = mi->mi_keylen;
1349 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, 0);
1352 * If we got the next key, save the header instance number.
1353 * For db1 Packages (db1->dbi_lastoffset != 0), always copy.
1354 * For db3 Packages, instance 0 (i.e. mi->mi_setx == 0) is the
1355 * largest header instance in the database, and should be
1358 if (rc == 0 && keyp && (dbi->dbi_lastoffset || mi->mi_setx))
1359 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
1361 /* Terminate on error or end of keys */
1362 if (rc || (mi->mi_setx && mi->mi_offset == 0))
1366 } while (mi->mi_offset == 0);
1368 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
1371 /* Retrieve next header */
1373 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, 0);
1378 /* Free current header */
1380 if (mi->mi_modified && mi->mi_prevoffset)
1381 dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
1382 headerFree(mi->mi_h);
1386 mi->mi_h = headerCopyLoad(uh);
1388 if (mi->mi_release) {
1389 const char *release;
1390 headerNVR(mi->mi_h, NULL, NULL, &release);
1391 if (strcmp(mi->mi_release, release))
1395 if (mi->mi_version) {
1396 const char *version;
1397 headerNVR(mi->mi_h, NULL, &version, NULL);
1398 if (strcmp(mi->mi_version, version))
1402 mi->mi_prevoffset = mi->mi_offset;
1403 mi->mi_modified = 0;
1408 const char *n, *v, *r;
1409 headerNVR(mi->mi_h, &n, &v, &r);
1410 rpmMessage(RPMMESS_DEBUG, "%s-%s-%s at 0x%x, h %p\n", n, v, r,
1411 mi->mi_offset, mi->mi_h);
1417 static void rpmdbSortIterator(rpmdbMatchIterator mi) {
1418 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
1419 qsort(mi->mi_set->recs, mi->mi_set->count, sizeof(*mi->mi_set->recs),
1425 static int rpmdbGrowIterator(rpmdbMatchIterator mi,
1426 const void * keyp, size_t keylen, int fpNum)
1428 dbiIndex dbi = NULL;
1429 DBC * dbcursor = NULL;
1430 dbiIndexSet set = NULL;
1437 dbi = dbiOpen(mi->mi_rpmdb, mi->mi_rpmtag, 0);
1442 keylen = strlen(keyp);
1444 xx = dbiCopen(dbi, &dbcursor, 0);
1445 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
1446 xx = dbiCclose(dbi, dbcursor, 0);
1449 if (rc == 0) { /* success */
1451 for (i = 0; i < set->count; i++)
1452 set->recs[i].fpNum = fpNum;
1454 if (mi->mi_set == NULL) {
1458 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
1459 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
1460 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
1461 set->count * sizeof(*(mi->mi_set->recs)));
1462 mi->mi_set->count += set->count;
1467 dbiFreeIndexSet(set);
1471 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
1472 int nHdrNums, int sorted)
1474 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
1478 dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
1482 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
1484 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
1487 if (mi->mi_set == NULL)
1488 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
1489 dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
1493 rpmdbMatchIterator rpmdbInitIterator(rpmdb rpmdb, int rpmtag,
1494 const void * keyp, size_t keylen)
1496 rpmdbMatchIterator mi = NULL;
1497 dbiIndexSet set = NULL;
1499 const void * mi_keyp = NULL;
1502 /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */
1505 rpmtag = RPMTAG_NAME;
1510 dbi = dbiOpen(rpmdb, rpmtag, 0);
1515 assert(dbi->dbi_rmw == NULL); /* db3: avoid "lost" cursors */
1516 assert(dbi->dbi_lastoffset == 0); /* db0: avoid "lost" cursors */
1519 fprintf(stderr, "*** RMW %s %p\n", tagName(rpmtag), dbi->dbi_rmw);
1522 dbi->dbi_lastoffset = 0; /* db0: rewind to beginning */
1524 if (rpmtag != RPMDBI_PACKAGES && keyp) {
1525 DBC * dbcursor = NULL;
1530 /* XXX HACK to get rpmdbFindByLabel out of the API */
1531 xx = dbiCopen(dbi, &dbcursor, 0);
1532 rc = dbiFindByLabel(dbi, dbcursor, keyp, &set);
1533 xx = dbiCclose(dbi, dbcursor, 0);
1535 } else if (rpmtag == RPMTAG_BASENAMES) {
1536 rc = rpmdbFindByFile(rpmdb, keyp, &set);
1538 xx = dbiCopen(dbi, &dbcursor, 0);
1539 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
1540 xx = dbiCclose(dbi, dbcursor, 0);
1543 if (rc) { /* error/not found */
1545 dbiFreeIndexSet(set);
1553 if (rpmtag != RPMDBI_PACKAGES && keylen == 0)
1554 keylen = strlen(keyp);
1555 k = xmalloc(keylen + 1);
1556 memcpy(k, keyp, keylen);
1557 k[keylen] = '\0'; /* XXX for strings */
1561 mi = xcalloc(1, sizeof(*mi));
1562 mi->mi_keyp = mi_keyp;
1563 mi->mi_keylen = keylen;
1565 mi->mi_rpmdb = rpmdb;
1566 mi->mi_rpmtag = rpmtag;
1573 mi->mi_modified = 0;
1574 mi->mi_prevoffset = 0;
1579 mi->mi_version = NULL;
1580 mi->mi_release = NULL;
1585 * Remove entry from database index.
1586 * @param dbi index database handle
1587 * @param dbcursor index database cursor
1588 * @param keyp search key
1589 * @param keylen search key length
1590 * @param rec record to remove
1591 * @return 0 on success
1593 static INLINE int removeIndexEntry(dbiIndex dbi, DBC * dbcursor,
1594 const void * keyp, size_t keylen, dbiIndexItem rec)
1596 dbiIndexSet set = NULL;
1599 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
1601 if (rc < 0) /* not found */
1603 else if (rc > 0) /* error */
1604 rc = 1; /* error message already generated from dbindex.c */
1605 else { /* success */
1606 if (!dbiPruneSet(set, rec, 1, sizeof(*rec), 1) &&
1607 dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
1612 dbiFreeIndexSet(set);
1619 /* XXX install.c uninstall.c */
1620 int rpmdbRemove(rpmdb rpmdb, int rid, unsigned int hdrNum)
1623 sigset_t signalMask;
1625 { rpmdbMatchIterator mi;
1626 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
1627 h = rpmdbNextIterator(mi);
1630 rpmdbFreeIterator(mi);
1634 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
1635 "rpmdbRemove", hdrNum);
1639 /* Add remove transaction id to header. */
1642 headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
1645 { const char *n, *v, *r;
1646 headerNVR(h, &n, &v, &r);
1647 rpmMessage(RPMMESS_DEBUG, " --- %10d %s-%s-%s\n", hdrNum, n, v, r);
1650 blockSignals(rpmdb, &signalMask);
1653 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
1655 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
1657 DBC * dbcursor = NULL;
1659 const char ** rpmvals = NULL;
1667 rpmtag = dbiTags[dbix];
1670 /* Filter out temporary databases */
1671 case RPMDBI_AVAILABLE:
1673 case RPMDBI_REMOVED:
1674 case RPMDBI_DEPENDS:
1676 /*@notreached@*/ break;
1677 case RPMDBI_PACKAGES:
1678 dbi = dbiOpen(rpmdb, rpmtag, 0);
1679 xx = dbiCopen(dbi, &dbcursor, 0);
1680 xx = dbiDel(dbi, dbcursor, &hdrNum, sizeof(hdrNum), 0);
1681 xx = dbiCclose(dbi, dbcursor, 0);
1683 /* XXX HACK sync is on the bt with multiple db access */
1684 if (!dbi->dbi_no_dbsync)
1685 xx = dbiSync(dbi, 0);
1687 /*@notreached@*/ break;
1690 if (!headerGetEntry(h, rpmtag, &rpmtype,
1691 (void **) &rpmvals, &rpmcnt))
1694 dbi = dbiOpen(rpmdb, rpmtag, 0);
1695 xx = dbiCopen(dbi, &dbcursor, 0);
1697 if (rpmtype == RPM_STRING_TYPE) {
1699 rpmMessage(RPMMESS_DEBUG, _("removing \"%s\" from %s index.\n"),
1700 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
1702 /* XXX force uniform headerGetEntry return */
1703 av[0] = (const char *) rpmvals;
1708 rpmMessage(RPMMESS_DEBUG, _("removing %d entries from %s index.\n"),
1709 rpmcnt, tagName(dbi->dbi_rpmtag));
1713 for (i = 0; i < rpmcnt; i++) {
1718 * This is almost right, but, if there are duplicate tag
1719 * values, there will be duplicate attempts to remove
1720 * the header instance. It's easier to just ignore errors
1721 * than to do things correctly.
1724 vallen = strlen(rpmvals[i]);
1725 xx = removeIndexEntry(dbi, dbcursor, valp, vallen, rec);
1728 xx = dbiCclose(dbi, dbcursor, 0);
1731 if (!dbi->dbi_no_dbsync)
1732 xx = dbiSync(dbi, 0);
1734 rpmvals = headerFreeData(rpmvals, rpmtype);
1745 unblockSignals(rpmdb, &signalMask);
1753 * Add entry to database index.
1754 * @param dbi index database handle
1755 * @param dbcursor index database cursor
1756 * @param keyp search key
1757 * @param keylen search key length
1758 * @param rec record to add
1759 * @return 0 on success
1761 static INLINE int addIndexEntry(dbiIndex dbi, DBC * dbcursor,
1762 const char * keyp, size_t keylen, dbiIndexItem rec)
1764 dbiIndexSet set = NULL;
1767 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
1772 if (rc < 0) { /* not found */
1774 set = xcalloc(1, sizeof(*set));
1776 dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
1777 if (dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
1782 dbiFreeIndexSet(set);
1790 int rpmdbAdd(rpmdb rpmdb, int iid, Header h)
1792 sigset_t signalMask;
1793 const char ** baseNames;
1798 unsigned int hdrNum;
1804 headerRemoveEntry(h, RPMTAG_REMOVETID);
1805 headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
1809 * If old style filename tags is requested, the basenames need to be
1810 * retrieved early, and the header needs to be converted before
1811 * being written to the package header database.
1814 headerGetEntry(h, RPMTAG_BASENAMES, &type, (void **) &baseNames, &count);
1819 blockSignals(rpmdb, &signalMask);
1822 unsigned int firstkey = 0;
1823 DBC * dbcursor = NULL;
1824 void * keyp = &firstkey;
1825 size_t keylen = sizeof(firstkey);
1826 void * datap = NULL;
1829 dbi = dbiOpen(rpmdb, RPMDBI_PACKAGES, 0);
1831 /* XXX db0: hack to pass sizeof header to fadAlloc */
1833 datalen = headerSizeof(h, HEADER_MAGIC_NO);
1835 xx = dbiCopen(dbi, &dbcursor, 0);
1837 /* Retrieve join key for next header instance. */
1839 rc = dbiGet(dbi, dbcursor, &keyp, &keylen, &datap, &datalen, 0);
1842 if (rc == 0 && datap)
1843 memcpy(&hdrNum, datap, sizeof(hdrNum));
1845 if (rc == 0 && datap) {
1846 memcpy(datap, &hdrNum, sizeof(hdrNum));
1849 datalen = sizeof(hdrNum);
1852 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, 0);
1853 xx = dbiSync(dbi, 0);
1855 xx = dbiCclose(dbi, dbcursor, 0);
1861 rpmError(RPMERR_DBCORRUPT,
1862 _("error(%d) allocating new package instance\n"), rc);
1866 /* Now update the indexes */
1868 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
1870 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
1871 DBC * dbcursor = NULL;
1873 const char **rpmvals = NULL;
1877 int_32 * requireFlags;
1881 requireFlags = NULL;
1882 rpmtag = dbiTags[dbix];
1885 /* Filter out temporary databases */
1886 case RPMDBI_AVAILABLE:
1888 case RPMDBI_REMOVED:
1889 case RPMDBI_DEPENDS:
1891 /*@notreached@*/ break;
1892 case RPMDBI_PACKAGES:
1893 dbi = dbiOpen(rpmdb, rpmtag, 0);
1894 xx = dbiCopen(dbi, &dbcursor, 0);
1895 xx = dbiUpdateRecord(dbi, dbcursor, hdrNum, h);
1896 xx = dbiCclose(dbi, dbcursor, 0);
1898 if (!dbi->dbi_no_dbsync)
1899 xx = dbiSync(dbi, 0);
1900 { const char *n, *v, *r;
1901 headerNVR(h, &n, &v, &r);
1902 rpmMessage(RPMMESS_DEBUG, " +++ %10d %s-%s-%s\n", hdrNum, n, v, r);
1905 /*@notreached@*/ break;
1906 /* XXX preserve legacy behavior */
1907 case RPMTAG_BASENAMES:
1909 rpmvals = baseNames;
1912 case RPMTAG_REQUIRENAME:
1913 headerGetEntry(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
1914 headerGetEntry(h, RPMTAG_REQUIREFLAGS, NULL,
1915 (void **)&requireFlags, NULL);
1918 headerGetEntry(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
1923 if (rpmtag != RPMTAG_GROUP)
1926 /* XXX preserve legacy behavior */
1927 rpmtype = RPM_STRING_TYPE;
1928 rpmvals = (const char **) "Unknown";
1932 dbi = dbiOpen(rpmdb, rpmtag, 0);
1934 xx = dbiCopen(dbi, &dbcursor, 0);
1935 if (rpmtype == RPM_STRING_TYPE) {
1936 rpmMessage(RPMMESS_DEBUG, _("adding \"%s\" to %s index.\n"),
1937 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
1939 /* XXX force uniform headerGetEntry return */
1940 av[0] = (const char *) rpmvals;
1945 rpmMessage(RPMMESS_DEBUG, _("adding %d entries to %s index.\n"),
1946 rpmcnt, tagName(dbi->dbi_rpmtag));
1950 for (i = 0; i < rpmcnt; i++) {
1955 * Include the tagNum in all indices. rpm-3.0.4 and earlier
1956 * included the tagNum only for files.
1958 switch (dbi->dbi_rpmtag) {
1959 case RPMTAG_REQUIRENAME:
1960 /* Filter out install prerequisites. */
1961 if (requireFlags && isInstallPreReq(requireFlags[i]))
1965 case RPMTAG_TRIGGERNAME:
1966 if (i) { /* don't add duplicates */
1967 for (j = 0; j < i; j++) {
1968 if (!strcmp(rpmvals[i], rpmvals[j]))
1982 vallen = strlen(rpmvals[i]);
1983 rc += addIndexEntry(dbi, dbcursor, valp, vallen, rec);
1985 xx = dbiCclose(dbi, dbcursor, 0);
1988 /* XXX HACK sync is on the bt with multiple db access */
1989 if (!dbi->dbi_no_dbsync)
1990 xx = dbiSync(dbi, 0);
1992 /*@-observertrans@*/
1993 rpmvals = headerFreeData(rpmvals, rpmtype);
1994 /*@=observertrans@*/
2006 unblockSignals(rpmdb, &signalMask);
2011 /* XXX transaction.c */
2012 int rpmdbFindFpList(rpmdb rpmdb, fingerPrint * fpList, dbiIndexSet * matchList,
2015 rpmdbMatchIterator mi;
2016 fingerPrintCache fpc;
2020 mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, NULL, 0);
2022 /* Gather all matches from the database */
2023 for (i = 0; i < numItems; i++) {
2024 rpmdbGrowIterator(mi, fpList[i].baseName, 0, i);
2025 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
2028 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
2029 rpmdbFreeIterator(mi);
2032 fpc = fpCacheCreate(i);
2034 rpmdbSortIterator(mi);
2035 /* iterator is now sorted by (recnum, filenum) */
2037 /* For each set of files matched in a package ... */
2038 while ((h = rpmdbNextIterator(mi)) != NULL) {
2039 const char ** dirNames;
2040 const char ** baseNames;
2041 const char ** fullBaseNames;
2042 int_32 * dirIndexes;
2043 int_32 * fullDirIndexes;
2050 start = mi->mi_setx - 1;
2051 im = mi->mi_set->recs + start;
2053 /* Find the end of the set of matched files in this package. */
2054 for (end = start + 1; end < mi->mi_set->count; end++) {
2055 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
2060 /* Compute fingerprints for this header's matches */
2061 headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
2062 (const void **) &fullBaseNames, NULL);
2063 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
2064 (const void **) &dirNames, NULL);
2065 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
2066 (const void **) &fullDirIndexes, NULL);
2068 baseNames = xcalloc(num, sizeof(*baseNames));
2069 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
2070 for (i = 0; i < num; i++) {
2071 baseNames[i] = fullBaseNames[im[i].tagNum];
2072 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
2075 fps = xcalloc(num, sizeof(*fps));
2076 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
2078 /* Add db (recnum,filenum) to list for fingerprint matches. */
2079 for (i = 0; i < num; i++, im++) {
2080 if (FP_EQUAL(fps[i], fpList[im->fpNum]))
2081 dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
2086 free(fullBaseNames);
2093 rpmdbFreeIterator(mi);
2101 char * db1basename (int rpmtag) {
2104 case RPMDBI_PACKAGES: base = "packages.rpm"; break;
2105 case RPMTAG_NAME: base = "nameindex.rpm"; break;
2106 case RPMTAG_BASENAMES: base = "fileindex.rpm"; break;
2107 case RPMTAG_GROUP: base = "groupindex.rpm"; break;
2108 case RPMTAG_REQUIRENAME: base = "requiredby.rpm"; break;
2109 case RPMTAG_PROVIDENAME: base = "providesindex.rpm"; break;
2110 case RPMTAG_CONFLICTNAME: base = "conflictsindex.rpm"; break;
2111 case RPMTAG_TRIGGERNAME: base = "triggerindex.rpm"; break;
2113 { const char * tn = tagName(rpmtag);
2114 base = alloca( strlen(tn) + sizeof(".idx") + 1 );
2115 (void) stpcpy( stpcpy(base, tn), ".idx");
2118 return xstrdup(base);
2121 static int rpmdbRemoveDatabase(const char * rootdir,
2122 const char * dbpath, int _dbapi)
2129 if (dbpath[i - 1] != '/') {
2130 filename = alloca(i);
2131 strcpy(filename, dbpath);
2133 filename[i + 1] = '\0';
2137 filename = alloca(strlen(rootdir) + strlen(dbpath) + 40);
2141 for (i = 0; i < dbiTagsMax; i++) {
2142 const char * base = tagName(dbiTags[i]);
2143 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
2144 (void)rpmCleanPath(filename);
2145 xx = unlink(filename);
2147 for (i = 0; i < 16; i++) {
2148 sprintf(filename, "%s/%s/__db.%03d", rootdir, dbpath, i);
2149 (void)rpmCleanPath(filename);
2150 xx = unlink(filename);
2156 for (i = 0; i < dbiTagsMax; i++) {
2157 const char * base = db1basename(dbiTags[i]);
2158 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
2159 (void)rpmCleanPath(filename);
2160 xx = unlink(filename);
2166 sprintf(filename, "%s/%s", rootdir, dbpath);
2167 (void)rpmCleanPath(filename);
2168 xx = rmdir(filename);
2173 static int rpmdbMoveDatabase(const char * rootdir,
2174 const char * olddbpath, int _olddbapi,
2175 const char * newdbpath, int _newdbapi)
2178 char * ofilename, * nfilename;
2182 i = strlen(olddbpath);
2183 if (olddbpath[i - 1] != '/') {
2184 ofilename = alloca(i + 2);
2185 strcpy(ofilename, olddbpath);
2187 ofilename[i + 1] = '\0';
2188 olddbpath = ofilename;
2191 i = strlen(newdbpath);
2192 if (newdbpath[i - 1] != '/') {
2193 nfilename = alloca(i + 2);
2194 strcpy(nfilename, newdbpath);
2196 nfilename[i + 1] = '\0';
2197 newdbpath = nfilename;
2200 ofilename = alloca(strlen(rootdir) + strlen(olddbpath) + 40);
2201 nfilename = alloca(strlen(rootdir) + strlen(newdbpath) + 40);
2203 switch (_olddbapi) {
2205 for (i = 0; i < dbiTagsMax; i++) {
2209 /* Filter out temporary databases */
2210 switch ((rpmtag = dbiTags[i])) {
2211 case RPMDBI_AVAILABLE:
2213 case RPMDBI_REMOVED:
2214 case RPMDBI_DEPENDS:
2216 /*@notreached@*/ break;
2221 base = tagName(rpmtag);
2222 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
2223 (void)rpmCleanPath(ofilename);
2224 if (!rpmfileexists(ofilename))
2226 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
2227 (void)rpmCleanPath(nfilename);
2228 if ((xx = Rename(ofilename, nfilename)) != 0)
2231 for (i = 0; i < 16; i++) {
2232 sprintf(ofilename, "%s/%s/__db.%03d", rootdir, olddbpath, i);
2233 (void)rpmCleanPath(ofilename);
2234 if (!rpmfileexists(ofilename))
2236 sprintf(nfilename, "%s/%s/__db.%03d", rootdir, newdbpath, i);
2237 (void)rpmCleanPath(nfilename);
2238 if ((xx = Rename(ofilename, nfilename)) != 0)
2245 for (i = 0; i < dbiTagsMax; i++) {
2249 /* Filter out temporary databases */
2250 switch ((rpmtag = dbiTags[i])) {
2251 case RPMDBI_AVAILABLE:
2253 case RPMDBI_REMOVED:
2254 case RPMDBI_DEPENDS:
2256 /*@notreached@*/ break;
2261 base = db1basename(rpmtag);
2262 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
2263 (void)rpmCleanPath(ofilename);
2264 if (!rpmfileexists(ofilename))
2266 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
2267 (void)rpmCleanPath(nfilename);
2268 if ((xx = Rename(ofilename, nfilename)) != 0)
2274 if (rc || _olddbapi == _newdbapi)
2277 rc = rpmdbRemoveDatabase(rootdir, newdbpath, _newdbapi);
2280 /* Remove /etc/rpm/macros.db1 configuration file if db3 rebuilt. */
2281 if (rc == 0 && _newdbapi == 1 && _olddbapi == 3) {
2282 const char * mdb1 = "/etc/rpm/macros.db1";
2284 if (!stat(mdb1, &st) && S_ISREG(st.st_mode) && !unlink(mdb1))
2285 rpmMessage(RPMMESS_DEBUG,
2286 _("removing %s after successful db3 rebuild.\n"), mdb1);
2291 int rpmdbRebuild(const char * rootdir)
2294 const char * dbpath = NULL;
2295 const char * rootdbpath = NULL;
2297 const char * newdbpath = NULL;
2298 const char * newrootdbpath = NULL;
2307 _dbapi = rpmExpandNumeric("%{_dbapi}");
2308 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
2310 tfn = rpmGetPath("%{_dbpath}", NULL);
2311 if (!(tfn && tfn[0] != '%')) {
2312 rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
2316 dbpath = rootdbpath = rpmGetPath(rootdir, tfn, NULL);
2317 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
2318 dbpath += strlen(rootdir);
2321 tfn = rpmGetPath("%{_dbpath_rebuild}", NULL);
2322 if (!(tfn && tfn[0] != '%' && strcmp(tfn, dbpath))) {
2325 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
2326 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
2327 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
2328 if (tfn) free((void *)tfn);
2332 newdbpath = newrootdbpath = rpmGetPath(rootdir, tfn, NULL);
2333 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
2334 newdbpath += strlen(rootdir);
2337 rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
2338 rootdbpath, newrootdbpath);
2340 if (!access(newrootdbpath, F_OK)) {
2341 rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
2347 rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
2348 if (Mkdir(newrootdbpath, 0755)) {
2349 rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
2350 newrootdbpath, strerror(errno));
2356 rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
2358 _rebuildinprogress = 1;
2359 if (openDatabase(rootdir, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
2360 RPMDB_FLAG_MINIMAL)) {
2364 _dbapi = olddb->db_api;
2365 _rebuildinprogress = 0;
2367 rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
2369 if (openDatabase(rootdir, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
2373 _dbapi_rebuild = newdb->db_api;
2376 rpmdbMatchIterator mi;
2377 #define _RECNUM rpmdbGetIteratorOffset(mi)
2379 /* RPMDBI_PACKAGES */
2380 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
2381 while ((h = rpmdbNextIterator(mi)) != NULL) {
2383 /* let's sanity check this record a bit, otherwise just skip it */
2384 if (!(headerIsEntry(h, RPMTAG_NAME) &&
2385 headerIsEntry(h, RPMTAG_VERSION) &&
2386 headerIsEntry(h, RPMTAG_RELEASE) &&
2387 headerIsEntry(h, RPMTAG_BUILDTIME)))
2389 rpmError(RPMERR_INTERNAL,
2390 _("record number %d in database is bad -- skipping.\n"),
2395 /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
2396 if (_db_filter_dups || newdb->db_filter_dups) {
2397 const char * name, * version, * release;
2400 headerNVR(h, &name, &version, &release);
2403 { rpmdbMatchIterator mi;
2404 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
2405 rpmdbSetIteratorVersion(mi, version);
2406 rpmdbSetIteratorRelease(mi, release);
2407 while (rpmdbNextIterator(mi)) {
2411 rpmdbFreeIterator(mi);
2419 /* Deleted entries are eliminated in legacy headers by copy. */
2420 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
2421 ? headerCopy(h) : NULL);
2422 rc = rpmdbAdd(newdb, -1, (nh ? nh : h));
2428 rpmError(RPMERR_INTERNAL,
2429 _("cannot add record originally at %d\n"), _RECNUM);
2435 rpmdbFreeIterator(mi);
2440 olddb->db_remove_env = 1;
2441 newdb->db_remove_env = 1;
2447 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
2448 "remains in place\n"));
2450 rpmdbRemoveDatabase(rootdir, newdbpath, _dbapi_rebuild);
2453 } else if (!nocleanup) {
2454 if (rpmdbMoveDatabase(rootdir, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
2455 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
2457 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
2458 "to recover"), dbpath, newdbpath);
2466 if (removedir && !(rc == 0 && nocleanup)) {
2467 rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
2468 if (Rmdir(newrootdbpath))
2469 rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
2470 newrootdbpath, strerror(errno));
2472 if (newrootdbpath) free((void *)newrootdbpath);
2473 if (rootdbpath) free((void *)rootdbpath);