/** \ingroup db3 * \file lib/db3.c */ static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */ #include "system.h" #if defined(HAVE_FTOK) && defined(HAVE_SYS_IPC_H) #include #endif #include #include #include #include #include "lib/rpmdb_internal.h" #include "debug.h" static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit) { if (printit && error) { int db_api = dbi->dbi_rpmdb->db_api; if (msg) rpmlog(RPMLOG_ERR, _("db%d error(%d) from %s: %s\n"), db_api, error, msg, db_strerror(error)); else rpmlog(RPMLOG_ERR, _("db%d error(%d): %s\n"), db_api, error, db_strerror(error)); } return error; } static int db_fini(dbiIndex dbi, const char * dbhome) { rpmdb rpmdb = dbi->dbi_rpmdb; DB_ENV * dbenv = rpmdb->db_dbenv; int rc; if (dbenv == NULL) return 0; rc = dbenv->close(dbenv, 0); rc = cvtdberr(dbi, "dbenv->close", rc, _debug); rpmlog(RPMLOG_DEBUG, "closed db environment %s\n", dbhome); if (rpmdb->db_remove_env) { int xx; xx = db_env_create(&dbenv, 0); xx = cvtdberr(dbi, "db_env_create", xx, _debug); xx = dbenv->remove(dbenv, dbhome, 0); /* filter out EBUSY as it just means somebody else gets to clean it */ xx = cvtdberr(dbi, "dbenv->remove", xx, (xx == EBUSY ? 0 : _debug)); rpmlog(RPMLOG_DEBUG, "removed db environment %s\n", dbhome); } return rc; } static int db3_fsync_disable(int fd) { return 0; } #if (DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 5) /* * dbenv->failchk() callback method for determining is the given pid/tid * is alive. We only care about pid's though. */ static int db3isalive(DB_ENV *dbenv, pid_t pid, db_threadid_t tid, uint32_t flags) { int alive = 0; if (pid == getpid()) { alive = 1; } else if (kill(pid, 0) == 0) { alive = 1; /* only existing processes can fail with EPERM */ } else if (errno == EPERM) { alive = 1; } return alive; } #endif static int db_init(dbiIndex dbi, const char * dbhome, DB_ENV ** dbenvp) { rpmdb rpmdb = dbi->dbi_rpmdb; DB_ENV *dbenv = NULL; int eflags; int rc, xx; if (dbenvp == NULL) return 1; /* XXX HACK */ if (rpmdb->db_errfile == NULL) rpmdb->db_errfile = stderr; eflags = (dbi->dbi_oeflags | dbi->dbi_eflags); if (eflags & DB_JOINENV) eflags &= DB_JOINENV; { char *fstr = prDbiOpenFlags(eflags, 1); rpmlog(RPMLOG_DEBUG, "opening db environment %s %s\n", dbhome, fstr); free(fstr); } /* XXX Set a default shm_key. */ if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) { #if defined(HAVE_FTOK) dbi->dbi_shmkey = ftok(dbhome, 0); #else dbi->dbi_shmkey = 0x44631380; #endif } rc = db_env_create(&dbenv, dbi->dbi_ecflags); rc = cvtdberr(dbi, "db_env_create", rc, _debug); if (dbenv == NULL || rc) goto errxit; dbenv->set_alloc(dbenv,rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free); dbenv->set_errcall(dbenv, (void *) rpmdb->db_errcall); dbenv->set_errfile(dbenv, rpmdb->db_errfile); dbenv->set_errpfx(dbenv, rpmdb->db_errpfx); #if (DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 5) /* * These enable automatic stale lock removal. * thread_count 8 is some kind of "magic minimum" value... */ dbenv->set_thread_count(dbenv, 8); dbenv->set_isalive(dbenv, db3isalive); #endif #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, (dbi->dbi_verbose & DB_VERB_CHKPOINT)); #endif dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, (dbi->dbi_verbose & DB_VERB_DEADLOCK)); dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, (dbi->dbi_verbose & DB_VERB_RECOVERY)); dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR, (dbi->dbi_verbose & DB_VERB_WAITSFOR)); if (dbi->dbi_mmapsize) { xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mmapsize); xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug); } if (dbi->dbi_tmpdir) { /* XXX this isn't correct wrt chroot in+out */ const char * root = rpmdb->db_chrootDone ? NULL : rpmdb->db_root; char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL); xx = dbenv->set_tmp_dir(dbenv, tmpdir); xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug); tmpdir = _free(tmpdir); } if (dbi->dbi_cachesize) { xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_cachesize, 0); xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug); } if (dbi->dbi_no_fsync) { xx = db_env_set_func_fsync(db3_fsync_disable); xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug); } if (dbi->dbi_shmkey) { xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey); xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug); } rc = (dbenv->open)(dbenv, dbhome, eflags, dbi->dbi_perms); rc = cvtdberr(dbi, "dbenv->open", rc, _debug); if (rc) goto errxit; #if (DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 5) /* stale lock removal */ rc = dbenv->failchk(dbenv, 0); rc = cvtdberr(dbi, "dbenv->failchk", rc, _debug); if (rc) goto errxit; #endif *dbenvp = dbenv; return 0; errxit: if (dbenv) { int xx; xx = dbenv->close(dbenv, 0); xx = cvtdberr(dbi, "dbenv->close", xx, _debug); } return rc; } static int db3sync(dbiIndex dbi, unsigned int flags) { DB * db = dbi->dbi_db; int rc = 0; if (db != NULL) { rc = db->sync(db, flags); rc = cvtdberr(dbi, "db->sync", rc, _debug); } return rc; } static int db3cclose(dbiIndex dbi, DBC * dbcursor, unsigned int flags) { int rc = -2; /* XXX db3copen error pathways come through here. */ if (dbcursor != NULL) { rc = dbcursor->c_close(dbcursor); rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug); } return rc; } static int db3copen(dbiIndex dbi, DB_TXN * txnid, DBC ** dbcp, unsigned int dbiflags) { DB * db = dbi->dbi_db; DBC * dbcursor = NULL; int flags; int rc; /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */ assert(db != NULL); if ((dbiflags & DB_WRITECURSOR) && (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY)) { flags = DB_WRITECURSOR; } else flags = 0; rc = db->cursor(db, txnid, &dbcursor, flags); rc = cvtdberr(dbi, "db->cursor", rc, _debug); if (dbcp) *dbcp = dbcursor; else (void) db3cclose(dbi, dbcursor, 0); return rc; } static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, unsigned int flags) { DB * db = dbi->dbi_db; int rc; assert(db != NULL); if (dbcursor == NULL) { rc = db->put(db, dbi->dbi_txnid, key, data, 0); rc = cvtdberr(dbi, "db->put", rc, _debug); } else { rc = dbcursor->c_put(dbcursor, key, data, DB_KEYLAST); rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug); } return rc; } static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, unsigned int flags) { DB * db = dbi->dbi_db; int rc; assert(db != NULL); if (dbcursor == NULL) { rc = db->del(db, dbi->dbi_txnid, key, flags); rc = cvtdberr(dbi, "db->del", rc, _debug); } else { int _printit; /* XXX TODO: insure that cursor is positioned with duplicates */ rc = dbcursor->c_get(dbcursor, key, data, DB_SET); /* XXX DB_NOTFOUND can be returned */ _printit = (rc == DB_NOTFOUND ? 0 : _debug); rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit); if (rc == 0) { rc = dbcursor->c_del(dbcursor, flags); rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug); } } return rc; } static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, unsigned int flags) { DB * db = dbi->dbi_db; int _printit; int rc; assert(db != NULL); if (dbcursor == NULL) { /* XXX duplicates require cursors. */ rc = db->get(db, dbi->dbi_txnid, key, data, 0); /* XXX DB_NOTFOUND can be returned */ _printit = (rc == DB_NOTFOUND ? 0 : _debug); rc = cvtdberr(dbi, "db->get", rc, _printit); } else { /* XXX db3 does DB_FIRST on uninitialized cursor */ rc = dbcursor->c_get(dbcursor, key, data, flags); /* XXX DB_NOTFOUND can be returned */ _printit = (rc == DB_NOTFOUND ? 0 : _debug); rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit); } return rc; } static int db3ccount(dbiIndex dbi, DBC * dbcursor, unsigned int * countp, unsigned int flags) { db_recno_t count = 0; int rc = 0; flags = 0; rc = dbcursor->c_count(dbcursor, &count, flags); rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug); if (rc) return rc; if (countp) *countp = count; return rc; } static int db3byteswapped(dbiIndex dbi) { DB * db = dbi->dbi_db; int rc = 0; if (db != NULL) { int isswapped = 0; rc = db->get_byteswapped(db, &isswapped); if (rc == 0) rc = isswapped; } return rc; } static int db3stat(dbiIndex dbi, unsigned int flags) { DB * db = dbi->dbi_db; #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) DB_TXN * txnid = NULL; #endif int rc = 0; assert(db != NULL); #if defined(DB_FAST_STAT) if (flags) flags = DB_FAST_STAT; else #endif flags = 0; dbi->dbi_stats = _free(dbi->dbi_stats); #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) rc = db->stat(db, txnid, &dbi->dbi_stats, flags); #else rc = db->stat(db, &dbi->dbi_stats, flags); #endif rc = cvtdberr(dbi, "db->stat", rc, _debug); return rc; } static int db3close(dbiIndex dbi, unsigned int flags) { rpmdb rpmdb = dbi->dbi_rpmdb; const char * dbhome = rpmdbHome(rpmdb); DB * db = dbi->dbi_db; int _printit; int rc = 0, xx; flags = 0; /* XXX unused */ if (db) { rc = db->close(db, 0); /* XXX ignore not found error messages. */ _printit = (rc == ENOENT ? 0 : _debug); rc = cvtdberr(dbi, "db->close", rc, _printit); db = dbi->dbi_db = NULL; rpmlog(RPMLOG_DEBUG, "closed db index %s/%s\n", dbhome, dbi->dbi_file); } if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) { if (rpmdb->db_opens == 1) { xx = db_fini(dbi, (dbhome ? dbhome : "")); rpmdb->db_dbenv = NULL; } rpmdb->db_opens--; } if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) { DB_ENV * dbenv = NULL; rc = db_env_create(&dbenv, 0); rc = cvtdberr(dbi, "db_env_create", rc, _debug); if (rc || dbenv == NULL) goto exit; dbenv->set_errcall(dbenv, (void *) rpmdb->db_errcall); dbenv->set_errfile(dbenv, rpmdb->db_errfile); dbenv->set_errpfx(dbenv, rpmdb->db_errpfx); #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, (dbi->dbi_verbose & DB_VERB_CHKPOINT)); #endif xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, (dbi->dbi_verbose & DB_VERB_DEADLOCK)); xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, (dbi->dbi_verbose & DB_VERB_RECOVERY)); xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR, (dbi->dbi_verbose & DB_VERB_WAITSFOR)); if (dbi->dbi_tmpdir) { /* XXX this isn't correct wrt chroot in+out */ const char * root = rpmdb->db_chrootDone ? NULL : rpmdb->db_root; char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL); rc = dbenv->set_tmp_dir(dbenv, tmpdir); rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug); tmpdir = _free(tmpdir); if (rc) goto exit; } rc = (dbenv->open)(dbenv, dbhome, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0); rc = cvtdberr(dbi, "dbenv->open", rc, _debug); if (rc) goto exit; rc = db_create(&db, dbenv, 0); rc = cvtdberr(dbi, "db_create", rc, _debug); if (db != NULL) { char * dbf = rpmGetPath(dbhome, "/", dbi->dbi_file, NULL); rc = db->verify(db, dbf, NULL, NULL, flags); rc = cvtdberr(dbi, "db->verify", rc, _debug); rpmlog(RPMLOG_DEBUG, "verified db index %s/%s\n", (dbhome ? dbhome : ""), dbi->dbi_file); /* * The DB handle may not be accessed again after * DB->verify is called, regardless of its return. */ db = NULL; dbf = _free(dbf); } xx = dbenv->close(dbenv, 0); xx = cvtdberr(dbi, "dbenv->close", xx, _debug); if (rc == 0 && xx) rc = xx; } exit: dbi->dbi_db = NULL; dbi = db3Free(dbi); return rc; } static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip) { extern const struct _dbiVec db3vec; const char *dbhome = rpmdbHome(rpmdb); dbiIndex dbi = NULL; int rc = 0; int xx; DB * db = NULL; DB_ENV * dbenv = NULL; DB_TXN * txnid = NULL; uint32_t oflags; int _printit; if (dbip) *dbip = NULL; /* * Parse db configuration parameters. */ if ((dbi = db3New(rpmdb, rpmtag)) == NULL) return 1; oflags = (dbi->dbi_oeflags | dbi->dbi_oflags); oflags &= ~DB_TRUNCATE; /* XXX this is dangerous */ #if 0 /* XXX rpmdb: illegal flag combination specified to DB->open */ if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL; #endif /* * Map open mode flags onto configured database/environment flags. */ if (dbi->dbi_temporary) { oflags |= DB_CREATE; dbi->dbi_oeflags |= DB_CREATE; oflags &= ~DB_RDONLY; dbi->dbi_oflags &= ~DB_RDONLY; } else { if ((dbi->dbi_mode & O_ACCMODE) == O_RDONLY) oflags |= DB_RDONLY; if (dbi->dbi_mode & O_CREAT) { oflags |= DB_CREATE; dbi->dbi_oeflags |= DB_CREATE; } #ifdef DANGEROUS if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE; #endif } /* * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open. */ if (dbi->dbi_use_dbenv) { if (access(dbhome, W_OK) == -1) { /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */ oflags &= ~DB_CREATE; /* ... but DBENV->open might still need DB_CREATE ... */ if (dbi->dbi_eflags & DB_PRIVATE) { dbi->dbi_eflags &= ~DB_JOINENV; } else { dbi->dbi_eflags |= DB_JOINENV; dbi->dbi_oeflags &= ~DB_CREATE; dbi->dbi_oeflags &= ~DB_THREAD; /* ... but, unless DB_PRIVATE is used, skip DBENV. */ dbi->dbi_use_dbenv = 0; } /* ... DB_RDONLY maps dbhome perms across files ... */ if (dbi->dbi_temporary) { oflags |= DB_CREATE; dbi->dbi_oeflags |= DB_CREATE; oflags &= ~DB_RDONLY; dbi->dbi_oflags &= ~DB_RDONLY; } else { oflags |= DB_RDONLY; /* ... and DB_WRITECURSOR won't be needed ... */ dbi->dbi_oflags |= DB_RDONLY; } } else { /* dbhome is writable, check for persistent dbenv. */ char * dbf = rpmGetPath(dbhome, "/__db.001", NULL); if (access(dbf, F_OK) == -1) { /* ... non-existent (or unwritable) DBENV, will create ... */ dbi->dbi_oeflags |= DB_CREATE; dbi->dbi_eflags &= ~DB_JOINENV; } else { /* ... pre-existent (or bogus) DBENV, will join ... */ if (dbi->dbi_eflags & DB_PRIVATE) { dbi->dbi_eflags &= ~DB_JOINENV; } else { dbi->dbi_eflags |= DB_JOINENV; dbi->dbi_oeflags &= ~DB_CREATE; dbi->dbi_oeflags &= ~DB_THREAD; } } dbf = _free(dbf); } } /* * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open. */ if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) { /* dbhome is writable, and DB->open flags may conflict. */ char * dbf = rpmGetPath(dbhome, "/", dbi->dbi_file, NULL); if (access(dbf, F_OK) == -1) { /* File does not exist, DB->open might create ... */ oflags &= ~DB_RDONLY; } else { /* File exists, DB->open need not create ... */ oflags &= ~DB_CREATE; } /* Only writers need DB_WRITECURSOR ... */ if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) { dbi->dbi_oflags &= ~DB_RDONLY; } else { dbi->dbi_oflags |= DB_RDONLY; } dbf = _free(dbf); } /* * Turn off verify-on-close if opening read-only. */ if (oflags & DB_RDONLY) dbi->dbi_verify_on_close = 0; if (dbi->dbi_use_dbenv) { if (rpmdb->db_dbenv == NULL) { rc = db_init(dbi, dbhome, &dbenv); if (rc == 0) { rpmdb->db_dbenv = dbenv; rpmdb->db_opens = 1; } } else { dbenv = rpmdb->db_dbenv; rpmdb->db_opens++; } } { char *dbiflags = prDbiOpenFlags(oflags, 0); rpmlog(RPMLOG_DEBUG, "opening db index %s/%s %s mode=0x%x\n", dbhome, dbi->dbi_file, dbiflags, dbi->dbi_mode); free(dbiflags); } if (rc == 0) { static int _lockdbfd = 0; rc = db_create(&db, dbenv, dbi->dbi_cflags); rc = cvtdberr(dbi, "db_create", rc, _debug); if (rc == 0 && db != NULL) { if (rc == 0 && !dbi->dbi_use_dbenv) { rc = db->set_alloc(db, rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free); rc = cvtdberr(dbi, "db->set_alloc", rc, _debug); } if (rc == 0 && !dbi->dbi_use_dbenv && dbi->dbi_cachesize) { rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0); rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug); } if (rc == 0 && dbi->dbi_lorder) { rc = db->set_lorder(db, dbi->dbi_lorder); rc = cvtdberr(dbi, "db->set_lorder", rc, _debug); } if (rc == 0 && dbi->dbi_pagesize) { rc = db->set_pagesize(db, dbi->dbi_pagesize); rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug); } if (rc == 0 && oflags & DB_CREATE) { switch(dbi->dbi_type) { default: case DB_HASH: if (dbi->dbi_h_ffactor) { rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor); rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug); if (rc) break; } if (dbi->dbi_h_nelem) { rc = db->set_h_nelem(db, dbi->dbi_h_nelem); rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug); if (rc) break; } if (dbi->dbi_h_flags) { rc = db->set_flags(db, dbi->dbi_h_flags); rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug); if (rc) break; } if (dbi->dbi_h_hash_fcn) { rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn); rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug); if (rc) break; } if (dbi->dbi_h_dup_compare_fcn) { rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn); rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug); if (rc) break; } break; case DB_BTREE: if (dbi->dbi_bt_flags) { rc = db->set_flags(db, dbi->dbi_bt_flags); rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug); if (rc) break; } if (dbi->dbi_bt_minkey) { rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey); rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug); if (rc) break; } if (dbi->dbi_bt_compare_fcn) { rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn); rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug); if (rc) break; } if (dbi->dbi_bt_dup_compare_fcn) { rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn); rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug); if (rc) break; } if (dbi->dbi_bt_prefix_fcn) { rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn); rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug); if (rc) break; } break; case DB_RECNO: if (dbi->dbi_re_delim) { rc = db->set_re_delim(db, dbi->dbi_re_delim); rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug); if (rc) break; } if (dbi->dbi_re_len) { rc = db->set_re_len(db, dbi->dbi_re_len); rc = cvtdberr(dbi, "db->set_re_len", rc, _debug); if (rc) break; } if (dbi->dbi_re_pad) { rc = db->set_re_pad(db, dbi->dbi_re_pad); rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug); if (rc) break; } if (dbi->dbi_re_source) { rc = db->set_re_source(db, dbi->dbi_re_source); rc = cvtdberr(dbi, "db->set_re_source", rc, _debug); if (rc) break; } break; case DB_QUEUE: if (dbi->dbi_q_extentsize) { rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize); rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug); if (rc) break; } break; } } if (rc == 0) { const char *dbpath = dbi->dbi_temporary ? NULL : dbi->dbi_file; char *fullpath = NULL; /* When not in environment, absolute path is needed */ if (!dbi->dbi_use_dbenv && !dbi->dbi_temporary) { fullpath = rpmGetPath(dbhome, "/", dbi->dbi_file, NULL); dbpath = fullpath; } rc = (db->open)(db, txnid, dbpath, NULL, dbi->dbi_type, oflags, dbi->dbi_perms); if (rc == 0 && dbi->dbi_type == DB_UNKNOWN) { DBTYPE dbi_type = DB_UNKNOWN; xx = db->get_type(db, &dbi_type); if (xx == 0) dbi->dbi_type = dbi_type; } free(fullpath); } /* XXX return rc == errno without printing */ _printit = (rc > 0 ? 0 : _debug); xx = cvtdberr(dbi, "db->open", rc, _printit); dbi->dbi_txnid = NULL; /* * Lock a file using fcntl(2). Traditionally this is Packages, * the file used to store metadata of installed header(s), * as Packages is always opened, and should be opened first, * for any rpmdb access. * * If no DBENV is used, then access is protected with a * shared/exclusive locking scheme, as always. * * With a DBENV, the fcntl(2) lock is necessary only to keep * the riff-raff from playing where they don't belong, as * the DBENV should provide it's own locking scheme. So try to * acquire a lock, but permit failures, as some other * DBENV player may already have acquired the lock. * * With NPTL posix mutexes, revert to fcntl lock on non-functioning * glibc/kernel combinations. */ if (rc == 0 && dbi->dbi_lockdbfd && (!dbi->dbi_use_dbenv || _lockdbfd++ == 0)) { int fdno = -1; if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) { rc = 1; } else { struct flock l; memset(&l, 0, sizeof(l)); l.l_whence = 0; l.l_start = 0; l.l_len = 0; l.l_type = (dbi->dbi_mode & O_ACCMODE) == O_RDONLY ? F_RDLCK : F_WRLCK; l.l_pid = 0; rc = fcntl(fdno, F_SETLK, (void *) &l); if (rc) { /* Warning iff using non-private CDB locking. */ rc = ((dbi->dbi_use_dbenv && (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_eflags & DB_PRIVATE)) ? 0 : 1); rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING), _("cannot get %s lock on %s/%s\n"), ((dbi->dbi_mode & O_ACCMODE) == O_RDONLY) ? _("shared") : _("exclusive"), dbhome, dbi->dbi_file); } else { rpmlog(RPMLOG_DEBUG, "locked db index %s/%s\n", dbhome, dbi->dbi_file); } } } } } dbi->dbi_db = db; if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) { dbi->dbi_vec = &db3vec; *dbip = dbi; } else { dbi->dbi_verify_on_close = 0; (void) db3close(dbi, 0); } return rc; } /** \ingroup db3 */ RPM_GNUC_INTERNAL const struct _dbiVec db3vec = { DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, db3open, db3close, db3sync, db3copen, db3cclose, db3cdel, db3cget, db3cput, db3ccount, db3byteswapped, db3stat };