5 static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
9 #if defined(HAVE_FTOK) && defined(HAVE_SYS_IPC_H)
17 #include <rpmurl.h> /* XXX urlPath proto */
25 /*@access dbiIndexSet@*/
28 * Hash database statistics.
32 unsigned int hash_magic; /*!< hash database magic number. */
33 unsigned int hash_version; /*!< version of the hash database. */
34 unsigned int hash_nkeys; /*!< no. of unique keys in the database. */
35 unsigned int hash_ndata; /*!< no. of key/data pairs in the database. */
36 unsigned int hash_pagesize; /*!< db page (and bucket) size, in bytes. */
37 unsigned int hash_nelem; /*!< estimated size of the hash table. */
38 unsigned int hash_ffactor; /*!< no. of items per bucket. */
39 unsigned int hash_buckets; /*!< no. of hash buckets. */
40 unsigned int hash_free; /*!< no. of pages on the free list. */
41 unsigned int hash_bfree; /*!< no. of bytes free on bucket pages. */
42 unsigned int hash_bigpages; /*!< no. of big key/data pages. */
43 unsigned int hash_big_bfree;/*!< no. of bytes free on big item pages. */
44 unsigned int hash_overflows;/*!< no. of overflow pages. */
45 unsigned int hash_ovfl_free;/*!< no. of bytes free on overflow pages. */
46 unsigned int hash_dup; /*!< no. of duplicate pages. */
47 unsigned int hash_dup_free; /*!< no. bytes free on duplicate pages. */
51 * B-tree database statistics.
54 unsigned int bt_magic; /*!< btree database magic. */
55 unsigned int bt_version; /*!< version of the btree database. */
56 unsigned int bt_nkeys; /*!< no. of unique keys in the database. */
57 unsigned int bt_ndata; /*!< no. of key/data pairs in the database. */
58 unsigned int bt_pagesize; /*!< database page size, in bytes. */
59 unsigned int bt_minkey; /*!< minimum keys per page. */
60 unsigned int bt_re_len; /*!< length of fixed-length records. */
61 unsigned int bt_re_pad; /*!< padding byte for fixed-length records. */
62 unsigned int bt_levels; /*!< no. of levels in the database. */
63 unsigned int bt_int_pg; /*!< no. of database internal pages. */
64 unsigned int bt_leaf_pg; /*!< no. of database leaf pages. */
65 unsigned int bt_dup_pg; /*!< no. of database duplicate pages. */
66 unsigned int bt_over_pg; /*!< no. of database overflow pages. */
67 unsigned int bt_free; /*!< no. of pages on the free list. */
68 unsigned int bt_int_pgfree; /*!< no. of bytes free in internal pages. */
69 unsigned int bt_leaf_pgfree;/*!< no. of bytes free in leaf pages. */
70 unsigned int bt_dup_pgfree; /*!< no. of bytes free in duplicate pages. */
71 unsigned int bt_over_pgfree;/*!< no. of bytes free in overflow pages. */
75 static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
76 /*@modifies fileSystem @*/
84 rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
85 dbi->dbi_api, rc, msg, db_strerror(error));
87 rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
88 dbi->dbi_api, rc, db_strerror(error));
94 static int db_fini(dbiIndex dbi, const char * dbhome,
95 /*@null@*/ const char * dbfile,
96 /*@unused@*/ /*@null@*/ const char * dbsubfile)
97 /*@modifies dbi, fileSystem @*/
99 rpmdb rpmdb = dbi->dbi_rpmdb;
100 DB_ENV * dbenv = dbi->dbi_dbenv;
104 dbi->dbi_dbenv = NULL;
108 rc = dbenv->close(dbenv, 0);
109 rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
112 rpmMessage(RPMMESS_DEBUG, _("closed db environment %s/%s\n"),
115 if (rpmdb->db_remove_env || dbi->dbi_tear_down) {
118 xx = db_env_create(&dbenv, 0);
119 xx = cvtdberr(dbi, "db_env_create", rc, _debug);
120 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0
121 xx = dbenv->remove(dbenv, dbhome, 0);
123 xx = dbenv->remove(dbenv, dbhome, NULL, 0);
125 xx = cvtdberr(dbi, "dbenv->remove", rc, _debug);
128 rpmMessage(RPMMESS_DEBUG, _("removed db environment %s/%s\n"),
132 dbi->dbi_dbenv = NULL;
136 static int db3_fsync_disable(/*@unused@*/ int fd)
142 static int db_init(dbiIndex dbi, const char * dbhome,
143 /*@null@*/ const char * dbfile,
144 /*@unused@*/ /*@null@*/ const char * dbsubfile,
145 /*@out@*/ DB_ENV ** dbenvp)
146 /*@modifies dbi, *dbenvp, fileSystem @*/
148 rpmdb rpmdb = dbi->dbi_rpmdb;
149 DB_ENV *dbenv = NULL;
158 if (rpmdb->db_errfile == NULL)
159 rpmdb->db_errfile = stderr;
162 eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
163 if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
166 rpmMessage(RPMMESS_DEBUG, _("opening db environment %s/%s %s\n"),
167 dbhome, dbfile, prDbiOpenFlags(eflags, 1));
169 /* XXX Can't do RPC w/o host. */
170 if (dbi->dbi_host == NULL)
171 dbi->dbi_ecflags &= ~DB_CLIENT;
173 /* XXX Set a default shm_key. */
174 if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
175 #if defined(HAVE_FTOK)
176 dbi->dbi_shmkey = ftok(dbhome, 0);
178 dbi->dbi_shmkey = 0x44631380;
182 rc = db_env_create(&dbenv, dbi->dbi_ecflags);
183 rc = cvtdberr(dbi, "db_env_create", rc, _debug);
191 dbenv->set_errcall(dbenv, rpmdb->db_errcall);
192 dbenv->set_errfile(dbenv, rpmdb->db_errfile);
193 dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
194 /* dbenv->set_paniccall(???) */
195 (void) dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
196 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
197 (void) dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
198 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
199 (void) dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
200 (dbi->dbi_verbose & DB_VERB_RECOVERY));
201 (void) dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
202 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
203 /* dbenv->set_lg_max(???) */
204 /* dbenv->set_lk_conflicts(???) */
205 /* dbenv->set_lk_detect(???) */
206 /* dbenv->set_lk_max(???) */
207 xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mp_mmapsize);
208 xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
209 xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_mp_size, 0);
210 xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
211 /* dbenv->set_tx_max(???) */
212 /* dbenv->set_tx_recover(???) */
213 if (dbi->dbi_no_fsync) {
214 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0
215 xx = db_env_set_func_fsync(db3_fsync_disable);
217 xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable);
219 xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
222 /* XXX 3.3.4 change. */
223 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3
224 if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
225 xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
226 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
227 xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
230 if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
231 xx = dbenv->set_server(dbenv, dbi->dbi_host,
232 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
233 xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
236 if (dbi->dbi_shmkey) {
237 xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
238 xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
240 if (dbi->dbi_tmpdir) {
244 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
245 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
247 tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
248 xx = dbenv->set_tmp_dir(dbenv, tmpdir);
249 xx = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
250 tmpdir = _free(tmpdir);
254 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0
255 rc = dbenv->open(dbenv, dbhome, eflags, dbi->dbi_perms);
257 rc = dbenv->open(dbenv, dbhome, NULL, eflags, dbi->dbi_perms);
259 rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
270 xx = dbenv->close(dbenv, 0);
271 xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
276 static int db3sync(dbiIndex dbi, unsigned int flags)
277 /*@modifies fileSystem @*/
279 DB * db = dbi->dbi_db;
284 rc = db->sync(db, flags);
285 /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
286 _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
287 rc = cvtdberr(dbi, "db->sync", rc, _printit);
291 static int db3c_del(dbiIndex dbi, DBC * dbcursor, u_int32_t flags)
292 /*@modifies fileSystem @*/
296 rc = dbcursor->c_del(dbcursor, flags);
297 rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
301 /*@unused@*/ static int db3c_dup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
303 /*@modifies *dbcp, fileSystem @*/
307 if (dbcp) *dbcp = NULL;
308 rc = dbcursor->c_dup(dbcursor, dbcp, flags);
309 rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
313 static int db3c_get(dbiIndex dbi, DBC * dbcursor,
314 DBT * key, DBT * data, u_int32_t flags)
315 /*@modifies fileSystem @*/
322 if ((dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
328 rc = dbcursor->c_get(dbcursor, key, data, rmw | flags);
330 /* XXX DB_NOTFOUND can be returned */
331 _printit = (rc == DB_NOTFOUND ? 0 : _debug);
332 rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
336 static int db3c_put(dbiIndex dbi, DBC * dbcursor,
337 DBT * key, DBT * data, u_int32_t flags)
338 /*@modifies fileSystem @*/
342 rc = dbcursor->c_put(dbcursor, key, data, flags);
344 rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
348 static inline int db3c_close(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor)
349 /*@modifies fileSystem @*/
353 if (dbcursor == NULL) return -2;
355 rc = dbcursor->c_close(dbcursor);
356 rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
360 static inline int db3c_open(dbiIndex dbi, /*@null@*/ /*@out@*/ DBC ** dbcp,
362 /*@modifies *dbcp, fileSystem @*/
364 DB * db = dbi->dbi_db;
365 DB_TXN * txnid = NULL;
369 if (db == NULL) return -2;
370 if ((dbiflags & DBI_WRITECURSOR) &&
371 (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
373 flags = DB_WRITECURSOR;
376 if (dbcp) *dbcp = NULL;
377 rc = db->cursor(db, txnid, dbcp, flags);
378 rc = cvtdberr(dbi, "db3c_open", rc, _debug);
383 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
385 /*@modifies dbi, fileSystem @*/
389 /* XXX per-iterator cursors */
390 if (flags & DBI_ITERATOR)
391 return db3c_close(dbi, dbcursor);
393 if (!dbi->dbi_use_cursors)
396 if (dbcursor == NULL)
397 dbcursor = dbi->dbi_rmw;
399 if (dbcursor == dbi->dbi_rmw)
401 rc = db3c_close(dbi, dbcursor);
403 /*@-usereleased -compdef@*/ return rc; /*@=usereleased =compdef@*/
406 static int db3copen(dbiIndex dbi,
407 /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int flags)
408 /*@modifies dbi, *dbcp, fileSystem @*/
413 /* XXX per-iterator cursors */
414 if (flags & DBI_ITERATOR)
415 return db3c_open(dbi, dbcp, flags);
417 if (!dbi->dbi_use_cursors) {
418 if (dbcp) *dbcp = NULL;
422 if ((dbcursor = dbi->dbi_rmw) == NULL) {
423 if ((rc = db3c_open(dbi, &dbcursor, flags)) == 0)
424 dbi->dbi_rmw = dbcursor;
428 /*@-onlytrans@*/ *dbcp = dbi->dbi_rmw; /*@=onlytrans@*/
433 static int db3cput(dbiIndex dbi, DBC * dbcursor,
434 const void * keyp, size_t keylen,
435 const void * datap, size_t datalen,
436 /*@unused@*/ unsigned int flags)
437 /*@modifies fileSystem @*/
439 DB * db = dbi->dbi_db;
440 DB_TXN * txnid = NULL;
444 memset(&key, 0, sizeof(key));
445 memset(&data, 0, sizeof(data));
446 key.data = (void *)keyp;
448 data.data = (void *)datap;
451 if (dbcursor == NULL) {
452 if (db == NULL) return -2;
453 rc = db->put(db, txnid, &key, &data, 0);
454 rc = cvtdberr(dbi, "db->put", rc, _debug);
457 rc = db3c_put(dbi, dbcursor, &key, &data, DB_KEYLAST);
464 static int db3cdel(dbiIndex dbi, DBC * dbcursor,
465 const void * keyp, size_t keylen,
466 /*@unused@*/ unsigned int flags)
467 /*@modifies fileSystem @*/
469 DB * db = dbi->dbi_db;
470 DB_TXN * txnid = NULL;
474 memset(&key, 0, sizeof(key));
475 memset(&data, 0, sizeof(data));
477 key.data = (void *)keyp;
480 if (dbcursor == NULL) {
481 if (db == NULL) return -2;
482 rc = db->del(db, txnid, &key, 0);
483 rc = cvtdberr(dbi, "db->del", rc, _debug);
486 rc = db3c_get(dbi, dbcursor, &key, &data, DB_SET);
489 /* XXX TODO: loop over duplicates */
490 rc = db3c_del(dbi, dbcursor, 0);
498 static int db3cget(dbiIndex dbi, DBC * dbcursor,
499 /*@null@*/ void ** keyp, /*@null@*/ size_t * keylen,
500 /*@null@*/ void ** datap, /*@null@*/ size_t * datalen,
501 /*@unused@*/ unsigned int flags)
502 /*@modifies *keyp, *keylen, *datap, *datalen, fileSystem @*/
504 DB * db = dbi->dbi_db;
505 DB_TXN * txnid = NULL;
509 memset(&key, 0, sizeof(key));
510 memset(&data, 0, sizeof(data));
511 /*@-unqualifiedtrans@*/
512 if (keyp) key.data = *keyp;
513 if (keylen) key.size = *keylen;
514 if (datap) data.data = *datap;
515 if (datalen) data.size = *datalen;
516 /*@=unqualifiedtrans@*/
518 if (dbcursor == NULL) {
521 if (db == NULL) return -2;
523 rc = db->get(db, txnid, &key, &data, 0);
524 /* XXX DB_NOTFOUND can be returned */
525 _printit = (rc == DB_NOTFOUND ? 0 : _debug);
526 rc = cvtdberr(dbi, "db->get", rc, _printit);
529 /* XXX db3 does DB_FIRST on uninitialized cursor */
530 rc = db3c_get(dbi, dbcursor, &key, &data,
531 key.data == NULL ? DB_NEXT : DB_SET);
537 if (keyp) *keyp = key.data;
538 if (keylen) *keylen = key.size;
539 if (datap) *datap = data.data;
540 if (datalen) *datalen = data.size;
544 /*@-compmempass -nullstate@*/
546 /*@=compmempass =nullstate@*/
549 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
550 /*@null@*/ /*@out@*/ unsigned int * countp,
551 /*@unused@*/ unsigned int flags)
552 /*@modifies *countp, fileSystem @*/
554 db_recno_t count = 0;
558 rc = dbcursor->c_count(dbcursor, &count, flags);
559 rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
561 if (countp) *countp = count;
566 static int db3byteswapped(dbiIndex dbi) /*@*/
568 DB * db = dbi->dbi_db;
572 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11
574 rc = db->get_byteswapped(db, &isswapped);
578 rc = db->get_byteswapped(db);
585 static int db3stat(dbiIndex dbi, unsigned int flags)
586 /*@modifies dbi, fileSystem @*/
588 DB * db = dbi->dbi_db;
591 if (db == NULL) return -2;
592 #if defined(DB_FAST_STAT)
594 flags = DB_FAST_STAT;
598 dbi->dbi_stats = _free(dbi->dbi_stats);
599 /* XXX 3.3.4 change. */
600 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3
601 rc = db->stat(db, &dbi->dbi_stats, flags);
603 rc = db->stat(db, &dbi->dbi_stats, NULL, flags);
605 rc = cvtdberr(dbi, "db->stat", rc, _debug);
609 /** @todo Add/use per-rpmdb verify_on_close. */
610 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
611 /*@modifies dbi, fileSystem @*/
613 rpmdb rpmdb = dbi->dbi_rpmdb;
614 const char * urlfn = NULL;
619 const char * dbsubfile;
620 DB * db = dbi->dbi_db;
623 flags = 0; /* XXX unused */
626 * Get the prefix/root component and directory path.
628 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
629 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
631 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
634 * Either the root or directory components may be a URL. Concatenate,
635 * convert the URL to a path, and add the name of the file.
637 urlfn = rpmGenPath(root, home, NULL);
638 (void) urlPath(urlfn, &dbhome);
639 if (dbi->dbi_temporary) {
644 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
645 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
647 dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
653 rc = db3cclose(dbi, NULL, 0);
656 rc = db->close(db, 0);
657 rc = cvtdberr(dbi, "db->close", rc, _debug);
658 db = dbi->dbi_db = NULL;
660 rpmMessage(RPMMESS_DEBUG, _("closed db index %s/%s\n"),
661 dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
665 dbi->dbi_dbinfo = _free(dbi->dbi_dbinfo);
667 if (dbi->dbi_use_dbenv) {
669 xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
673 if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
674 DB_ENV * dbenv = NULL;
676 rc = db_env_create(&dbenv, 0);
677 rc = cvtdberr(dbi, "db_env_create", rc, _debug);
678 if (rc || dbenv == NULL) goto exit;
680 if (dbi->dbi_tmpdir) {
681 const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
682 rc = dbenv->set_tmp_dir(dbenv, tmpdir);
683 rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
684 tmpdir = _free(tmpdir);
688 rc = dbenv->open(dbenv, dbhome,
689 DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0);
690 rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
693 rc = db_create(&db, dbenv, 0);
694 rc = cvtdberr(dbi, "db_create", rc, _debug);
697 const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
699 rc = db->verify(db, dbf, NULL, NULL, flags);
700 rc = cvtdberr(dbi, "db->verify", rc, _debug);
702 rpmMessage(RPMMESS_DEBUG, _("verified db index %s/%s\n"),
703 (dbhome ? dbhome : ""),
704 (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
706 xx = db->close(db, 0);
707 xx = cvtdberr(dbi, "db->close", xx, _debug);
709 if (rc == 0 && xx) rc = xx;
713 xx = dbenv->close(dbenv, 0);
714 xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
715 if (rc == 0 && xx) rc = xx;
721 urlfn = _free(urlfn);
728 static int db3open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
729 /*@modifies *dbip, fileSystem @*/
732 extern struct _dbiVec db3vec;
734 const char * urlfn = NULL;
739 const char * dbsubfile;
745 DB_ENV * dbenv = NULL;
746 DB_TXN * txnid = NULL;
754 * Parse db configuration parameters.
756 if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
760 dbi->dbi_api = DB_VERSION_MAJOR;
763 * Get the prefix/root component and directory path.
765 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
766 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
768 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
771 * Either the root or directory components may be a URL. Concatenate,
772 * convert the URL to a path, and add the name of the file.
774 urlfn = rpmGenPath(root, home, NULL);
775 (void) urlPath(urlfn, &dbhome);
776 if (dbi->dbi_temporary) {
781 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
782 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
784 dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
789 oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
790 oflags &= ~DB_TRUNCATE; /* XXX this is dangerous */
792 #if 0 /* XXX rpmdb: illegal flag combination specified to DB->open */
793 if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
797 * Map open mode flags onto configured database/environment flags.
799 if (dbi->dbi_temporary) {
801 dbi->dbi_oeflags |= DB_CREATE;
802 oflags &= ~DB_RDONLY;
803 dbi->dbi_oflags &= ~DB_RDONLY;
805 if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
806 if (dbi->dbi_mode & O_CREAT) {
808 dbi->dbi_oeflags |= DB_CREATE;
811 if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE;
816 * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open.
818 if (dbi->dbi_use_dbenv) {
819 if (access(dbhome, W_OK) == -1) {
821 /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */
822 oflags &= ~DB_CREATE;
824 /* ... but DBENV->open might still need DB_CREATE ... */
825 if (dbi->dbi_eflags & DB_PRIVATE) {
826 dbi->dbi_eflags &= ~DB_JOINENV;
828 dbi->dbi_eflags |= DB_JOINENV;
829 dbi->dbi_oeflags &= ~DB_CREATE;
830 dbi->dbi_oeflags &= ~DB_THREAD;
831 /* ... but, unless DB_PRIVATE is used, skip DBENV. */
832 dbi->dbi_use_dbenv = 0;
835 /* ... DB_RDONLY maps dphome perms across files ... */
836 if (dbi->dbi_temporary) {
838 dbi->dbi_oeflags |= DB_CREATE;
839 oflags &= ~DB_RDONLY;
840 dbi->dbi_oflags &= ~DB_RDONLY;
843 /* ... and DB_WRITECURSOR won't be needed ... */
844 dbi->dbi_oflags |= DB_RDONLY;
847 } else { /* dbhome is writable, check for persistent dbenv. */
848 const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
850 if (access(dbf, F_OK) == -1) {
851 /* ... non-existent (or unwritable) DBENV, will create ... */
852 dbi->dbi_oeflags |= DB_CREATE;
853 dbi->dbi_eflags &= ~DB_JOINENV;
855 /* ... pre-existent (or bogus) DBENV, will join ... */
856 dbi->dbi_oeflags &= ~DB_CREATE;
857 dbi->dbi_eflags |= DB_JOINENV;
864 * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open.
866 if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
867 /* dbhome is writable, and DB->open flags may conflict. */
868 const char * dbfn = (dbfile ? dbfile : tagName(dbi->dbi_rpmtag));
869 const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
871 if (access(dbf, F_OK) == -1) {
872 /* File does not exist, DB->open might create ... */
873 oflags &= ~DB_RDONLY;
875 /* File exists, DB->open need not create ... */
876 oflags &= ~DB_CREATE;
879 /* Only writers need DB_WRITECURSOR ... */
880 if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
881 dbi->dbi_oflags &= ~DB_RDONLY;
883 dbi->dbi_oflags |= DB_RDONLY;
889 * Turn off verify-on-close if opening read-only.
891 if (oflags & DB_RDONLY)
892 dbi->dbi_verify_on_close = 0;
894 dbi->dbi_dbinfo = NULL;
896 if (dbi->dbi_use_dbenv)
897 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
899 rpmMessage(RPMMESS_DEBUG, _("opening db index %s/%s %s mode=0x%x\n"),
900 dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)),
901 prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
904 static int _lockdbfd = 0;
906 rc = db_create(&db, dbenv, dbi->dbi_cflags);
907 rc = cvtdberr(dbi, "db_create", rc, _debug);
908 if (rc == 0 && db != NULL) {
909 if (rc == 0 && dbi->dbi_lorder) {
910 rc = db->set_lorder(db, dbi->dbi_lorder);
911 rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
913 if (rc == 0 && dbi->dbi_cachesize) {
914 rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0);
915 rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug);
917 if (rc == 0 && dbi->dbi_pagesize) {
918 rc = db->set_pagesize(db, dbi->dbi_pagesize);
919 rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
921 /* XXX 3.3.4 change. */
922 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3
924 rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
926 rc = db->set_alloc(db,
927 rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
928 rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
931 if (rc == 0 && rpmdb->db_malloc) {
932 rc = db->set_malloc(db, rpmdb->db_malloc);
933 rc = cvtdberr(dbi, "db->set_malloc", rc, _debug);
936 if (rc == 0 && oflags & DB_CREATE) {
937 switch(dbi->dbi_type) {
940 if (dbi->dbi_h_ffactor) {
941 rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor);
942 rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug);
945 if (dbi->dbi_h_nelem) {
946 rc = db->set_h_nelem(db, dbi->dbi_h_nelem);
947 rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug);
950 if (dbi->dbi_h_flags) {
951 rc = db->set_flags(db, dbi->dbi_h_flags);
952 rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug);
955 /* XXX db-3.2.9 has added a DB arg to the call. */
956 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2
957 if (dbi->dbi_h_hash_fcn) {
958 rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn);
959 rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug);
962 if (dbi->dbi_h_dup_compare_fcn) {
963 rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn);
964 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
970 if (dbi->dbi_bt_flags) {
971 rc = db->set_flags(db, dbi->dbi_bt_flags);
972 rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
975 if (dbi->dbi_bt_minkey) {
976 rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey);
977 rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug);
980 /* XXX db-3.2.9 has added a DB arg to the call. */
981 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2
982 if (dbi->dbi_bt_compare_fcn) {
983 rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn);
984 rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug);
987 if (dbi->dbi_bt_dup_compare_fcn) {
988 rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn);
989 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
992 if (dbi->dbi_bt_prefix_fcn) {
993 rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn);
994 rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug);
1000 if (dbi->dbi_re_delim) {
1001 rc = db->set_re_delim(db, dbi->dbi_re_delim);
1002 rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
1005 if (dbi->dbi_re_len) {
1006 rc = db->set_re_len(db, dbi->dbi_re_len);
1007 rc = cvtdberr(dbi, "db->set_re_len", rc, _debug);
1010 if (dbi->dbi_re_pad) {
1011 rc = db->set_re_pad(db, dbi->dbi_re_pad);
1012 rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug);
1015 if (dbi->dbi_re_source) {
1016 rc = db->set_re_source(db, dbi->dbi_re_source);
1017 rc = cvtdberr(dbi, "db->set_re_source", rc, _debug);
1022 if (dbi->dbi_q_extentsize) {
1023 rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize);
1024 rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug);
1030 dbi->dbi_dbinfo = NULL;
1033 const char * dbfullpath;
1034 const char * dbpath;
1038 nb = strlen(dbhome);
1039 if (dbfile) nb += 1 + strlen(dbfile);
1040 dbfullpath = t = alloca(nb + 1);
1042 t = stpcpy(t, dbhome);
1044 t = stpcpy( stpcpy( t, "/"), dbfile);
1045 dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
1046 ? dbfullpath : dbfile;
1048 rc = db->open(db, dbpath, dbsubfile,
1049 dbi->dbi_type, oflags, dbi->dbi_perms);
1051 if (rc == 0 && dbi->dbi_type == DB_UNKNOWN) {
1052 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11
1053 DBTYPE dbi_type = DB_UNKNOWN;
1054 xx = db->get_type(db, &dbi_type);
1056 dbi->dbi_type = dbi_type;
1058 dbi->dbi_type = db->get_type(db);
1063 /* XXX return rc == errno without printing */
1064 _printit = (rc > 0 ? 0 : _debug);
1065 xx = cvtdberr(dbi, "db->open", rc, _printit);
1067 if (rc == 0 && dbi->dbi_use_dbenv
1068 && (dbi->dbi_eflags & DB_INIT_CDB) && dbi->dbi_get_rmw_cursor)
1070 DBC * dbcursor = NULL;
1071 xx = db->cursor(db, txnid, &dbcursor,
1072 ((oflags & DB_RDONLY) ? 0 : DB_WRITECURSOR));
1073 xx = cvtdberr(dbi, "db->cursor", xx, _debug);
1074 dbi->dbi_rmw = dbcursor;
1076 dbi->dbi_rmw = NULL;
1079 * Lock a file using fcntl(2). Traditionally this is Packages,
1080 * the file used * to store metadata of installed header(s),
1081 * as Packages is always opened, and should be opened first,
1082 * for any rpmdb access.
1084 * If no DBENV is used, then access is protected with a
1085 * shared/exclusive locking scheme, as always.
1087 * With a DBENV, the fcntl(2) lock is necessary only to keep
1088 * the riff-raff from playing where they don't belong, as
1089 * the DBENV should provide it's own locking scheme. So try to
1090 * acquire a lock, but permit failures, as some other
1091 * DBENV player may already have acquired the lock.
1093 if (rc == 0 && dbi->dbi_lockdbfd &&
1094 (!dbi->dbi_use_dbenv || _lockdbfd++ == 0))
1098 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
1102 memset(&l, 0, sizeof(l));
1106 l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY))
1107 ? F_WRLCK : F_RDLCK;
1110 rc = fcntl(fdno, F_SETLK, (void *) &l);
1112 /* Warning only if using CDB locking. */
1113 rc = ((dbi->dbi_use_dbenv &&
1114 (dbi->dbi_eflags & DB_INIT_CDB))
1116 rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK),
1117 _("cannot get %s lock on %s/%s\n"),
1118 ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
1119 ? _("exclusive") : _("shared")),
1120 dbhome, (dbfile ? dbfile : ""));
1121 } else if (dbfile) {
1122 rpmMessage(RPMMESS_DEBUG,
1123 _("locked db index %s/%s\n"),
1132 dbi->dbi_dbenv = dbenv;
1134 if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
1135 dbi->dbi_vec = &db3vec;
1138 dbi->dbi_verify_on_close = 0;
1139 (void) db3close(dbi, 0);
1142 urlfn = _free(urlfn);
1151 /*@-exportheadervar@*/
1152 struct _dbiVec db3vec = {
1153 DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
1154 db3open, db3close, db3sync, db3copen, db3cclose, db3cdel, db3cget, db3cput,
1155 db3ccount, db3byteswapped, db3stat
1157 /*@=exportheadervar@*/