1397 lines
37 KiB
C
1397 lines
37 KiB
C
/*@-type@*/ /* FIX: annotate db3 methods */
|
|
/** \ingroup db3
|
|
* \file rpmdb/db3.c
|
|
*/
|
|
|
|
/*@unchecked@*/
|
|
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 <sys/ipc.h>
|
|
#endif
|
|
|
|
#if defined(__LCLINT__)
|
|
/*@-redef@*/ /* FIX: rpmio/rpmio.c also declares */
|
|
typedef unsigned int u_int32_t;
|
|
typedef unsigned short u_int16_t;
|
|
typedef unsigned char u_int8_t;
|
|
/*@-incondefs@*/ /* LCLint 3.0.0.15 */
|
|
typedef int int32_t;
|
|
/*@=incondefs@*/
|
|
/*@=redef@*/
|
|
#endif
|
|
|
|
#if defined(HAVE_DB4_DB_H)
|
|
#include <db4/db.h>
|
|
#elif defined(HAVE_DB3_DB_H)
|
|
#include <db3/db.h>
|
|
#endif
|
|
|
|
#include "rpmlib.h"
|
|
#include "rpmmacro.h"
|
|
#include "rpmurl.h" /* XXX urlPath proto */
|
|
|
|
#include "rpmdb.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#if !defined(DB_CLIENT) /* XXX db-4.2.42 retrofit */
|
|
#define DB_CLIENT DB_RPCCLIENT
|
|
#endif
|
|
|
|
/*@access rpmdb @*/
|
|
/*@access dbiIndex @*/
|
|
/*@access dbiIndexSet @*/
|
|
|
|
/** \ingroup dbi
|
|
* Hash database statistics.
|
|
*/
|
|
/*@-fielduse@*/
|
|
struct dbiHStats_s {
|
|
unsigned int hash_magic; /*!< hash database magic number. */
|
|
unsigned int hash_version; /*!< version of the hash database. */
|
|
unsigned int hash_nkeys; /*!< no. of unique keys in the database. */
|
|
unsigned int hash_ndata; /*!< no. of key/data pairs in the database. */
|
|
unsigned int hash_pagesize; /*!< db page (and bucket) size, in bytes. */
|
|
unsigned int hash_nelem; /*!< estimated size of the hash table. */
|
|
unsigned int hash_ffactor; /*!< no. of items per bucket. */
|
|
unsigned int hash_buckets; /*!< no. of hash buckets. */
|
|
unsigned int hash_free; /*!< no. of pages on the free list. */
|
|
unsigned int hash_bfree; /*!< no. of bytes free on bucket pages. */
|
|
unsigned int hash_bigpages; /*!< no. of big key/data pages. */
|
|
unsigned int hash_big_bfree;/*!< no. of bytes free on big item pages. */
|
|
unsigned int hash_overflows;/*!< no. of overflow pages. */
|
|
unsigned int hash_ovfl_free;/*!< no. of bytes free on overflow pages. */
|
|
unsigned int hash_dup; /*!< no. of duplicate pages. */
|
|
unsigned int hash_dup_free; /*!< no. bytes free on duplicate pages. */
|
|
};
|
|
|
|
/** \ingroup dbi
|
|
* B-tree database statistics.
|
|
*/
|
|
struct dbiBStats_s {
|
|
unsigned int bt_magic; /*!< btree database magic. */
|
|
unsigned int bt_version; /*!< version of the btree database. */
|
|
unsigned int bt_nkeys; /*!< no. of unique keys in the database. */
|
|
unsigned int bt_ndata; /*!< no. of key/data pairs in the database. */
|
|
unsigned int bt_pagesize; /*!< database page size, in bytes. */
|
|
unsigned int bt_minkey; /*!< minimum keys per page. */
|
|
unsigned int bt_re_len; /*!< length of fixed-length records. */
|
|
unsigned int bt_re_pad; /*!< padding byte for fixed-length records. */
|
|
unsigned int bt_levels; /*!< no. of levels in the database. */
|
|
unsigned int bt_int_pg; /*!< no. of database internal pages. */
|
|
unsigned int bt_leaf_pg; /*!< no. of database leaf pages. */
|
|
unsigned int bt_dup_pg; /*!< no. of database duplicate pages. */
|
|
unsigned int bt_over_pg; /*!< no. of database overflow pages. */
|
|
unsigned int bt_free; /*!< no. of pages on the free list. */
|
|
unsigned int bt_int_pgfree; /*!< no. of bytes free in internal pages. */
|
|
unsigned int bt_leaf_pgfree;/*!< no. of bytes free in leaf pages. */
|
|
unsigned int bt_dup_pgfree; /*!< no. of bytes free in duplicate pages. */
|
|
unsigned int bt_over_pgfree;/*!< no. of bytes free in overflow pages. */
|
|
};
|
|
/*@=fielduse@*/
|
|
|
|
/*@-globuse -mustmod @*/ /* FIX: rpmError not annotated yet. */
|
|
static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
int rc = error;
|
|
|
|
if (printit && rc) {
|
|
/*@-moduncon@*/ /* FIX: annotate db3 methods */
|
|
if (msg)
|
|
rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
|
|
dbi->dbi_api, rc, msg, db_strerror(error));
|
|
else
|
|
rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
|
|
dbi->dbi_api, rc, db_strerror(error));
|
|
/*@=moduncon@*/
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
/*@=globuse =mustmod @*/
|
|
|
|
static int db_fini(dbiIndex dbi, const char * dbhome,
|
|
/*@null@*/ const char * dbfile,
|
|
/*@unused@*/ /*@null@*/ const char * dbsubfile)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
rpmdb rpmdb = dbi->dbi_rpmdb;
|
|
DB_ENV * dbenv = rpmdb->db_dbenv;
|
|
int _printit;
|
|
int rc;
|
|
|
|
if (dbenv == NULL)
|
|
return 0;
|
|
|
|
rc = dbenv->close(dbenv, 0);
|
|
rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
|
|
|
|
if (dbfile)
|
|
rpmMessage(RPMMESS_DEBUG, _("closed db environment %s/%s\n"),
|
|
dbhome, dbfile);
|
|
|
|
if (rpmdb->db_remove_env || dbi->dbi_tear_down) {
|
|
int xx;
|
|
|
|
/*@-moduncon@*/ /* FIX: annotate db3 methods */
|
|
xx = db_env_create(&dbenv, 0);
|
|
/*@=moduncon@*/
|
|
xx = cvtdberr(dbi, "db_env_create", xx, _debug);
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
|
|
xx = dbenv->remove(dbenv, dbhome, 0);
|
|
#else
|
|
xx = dbenv->remove(dbenv, dbhome, NULL, 0);
|
|
#endif
|
|
/* XXX ignore "Device or resource busy" error messages. */
|
|
_printit = (xx == EBUSY ? 0 : _debug);
|
|
xx = cvtdberr(dbi, "dbenv->remove", xx, _printit);
|
|
|
|
if (dbfile)
|
|
rpmMessage(RPMMESS_DEBUG, _("removed db environment %s/%s\n"),
|
|
dbhome, dbfile);
|
|
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int db3_fsync_disable(/*@unused@*/ int fd)
|
|
/*@*/
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*@-moduncon@*/ /* FIX: annotate db3 methods */
|
|
static int db_init(dbiIndex dbi, const char * dbhome,
|
|
/*@null@*/ const char * dbfile,
|
|
/*@unused@*/ /*@null@*/ const char * dbsubfile,
|
|
/*@out@*/ DB_ENV ** dbenvp)
|
|
/*@globals rpmGlobalMacroContext,
|
|
fileSystem @*/
|
|
/*@modifies dbi, *dbenvp, fileSystem @*/
|
|
{
|
|
rpmdb rpmdb = dbi->dbi_rpmdb;
|
|
DB_ENV *dbenv = NULL;
|
|
int eflags;
|
|
int rc;
|
|
|
|
if (dbenvp == NULL)
|
|
return 1;
|
|
|
|
/* XXX HACK */
|
|
/*@-assignexpose@*/
|
|
if (rpmdb->db_errfile == NULL)
|
|
rpmdb->db_errfile = stderr;
|
|
/*@=assignexpose@*/
|
|
|
|
eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
|
|
if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
|
|
|
|
if (dbfile)
|
|
rpmMessage(RPMMESS_DEBUG, _("opening db environment %s/%s %s\n"),
|
|
dbhome, dbfile, prDbiOpenFlags(eflags, 1));
|
|
|
|
/* XXX Can't do RPC w/o host. */
|
|
if (dbi->dbi_host == NULL)
|
|
dbi->dbi_ecflags &= ~DB_CLIENT;
|
|
|
|
/* 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;
|
|
|
|
{ int xx;
|
|
/*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
|
|
|
|
/* 4.1: dbenv->set_app_dispatch(???) */
|
|
/* 4.1: dbenv->set_alloc(???) */
|
|
/* 4.1: dbenv->set_data_dir(???) */
|
|
/* 4.1: dbenv->set_encrypt(???) */
|
|
|
|
dbenv->set_errcall(dbenv, rpmdb->db_errcall);
|
|
dbenv->set_errfile(dbenv, rpmdb->db_errfile);
|
|
dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
|
|
/*@=noeffectuncon@*/
|
|
|
|
/* 4.1: dbenv->set_feedback(???) */
|
|
/* 4.1: dbenv->set_flags(???) */
|
|
|
|
/* dbenv->set_paniccall(???) */
|
|
|
|
if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
|
|
const char * home;
|
|
int retry = 0;
|
|
|
|
if ((home = strrchr(dbhome, '/')) != NULL)
|
|
dbhome = ++home;
|
|
|
|
while (retry++ < 5) {
|
|
/* XXX 3.3.4 change. */
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
|
|
xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
|
|
dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
|
|
xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
|
|
#else
|
|
xx = dbenv->set_server(dbenv, dbi->dbi_host,
|
|
dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
|
|
xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
|
|
#endif
|
|
if (!xx)
|
|
break;
|
|
sleep(15);
|
|
}
|
|
} else {
|
|
#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_mp_mmapsize) {
|
|
xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mp_mmapsize);
|
|
xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
|
|
}
|
|
if (dbi->dbi_tmpdir) {
|
|
const char * root;
|
|
const char * tmpdir;
|
|
|
|
root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
|
|
if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
|
|
root = NULL;
|
|
/*@-mods@*/
|
|
tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
|
|
/*@=mods@*/
|
|
xx = dbenv->set_tmp_dir(dbenv, tmpdir);
|
|
xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug);
|
|
tmpdir = _free(tmpdir);
|
|
}
|
|
}
|
|
|
|
/* dbenv->set_lk_conflicts(???) */
|
|
/* dbenv->set_lk_detect(???) */
|
|
/* 4.1: dbenv->set_lk_max_lockers(???) */
|
|
/* 4.1: dbenv->set_lk_max_locks(???) */
|
|
/* 4.1: dbenv->set_lk_max_objects(???) */
|
|
|
|
/* 4.1: dbenv->set_lg_bsize(???) */
|
|
/* 4.1: dbenv->set_lg_dir(???) */
|
|
/* 4.1: dbenv->set_lg_max(???) */
|
|
/* 4.1: dbenv->set_lg_regionmax(???) */
|
|
|
|
if (dbi->dbi_cachesize) {
|
|
xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_cachesize, 0);
|
|
xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
|
|
}
|
|
|
|
/* 4.1 dbenv->set_timeout(???) */
|
|
/* dbenv->set_tx_max(???) */
|
|
/* 4.1: dbenv->set_tx_timestamp(???) */
|
|
/* dbenv->set_tx_recover(???) */
|
|
|
|
/* dbenv->set_rep_transport(???) */
|
|
/* dbenv->set_rep_limit(???) */
|
|
|
|
if (dbi->dbi_no_fsync) {
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
|
|
xx = db_env_set_func_fsync(db3_fsync_disable);
|
|
#else
|
|
xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable);
|
|
#endif
|
|
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);
|
|
}
|
|
}
|
|
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
|
|
rc = dbenv->open(dbenv, dbhome, eflags, dbi->dbi_perms);
|
|
#else
|
|
rc = dbenv->open(dbenv, dbhome, NULL, eflags, dbi->dbi_perms);
|
|
#endif
|
|
rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
|
|
if (rc)
|
|
goto errxit;
|
|
|
|
*dbenvp = dbenv;
|
|
|
|
return 0;
|
|
|
|
errxit:
|
|
if (dbenv) {
|
|
int xx;
|
|
xx = dbenv->close(dbenv, 0);
|
|
xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
|
|
}
|
|
return rc;
|
|
}
|
|
/*@=moduncon@*/
|
|
|
|
static int db3sync(dbiIndex dbi, unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
DB * db = dbi->dbi_db;
|
|
int rc = 0;
|
|
int _printit;
|
|
|
|
if (db != NULL)
|
|
rc = db->sync(db, flags);
|
|
/* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
|
|
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
|
|
_printit = _debug;
|
|
#else
|
|
_printit = (rc == DB_INCOMPLETE ? 0 : _debug);
|
|
#endif
|
|
rc = cvtdberr(dbi, "db->sync", rc, _printit);
|
|
return rc;
|
|
}
|
|
|
|
static int db3c_del(dbiIndex dbi, DBC * dbcursor, u_int32_t flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
int rc;
|
|
|
|
rc = dbcursor->c_del(dbcursor, flags);
|
|
rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
|
|
return rc;
|
|
}
|
|
|
|
#if 0
|
|
/*@unused@*/ static int db3c_dup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
|
|
u_int32_t flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies *dbcp, fileSystem @*/
|
|
{
|
|
int rc;
|
|
|
|
if (dbcp) *dbcp = NULL;
|
|
rc = dbcursor->c_dup(dbcursor, dbcp, flags);
|
|
rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
|
|
/*@-nullstate @*/ /* FIX: *dbcp can be NULL */
|
|
return rc;
|
|
/*@=nullstate @*/
|
|
}
|
|
#endif
|
|
|
|
static int db3c_get(dbiIndex dbi, DBC * dbcursor,
|
|
DBT * key, DBT * data, u_int32_t flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
int _printit;
|
|
int rc;
|
|
int rmw;
|
|
|
|
#ifdef NOTYET
|
|
if ((dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
|
|
rmw = DB_RMW;
|
|
else
|
|
#endif
|
|
rmw = 0;
|
|
|
|
rc = dbcursor->c_get(dbcursor, key, data, rmw | 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 db3c_put(dbiIndex dbi, DBC * dbcursor,
|
|
DBT * key, DBT * data, u_int32_t flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
int rc;
|
|
|
|
rc = dbcursor->c_put(dbcursor, key, data, flags);
|
|
|
|
rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
|
|
return rc;
|
|
}
|
|
|
|
static inline int db3c_close(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
int rc;
|
|
|
|
if (dbcursor == NULL) return -2;
|
|
|
|
rc = dbcursor->c_close(dbcursor);
|
|
rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
|
|
return rc;
|
|
}
|
|
|
|
static inline int db3c_open(dbiIndex dbi, /*@null@*/ /*@out@*/ DBC ** dbcp,
|
|
int dbiflags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies *dbcp, fileSystem @*/
|
|
{
|
|
DB * db = dbi->dbi_db;
|
|
DB_TXN * txnid = NULL;
|
|
int flags;
|
|
int rc;
|
|
|
|
if (db == NULL) return -2;
|
|
if ((dbiflags & DBI_WRITECURSOR) &&
|
|
(dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
|
|
{
|
|
flags = DB_WRITECURSOR;
|
|
} else
|
|
flags = 0;
|
|
if (dbcp) *dbcp = NULL;
|
|
rc = db->cursor(db, txnid, dbcp, flags);
|
|
rc = cvtdberr(dbi, "db3c_open", rc, _debug);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
|
|
unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies dbi, fileSystem @*/
|
|
{
|
|
int rc = 0;
|
|
|
|
/* XXX per-iterator cursors */
|
|
if (flags & DBI_ITERATOR)
|
|
return db3c_close(dbi, dbcursor);
|
|
|
|
if (!dbi->dbi_use_cursors)
|
|
return 0;
|
|
|
|
/*@-branchstate@*/
|
|
if (dbcursor == NULL)
|
|
dbcursor = dbi->dbi_rmw;
|
|
/*@=branchstate@*/
|
|
if (dbcursor) {
|
|
/*@-branchstate@*/
|
|
if (dbcursor == dbi->dbi_rmw)
|
|
dbi->dbi_rmw = NULL;
|
|
/*@=branchstate@*/
|
|
rc = db3c_close(dbi, dbcursor);
|
|
}
|
|
/*@-usereleased -compdef@*/ return rc; /*@=usereleased =compdef@*/
|
|
}
|
|
|
|
static int db3copen(dbiIndex dbi,
|
|
/*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies dbi, *dbcp, fileSystem @*/
|
|
{
|
|
DBC * dbcursor;
|
|
int rc = 0;
|
|
|
|
/* XXX per-iterator cursors */
|
|
if (flags & DBI_ITERATOR)
|
|
return db3c_open(dbi, dbcp, flags);
|
|
|
|
if (!dbi->dbi_use_cursors) {
|
|
if (dbcp) *dbcp = NULL;
|
|
return 0;
|
|
}
|
|
|
|
if ((dbcursor = dbi->dbi_rmw) == NULL) {
|
|
if ((rc = db3c_open(dbi, &dbcursor, flags)) == 0)
|
|
dbi->dbi_rmw = dbcursor;
|
|
}
|
|
|
|
if (dbcp)
|
|
/*@-onlytrans@*/ *dbcp = dbi->dbi_rmw; /*@=onlytrans@*/
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int db3cput(dbiIndex dbi, DBC * dbcursor,
|
|
const void * keyp, size_t keylen,
|
|
const void * datap, size_t datalen,
|
|
/*@unused@*/ unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
DB * db = dbi->dbi_db;
|
|
DB_TXN * txnid = NULL;
|
|
DBT key, data;
|
|
int rc;
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
memset(&data, 0, sizeof(data));
|
|
key.data = (void *)keyp;
|
|
key.size = keylen;
|
|
data.data = (void *)datap;
|
|
data.size = datalen;
|
|
|
|
if (dbcursor == NULL) {
|
|
if (db == NULL) return -2;
|
|
rc = db->put(db, txnid, &key, &data, 0);
|
|
rc = cvtdberr(dbi, "db->put", rc, _debug);
|
|
} else {
|
|
|
|
rc = db3c_put(dbi, dbcursor, &key, &data, DB_KEYLAST);
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int db3cdel(dbiIndex dbi, DBC * dbcursor,
|
|
const void * keyp, size_t keylen,
|
|
/*@unused@*/ unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies fileSystem @*/
|
|
{
|
|
DB * db = dbi->dbi_db;
|
|
DB_TXN * txnid = NULL;
|
|
DBT key, data;
|
|
int rc;
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
key.data = (void *)keyp;
|
|
key.size = keylen;
|
|
|
|
if (dbcursor == NULL) {
|
|
if (db == NULL) return -2;
|
|
rc = db->del(db, txnid, &key, 0);
|
|
rc = cvtdberr(dbi, "db->del", rc, _debug);
|
|
} else {
|
|
|
|
rc = db3c_get(dbi, dbcursor, &key, &data, DB_SET);
|
|
|
|
if (rc == 0) {
|
|
/* XXX TODO: loop over duplicates */
|
|
rc = db3c_del(dbi, dbcursor, 0);
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int db3cget(dbiIndex dbi, DBC * dbcursor,
|
|
/*@null@*/ void ** keyp, /*@null@*/ size_t * keylen,
|
|
/*@null@*/ void ** datap, /*@null@*/ size_t * datalen,
|
|
/*@unused@*/ unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies *keyp, *keylen, *datap, *datalen, fileSystem @*/
|
|
{
|
|
DB * db = dbi->dbi_db;
|
|
DB_TXN * txnid = NULL;
|
|
DBT key, data;
|
|
int rc;
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
memset(&data, 0, sizeof(data));
|
|
/*@-unqualifiedtrans@*/
|
|
if (keyp) key.data = *keyp;
|
|
if (keylen) key.size = *keylen;
|
|
if (datap) data.data = *datap;
|
|
if (datalen) data.size = *datalen;
|
|
/*@=unqualifiedtrans@*/
|
|
|
|
if (dbcursor == NULL) {
|
|
int _printit;
|
|
/*@-compmempass@*/
|
|
if (db == NULL) return -2;
|
|
/*@=compmempass@*/
|
|
rc = db->get(db, 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 = db3c_get(dbi, dbcursor, &key, &data,
|
|
key.data == NULL ? DB_NEXT : DB_SET);
|
|
|
|
}
|
|
|
|
if (rc == 0) {
|
|
/*@-onlytrans@*/
|
|
if (keyp) *keyp = key.data;
|
|
if (keylen) *keylen = key.size;
|
|
if (datap) *datap = data.data;
|
|
if (datalen) *datalen = data.size;
|
|
/*@=onlytrans@*/
|
|
}
|
|
|
|
/*@-compmempass -nullstate@*/
|
|
return rc;
|
|
/*@=compmempass =nullstate@*/
|
|
}
|
|
|
|
static int db3ccount(dbiIndex dbi, DBC * dbcursor,
|
|
/*@null@*/ /*@out@*/ unsigned int * countp,
|
|
/*@unused@*/ unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies *countp, fileSystem @*/
|
|
{
|
|
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) {
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH >= 11) \
|
|
|| (DB_VERSION_MAJOR == 4)
|
|
int isswapped = 0;
|
|
rc = db->get_byteswapped(db, &isswapped);
|
|
if (rc == 0)
|
|
rc = isswapped;
|
|
#else
|
|
rc = db->get_byteswapped(db);
|
|
#endif
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int db3stat(dbiIndex dbi, unsigned int flags)
|
|
/*@globals fileSystem @*/
|
|
/*@modifies dbi, fileSystem @*/
|
|
{
|
|
DB * db = dbi->dbi_db;
|
|
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
|
|
DB_TXN * txnid = NULL;
|
|
#endif
|
|
int rc = 0;
|
|
|
|
if (db == NULL) return -2;
|
|
#if defined(DB_FAST_STAT)
|
|
if (flags)
|
|
flags = DB_FAST_STAT;
|
|
else
|
|
#endif
|
|
flags = 0;
|
|
dbi->dbi_stats = _free(dbi->dbi_stats);
|
|
/* XXX 3.3.4 change. */
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
|
|
#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
|
|
#else
|
|
rc = db->stat(db, &dbi->dbi_stats, NULL, flags);
|
|
#endif
|
|
rc = cvtdberr(dbi, "db->stat", rc, _debug);
|
|
return rc;
|
|
}
|
|
|
|
/*@-moduncon@*/ /* FIX: annotate db3 methods */
|
|
static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
|
|
/*@globals rpmGlobalMacroContext,
|
|
fileSystem @*/
|
|
/*@modifies dbi, fileSystem @*/
|
|
{
|
|
rpmdb rpmdb = dbi->dbi_rpmdb;
|
|
const char * urlfn = NULL;
|
|
const char * root;
|
|
const char * home;
|
|
const char * dbhome;
|
|
const char * dbfile;
|
|
const char * dbsubfile;
|
|
DB * db = dbi->dbi_db;
|
|
int _printit;
|
|
int rc = 0, xx;
|
|
|
|
flags = 0; /* XXX unused */
|
|
|
|
/*
|
|
* Get the prefix/root component and directory path.
|
|
*/
|
|
root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
|
|
if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
|
|
root = NULL;
|
|
home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
|
|
|
|
/*
|
|
* Either the root or directory components may be a URL. Concatenate,
|
|
* convert the URL to a path, and add the name of the file.
|
|
*/
|
|
/*@-mods@*/
|
|
urlfn = rpmGenPath(root, home, NULL);
|
|
/*@=mods@*/
|
|
(void) urlPath(urlfn, &dbhome);
|
|
if (dbi->dbi_temporary) {
|
|
dbfile = NULL;
|
|
dbsubfile = NULL;
|
|
} else {
|
|
#ifdef HACK /* XXX necessary to support dbsubfile */
|
|
dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
|
|
dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
|
|
#else
|
|
dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
|
|
dbsubfile = NULL;
|
|
#endif
|
|
}
|
|
|
|
if (dbi->dbi_rmw)
|
|
rc = db3cclose(dbi, NULL, 0);
|
|
|
|
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;
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("closed db index %s/%s\n"),
|
|
dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
|
|
|
|
}
|
|
|
|
if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) {
|
|
if (rpmdb->db_opens == 1) {
|
|
/*@-nullstate@*/
|
|
xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
|
|
/*@=nullstate@*/
|
|
rpmdb->db_dbenv = NULL;
|
|
}
|
|
rpmdb->db_opens--;
|
|
}
|
|
|
|
if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
|
|
DB_ENV * dbenv = NULL;
|
|
|
|
/*@-moduncon@*/ /* FIX: annotate db3 methods */
|
|
rc = db_env_create(&dbenv, 0);
|
|
/*@=moduncon@*/
|
|
rc = cvtdberr(dbi, "db_env_create", rc, _debug);
|
|
if (rc || dbenv == NULL) goto exit;
|
|
|
|
/*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
|
|
dbenv->set_errcall(dbenv, rpmdb->db_errcall);
|
|
dbenv->set_errfile(dbenv, rpmdb->db_errfile);
|
|
dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
|
|
/* dbenv->set_paniccall(???) */
|
|
/*@=noeffectuncon@*/
|
|
#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) {
|
|
/*@-mods@*/
|
|
const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
|
|
/*@=mods@*/
|
|
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;
|
|
|
|
/*@-moduncon@*/ /* FIX: annotate db3 methods */
|
|
rc = db_create(&db, dbenv, 0);
|
|
/*@=moduncon@*/
|
|
rc = cvtdberr(dbi, "db_create", rc, _debug);
|
|
|
|
if (db != NULL) {
|
|
/*@-mods@*/
|
|
const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
|
|
/*@=mods@*/
|
|
|
|
rc = db->verify(db, dbf, NULL, NULL, flags);
|
|
rc = cvtdberr(dbi, "db->verify", rc, _debug);
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("verified db index %s/%s\n"),
|
|
(dbhome ? dbhome : ""),
|
|
(dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
|
|
|
|
/*
|
|
* Depending on the DB version,
|
|
* the DB handle may not be accessed again after
|
|
* DB->verify is called, regardless of its return.
|
|
*/
|
|
#if (DB_VERSION_MAJOR <= 3) || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 1)
|
|
xx = db->close(db, 0);
|
|
xx = cvtdberr(dbi, "db->close", xx, _debug);
|
|
if (rc == 0 && xx) rc = xx;
|
|
#endif
|
|
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;
|
|
|
|
urlfn = _free(urlfn);
|
|
|
|
dbi = db3Free(dbi);
|
|
|
|
return rc;
|
|
}
|
|
/*@=moduncon@*/
|
|
|
|
static inline int parseYesNo( const char *s )
|
|
{
|
|
if (!s ||
|
|
!strcasecmp(s, "no") ||
|
|
!strcasecmp(s, "false") ||
|
|
!strcasecmp(s, "off") ||
|
|
!strcmp(s, "0")) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int wait_for_lock (void)
|
|
{
|
|
const char *str = rpmExpand ("%{?_wait_for_lock}", NULL);
|
|
int val = (str && *str) ? parseYesNo (str) : 1;
|
|
str = _free (str);
|
|
|
|
return val;
|
|
}
|
|
|
|
static int dbi_set_lock (dbiIndex dbi, DB *db, const char *dbhome, const char *dbfile)
|
|
{
|
|
int rc = 0;
|
|
/*
|
|
* 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.
|
|
*/
|
|
if (!dbi->dbi_lockdbfd)
|
|
return 0;
|
|
|
|
int fdno = -1;
|
|
if (db->fd(db, &fdno) || fdno < 0)
|
|
return 1;
|
|
|
|
int ignore_lock = dbi->dbi_use_dbenv && (dbi->dbi_eflags & DB_INIT_CDB);
|
|
int wait_lock = wait_for_lock();
|
|
int cmd = (ignore_lock || !wait_lock) ? F_SETLK : F_SETLKW;
|
|
short l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY)) ? F_WRLCK : F_RDLCK;
|
|
struct flock l;
|
|
memset(&l, 0, sizeof(l));
|
|
l.l_type = l_type;
|
|
|
|
if (fcntl(fdno, F_GETLK, (void *) &l) == 0 &&
|
|
l.l_type == l_type && l.l_pid == getpid())
|
|
return 0;
|
|
|
|
memset(&l, 0, sizeof(l));
|
|
l.l_type = l_type;
|
|
for (;;) {
|
|
rc = fcntl(fdno, cmd, (void *) &l);
|
|
if (rc) {
|
|
if (EINTR == errno)
|
|
continue;
|
|
|
|
/* Warning only if using CDB locking. */
|
|
if (ignore_lock)
|
|
rc = 0;
|
|
else if (wait_lock &&
|
|
(EACCES == errno || EAGAIN == errno || ENOLCK == errno))
|
|
continue;
|
|
rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK),
|
|
_("cannot get %s lock on %s/%s\n"),
|
|
((dbi->dbi_mode & (O_RDWR|O_WRONLY))
|
|
? _("exclusive") : _("shared")),
|
|
dbhome, (dbfile ? dbfile : ""));
|
|
} else if (dbfile) {
|
|
rpmMessage(RPMMESS_DEBUG,
|
|
_("locked db index %s/%s\n"),
|
|
dbhome, dbfile);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int db3open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
|
|
/*@globals rpmGlobalMacroContext,
|
|
fileSystem @*/
|
|
/*@modifies *dbip, fileSystem @*/
|
|
{
|
|
/*@-nestedextern@*/
|
|
extern struct _dbiVec db3vec;
|
|
/*@=nestedextern@*/
|
|
const char * urlfn = NULL;
|
|
const char * root;
|
|
const char * home;
|
|
const char * dbhome;
|
|
const char * dbfile;
|
|
const char * dbsubfile;
|
|
dbiIndex dbi = NULL;
|
|
int rc = 0;
|
|
int xx;
|
|
|
|
DB * db = NULL;
|
|
DB_ENV * dbenv = NULL;
|
|
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
|
|
DB_TXN * txnid = NULL;
|
|
#endif
|
|
u_int32_t oflags;
|
|
int _printit;
|
|
|
|
if (dbip)
|
|
*dbip = NULL;
|
|
|
|
/*
|
|
* Parse db configuration parameters.
|
|
*/
|
|
/*@-mods@*/
|
|
if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
|
|
/*@-nullstate@*/
|
|
return 1;
|
|
/*@=nullstate@*/
|
|
/*@=mods@*/
|
|
dbi->dbi_api = DB_VERSION_MAJOR;
|
|
|
|
/*
|
|
* Get the prefix/root component and directory path.
|
|
*/
|
|
root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
|
|
if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
|
|
root = NULL;
|
|
home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
|
|
|
|
/*
|
|
* Either the root or directory components may be a URL. Concatenate,
|
|
* convert the URL to a path, and add the name of the file.
|
|
*/
|
|
/*@-mods@*/
|
|
urlfn = rpmGenPath(root, home, NULL);
|
|
/*@=mods@*/
|
|
(void) urlPath(urlfn, &dbhome);
|
|
if (dbi->dbi_temporary) {
|
|
dbfile = NULL;
|
|
dbsubfile = NULL;
|
|
} else {
|
|
#ifdef HACK /* XXX necessary to support dbsubfile */
|
|
dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
|
|
dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
|
|
#else
|
|
dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
|
|
dbsubfile = NULL;
|
|
#endif
|
|
}
|
|
|
|
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_RDWR|O_WRONLY))) 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
|
|
}
|
|
|
|
#ifdef TOOBAD
|
|
/*
|
|
* Create the /var/lib/rpm directory if it doesn't exist (root only).
|
|
*/
|
|
(void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
|
|
#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. */
|
|
/*@-mods@*/
|
|
const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
|
|
/*@=mods@*/
|
|
|
|
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. */
|
|
const char * dbfn = (dbfile ? dbfile : tagName(dbi->dbi_rpmtag));
|
|
/*@-mods@*/
|
|
const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
|
|
/*@=mods@*/
|
|
|
|
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) {
|
|
/*@-mods@*/
|
|
if (rpmdb->db_dbenv == NULL) {
|
|
rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
|
|
if (rc == 0) {
|
|
rpmdb->db_dbenv = dbenv;
|
|
rpmdb->db_opens = 1;
|
|
}
|
|
} else {
|
|
dbenv = rpmdb->db_dbenv;
|
|
rpmdb->db_opens++;
|
|
}
|
|
/*@=mods@*/
|
|
}
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("opening db index %s/%s %s mode=0x%x\n"),
|
|
dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)),
|
|
prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
|
|
|
|
if (rc == 0) {
|
|
/*@-moduncon@*/ /* FIX: annotate db3 methods */
|
|
rc = db_create(&db, dbenv, dbi->dbi_cflags);
|
|
/*@=moduncon@*/
|
|
rc = cvtdberr(dbi, "db_create", rc, _debug);
|
|
if (rc == 0 && db != NULL) {
|
|
|
|
/* XXX 3.3.4 change. */
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
|
|
if (rc == 0 &&
|
|
rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
|
|
{
|
|
rc = db->set_alloc(db,
|
|
rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
|
|
rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
|
|
}
|
|
#else
|
|
if (rc == 0 && rpmdb->db_malloc) {
|
|
rc = db->set_malloc(db, rpmdb->db_malloc);
|
|
rc = cvtdberr(dbi, "db->set_malloc", rc, _debug);
|
|
}
|
|
#endif
|
|
|
|
/* 4.1: db->set_cache_priority(???) */
|
|
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);
|
|
}
|
|
/* 4.1: db->set_encrypt(???) */
|
|
/* 4.1: db->set_errcall(dbenv, rpmdb->db_errcall); */
|
|
/* 4.1: db->set_errfile(dbenv, rpmdb->db_errfile); */
|
|
/* 4.1: db->set_errpfx(dbenv, rpmdb->db_errpfx); */
|
|
/* 4.1: db->set_feedback(???) */
|
|
|
|
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);
|
|
}
|
|
/* 4.1: db->set_paniccall(???) */
|
|
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;
|
|
}
|
|
/* XXX db-3.2.9 has added a DB arg to the call. */
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
|
|
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;
|
|
}
|
|
#endif
|
|
break;
|
|
case DB_BTREE:
|
|
/* 4.1: db->set_append_recno(???) */
|
|
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;
|
|
}
|
|
/* XXX db-3.2.9 has added a DB arg to the call. */
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
|
|
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;
|
|
}
|
|
#endif
|
|
break;
|
|
case DB_RECNO:
|
|
if (dbi->dbi_re_delim) {
|
|
/* 4.1: db->set_append_recno(???) */
|
|
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 * dbfullpath;
|
|
const char * dbpath;
|
|
char * t;
|
|
int nb;
|
|
|
|
nb = strlen(dbhome);
|
|
if (dbfile) nb += 1 + strlen(dbfile);
|
|
dbfullpath = t = alloca(nb + 1);
|
|
|
|
t = stpcpy(t, dbhome);
|
|
if (dbfile)
|
|
t = stpcpy( stpcpy( t, "/"), dbfile);
|
|
#ifdef HACK /* XXX necessary to support dbsubfile */
|
|
dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
|
|
? dbfullpath : dbfile;
|
|
#else
|
|
dbpath = (!dbi->dbi_temporary)
|
|
? dbfullpath : dbfile;
|
|
#endif
|
|
|
|
#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
|
|
rc = db->open(db, txnid, dbpath, dbsubfile,
|
|
dbi->dbi_type, oflags, dbi->dbi_perms);
|
|
#else
|
|
rc = db->open(db, dbpath, dbsubfile,
|
|
dbi->dbi_type, oflags, dbi->dbi_perms);
|
|
#endif
|
|
|
|
if (rc == 0 && dbi->dbi_type == DB_UNKNOWN) {
|
|
#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH >= 11) \
|
|
|| (DB_VERSION_MAJOR == 4)
|
|
DBTYPE dbi_type = DB_UNKNOWN;
|
|
xx = db->get_type(db, &dbi_type);
|
|
if (xx == 0)
|
|
dbi->dbi_type = dbi_type;
|
|
#else
|
|
dbi->dbi_type = db->get_type(db);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* XXX return rc == errno without printing */
|
|
_printit = (rc > 0 ? 0 : _debug);
|
|
xx = cvtdberr(dbi, "db->open", rc, _printit);
|
|
|
|
dbi->dbi_rmw = NULL;
|
|
|
|
if (rc == 0)
|
|
rc = dbi_set_lock(dbi, db, dbhome, dbfile);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
urlfn = _free(urlfn);
|
|
|
|
/*@-nullstate -compmempass@*/
|
|
return rc;
|
|
/*@=nullstate =compmempass@*/
|
|
}
|
|
|
|
/** \ingroup db3
|
|
*/
|
|
/*@-exportheadervar@*/
|
|
/*@observer@*/ /*@unchecked@*/
|
|
struct _dbiVec db3vec = {
|
|
DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
|
|
db3open, db3close, db3sync, db3copen, db3cclose, db3cdel, db3cget, db3cput,
|
|
db3ccount, db3byteswapped, db3stat
|
|
};
|
|
/*@=exportheadervar@*/
|
|
/*@=type@*/
|