rpmdb/db3.c

Go to the documentation of this file.
00001 /*@-type@*/ /* FIX: annotate db3 methods */
00006 /*@unchecked@*/
00007 static int _debug = 1;  /* XXX if < 0 debugging, > 0 unusual error returns */
00008 
00009 #include "system.h"
00010 
00011 #if defined(HAVE_FTOK) && defined(HAVE_SYS_IPC_H)
00012 #include <sys/ipc.h>
00013 #endif
00014 
00015 #include <rpmlib.h>
00016 #include <rpmmacro.h>
00017 #include <rpmurl.h>     /* XXX urlPath proto */
00018 
00019 #define _RPMDB_INTERNAL
00020 #include <rpmdb.h>
00021 
00022 #include "debug.h"
00023 
00024 #if !defined(DB_CLIENT) /* XXX db-4.2.42 retrofit */
00025 #define DB_CLIENT       DB_RPCCLIENT
00026 #endif
00027 
00028 /*@access rpmdb @*/
00029 /*@access dbiIndex @*/
00030 /*@access dbiIndexSet @*/
00031 
00035 /*@-fielduse@*/
00036 struct dbiHStats_s {
00037     unsigned int hash_magic;    
00038     unsigned int hash_version;  
00039     unsigned int hash_nkeys;    
00040     unsigned int hash_ndata;    
00041     unsigned int hash_pagesize; 
00042     unsigned int hash_nelem;    
00043     unsigned int hash_ffactor;  
00044     unsigned int hash_buckets;  
00045     unsigned int hash_free;     
00046     unsigned int hash_bfree;    
00047     unsigned int hash_bigpages; 
00048     unsigned int hash_big_bfree;
00049     unsigned int hash_overflows;
00050     unsigned int hash_ovfl_free;
00051     unsigned int hash_dup;      
00052     unsigned int hash_dup_free; 
00053 };
00054 
00058 struct dbiBStats_s {
00059     unsigned int bt_magic;      
00060     unsigned int bt_version;    
00061     unsigned int bt_nkeys;      
00062     unsigned int bt_ndata;      
00063     unsigned int bt_pagesize;   
00064     unsigned int bt_minkey;     
00065     unsigned int bt_re_len;     
00066     unsigned int bt_re_pad;     
00067     unsigned int bt_levels;     
00068     unsigned int bt_int_pg;     
00069     unsigned int bt_leaf_pg;    
00070     unsigned int bt_dup_pg;     
00071     unsigned int bt_over_pg;    
00072     unsigned int bt_free;       
00073     unsigned int bt_int_pgfree; 
00074     unsigned int bt_leaf_pgfree;
00075     unsigned int bt_dup_pgfree; 
00076     unsigned int bt_over_pgfree;
00077 };
00078 /*@=fielduse@*/
00079 
00080 #ifdef  NOTNOW
00081 static const char * bfstring(unsigned int x, const char * xbf)
00082 {
00083     const char * s = xbf;
00084     static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00085     static char buf[BUFSIZ];
00086     char * t, * te;
00087     unsigned radix;
00088     unsigned c, i, k;
00089 
00090     radix = (s != NULL ? *s++ : 16);
00091 
00092     if (radix <= 1 || radix >= 32)
00093         radix = 16;
00094 
00095     t = buf;
00096     switch (radix) {
00097     case 8:     *t++ = '0';     break;
00098     case 16:    *t++ = '0';     *t++ = 'x';     break;
00099     }
00100 
00101     i = 0;
00102     k = x;
00103     do { i++; k /= radix; } while (k);
00104 
00105     te = t + i;
00106 
00107     k = x;
00108     do { --i; t[i] = digits[k % radix]; k /= radix; } while (k);
00109 
00110     t = te;
00111     i = '<';
00112     if (s != NULL)
00113     while ((c = *s++) != '\0') {
00114         if (c > ' ') continue;
00115 
00116         k = (1 << (c - 1));
00117         if (!(x & k)) continue;
00118 
00119         if (t == te) *t++ = '=';
00120 
00121         *t++ = i;
00122         i = ',';
00123         while (*s > ' ')
00124             *t++ = *s++;
00125     }
00126     if (t > te) *t++ = '>';
00127     *t = '\0';
00128     return buf;
00129 }
00130 
00131 /* XXX checked with db-4.5.20 */
00132 static const char * dbtFlags =
00133         "\20\1APPMALLOC\2ISSET\3MALLOC\4PARTIAL\5REALLOC\6USERMEM\7DUPOK";
00134 
00135 static const char * dbenvOpenFlags =
00136         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CDB\20LOCK\21LOG\22MPOOL\23REP\24TXN\25LOCKDOWN\26PRIVATE\27RECOVER_FATAL\30REGISTER\31SYSTEM_MEM";
00137 
00138 static const char * dbOpenFlags =
00139         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17EXCL\20FCNTL_LOCKING\21NO_AUTO_COMMIT\22RDWRMASTER\23WRITEOPEN";
00140 
00141 static const char * dbenvSetFlags =
00142         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CDB_ALLDB\20DIRECT_DB\21DIRECT_LOG\22DSYNC_DB\23DSYNC_LOG\24LOG_AUTOREMOVE\25LOG_INMEMORY\26NOLOCKING\27NOPANIC\30OVERWRITE\31PANIC_ENV\36REGION_INIT\37TIME_NOTGRANTED\40YIELDCPU";
00143 
00144 static const char * dbSetFlags =
00145         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CHKSUM\20DUP\21DUPSORT\22ENCRYPT\23INORDER\24RECNUM\25RENUMBER\26REVSPLITOFF\27SNAPSHOT";
00146 
00147 static const char * dbiModeFlags =
00148         "\20\1WRONLY\2RDWR\7CREAT\10EXCL\11NOCTTY\12TRUNC\13APPEND\14NONBLOCK\15SYNC\16ASYNC\17DIRECT\20LARGEFILE\21DIRECTORY\22NOFOLLOW";
00149 #endif  /* NOTNOW */
00150 
00151 
00152 /*@-globuse -mustmod @*/        /* FIX: rpmError not annotated yet. */
00153 static int cvtdberr(/*@unused@*/ dbiIndex dbi, const char * msg, int error, int printit)
00154         /*@globals fileSystem @*/
00155         /*@modifies fileSystem @*/
00156 {
00157     int rc = error;
00158 
00159     if (printit && rc) {
00160         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00161         if (msg)
00162             rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
00163                 DB_VERSION_MAJOR, rc, msg, db_strerror(error));
00164         else
00165             rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
00166                 DB_VERSION_MAJOR, rc, db_strerror(error));
00167         /*@=moduncon@*/
00168     }
00169 
00170     return rc;
00171 }
00172 /*@=globuse =mustmod @*/
00173 
00174 static int db_fini(dbiIndex dbi, const char * dbhome,
00175                 /*@null@*/ const char * dbfile,
00176                 /*@unused@*/ /*@null@*/ const char * dbsubfile)
00177         /*@globals fileSystem @*/
00178         /*@modifies fileSystem @*/
00179 {
00180     rpmdb rpmdb = dbi->dbi_rpmdb;
00181     DB_ENV * dbenv = rpmdb->db_dbenv;
00182     int rc;
00183 
00184     if (dbenv == NULL)
00185         return 0;
00186 
00187     rc = dbenv->close(dbenv, 0);
00188     rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
00189 
00190     if (dbfile)
00191         rpmMessage(RPMMESS_DEBUG, _("closed   db environment %s/%s\n"),
00192                         dbhome, dbfile);
00193 
00194     if (rpmdb->db_remove_env) {
00195         int xx;
00196 
00197         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00198         xx = db_env_create(&dbenv, 0);
00199         /*@=moduncon@*/
00200         if (!xx && dbenv != NULL) {
00201             xx = cvtdberr(dbi, "db_env_create", xx, _debug);
00202 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00203             xx = dbenv->remove(dbenv, dbhome, DB_FORCE);
00204 #else
00205             xx = dbenv->remove(dbenv, dbhome, NULL, 0);
00206 #endif
00207             xx = cvtdberr(dbi, "dbenv->remove", xx, _debug);
00208 
00209             if (dbfile)
00210                 rpmMessage(RPMMESS_DEBUG, _("removed  db environment %s/%s\n"),
00211                         dbhome, dbfile);
00212         }
00213 
00214     }
00215     return rc;
00216 }
00217 
00218 static int db3_fsync_disable(/*@unused@*/ int fd)
00219         /*@*/
00220 {
00221     return 0;
00222 }
00223 
00224 #if 0
00225 #if HAVE_LIBPTHREAD
00226 #if HAVE_PTHREAD_H
00227 #include <pthread.h>
00228 #endif
00229 
00234 static int db3_pthread_nptl(void)
00235         /*@*/
00236 {
00237     pthread_mutex_t mutex;
00238     pthread_mutexattr_t mutexattr, *mutexattrp = NULL;
00239     pthread_cond_t cond;
00240     pthread_condattr_t condattr, *condattrp = NULL;
00241     int ret = 0;
00242 
00243     ret = pthread_mutexattr_init(&mutexattr);
00244     if (ret == 0) {
00245         ret = pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
00246         mutexattrp = &mutexattr;
00247     }
00248 
00249     if (ret == 0)
00250         ret = pthread_mutex_init(&mutex, mutexattrp);
00251     if (mutexattrp != NULL)
00252         pthread_mutexattr_destroy(mutexattrp);
00253     if (ret)
00254         return ret;
00255     (void) pthread_mutex_destroy(&mutex);
00256 
00257     ret = pthread_condattr_init(&condattr);
00258     if (ret == 0) {
00259         ret = pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED);
00260         condattrp = &condattr;
00261     }
00262 
00263     if (ret == 0)
00264         ret = pthread_cond_init(&cond, condattrp);
00265 
00266     if (condattrp != NULL)
00267         (void)pthread_condattr_destroy(condattrp);
00268     if (ret == 0)
00269         (void) pthread_cond_destroy(&cond);
00270     return ret;
00271 }
00272 #endif
00273 #endif
00274 
00275 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
00276 
00284 static int db3is_alive(/*@unused@*/ DB_ENV *dbenv, pid_t pid, /*@unused@*/ db_threadid_t tid,
00285                 u_int32_t flags)
00286         /*@*/
00287 {
00288     int is_alive = 1;   /* assume all processes are alive */
00289 
00290     switch (flags) {
00291     case DB_MUTEX_PROCESS_ONLY:
00292     case 0:
00293     default:
00294         is_alive = (!(kill(pid, 0) < 0 && errno == ESRCH));
00295         break;
00296     }
00297     return is_alive;
00298 }
00299 #endif
00300 
00301 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00302 static int db_init(dbiIndex dbi, const char * dbhome,
00303                 /*@null@*/ const char * dbfile,
00304                 /*@unused@*/ /*@null@*/ const char * dbsubfile,
00305                 /*@out@*/ DB_ENV ** dbenvp)
00306         /*@globals rpmGlobalMacroContext, h_errno,
00307                 fileSystem @*/
00308         /*@modifies dbi, *dbenvp, fileSystem @*/
00309 {
00310     rpmdb rpmdb = dbi->dbi_rpmdb;
00311     DB_ENV *dbenv = NULL;
00312     int eflags;
00313     int rc;
00314     int xx;
00315 
00316     if (dbenvp == NULL)
00317         return 1;
00318 
00319     /* XXX HACK */
00320     /*@-assignexpose@*/
00321     if (rpmdb->db_errfile == NULL)
00322         rpmdb->db_errfile = stderr;
00323     /*@=assignexpose@*/
00324 
00325     eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
00326     /* Try to join, rather than create, the environment. */
00327     /* XXX DB_JOINENV is defined to 0 in db-4.5.20 */
00328     if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
00329 
00330     if (dbfile)
00331         rpmMessage(RPMMESS_DEBUG, _("opening  db environment %s/%s %s\n"),
00332                 dbhome, dbfile, prDbiOpenFlags(eflags, 1));
00333 
00334     /* XXX Can't do RPC w/o host. */
00335     if (dbi->dbi_host == NULL)
00336         dbi->dbi_ecflags &= ~DB_CLIENT;
00337 
00338     /* XXX Set a default shm_key. */
00339     if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
00340 #if defined(HAVE_FTOK)
00341         dbi->dbi_shmkey = ftok(dbhome, 0);
00342 #else
00343         dbi->dbi_shmkey = 0x44631380;
00344 #endif
00345     }
00346 
00347     rc = db_env_create(&dbenv, dbi->dbi_ecflags);
00348     rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00349     if (dbenv == NULL || rc)
00350         goto errxit;
00351 
00352     /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
00353 
00354  /* 4.1: dbenv->set_app_dispatch(???) */
00355  /* 4.1: dbenv->set_alloc(???) */
00356  /* 4.1: dbenv->set_data_dir(???) */
00357  /* 4.1: dbenv->set_encrypt(???) */
00358 
00359     dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00360     dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00361     dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00362     /*@=noeffectuncon@*/
00363 
00364  /* 4.1: dbenv->set_feedback(???) */
00365  /* 4.1: dbenv->set_flags(???) */
00366 
00367  /* dbenv->set_paniccall(???) */
00368 
00369     if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
00370         const char * home;
00371         int retry = 0;
00372 
00373         if ((home = strrchr(dbhome, '/')) != NULL)
00374             dbhome = ++home;
00375 
00376         while (retry++ < 5) {
00377 /* XXX 3.3.4 change. */
00378 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00379             xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
00380                 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00381             xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00382 #else
00383             xx = dbenv->set_server(dbenv, dbi->dbi_host,
00384                 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00385             xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00386 #endif
00387             if (!xx)
00388                 break;
00389             (void) sleep(15);
00390         }
00391     } else {
00392 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
00393         xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
00394                 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
00395 #endif
00396         xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
00397                 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
00398         xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
00399                 (dbi->dbi_verbose & DB_VERB_RECOVERY));
00400 #if defined(DB_VERB_REGISTER)
00401         xx = dbenv->set_verbose(dbenv, DB_VERB_REGISTER,
00402                 (dbi->dbi_verbose & DB_VERB_REGISTER));
00403 #endif
00404 #if defined(DB_VERB_REPLICATION)
00405         xx = dbenv->set_verbose(dbenv, DB_VERB_REPLICATION,
00406                 (dbi->dbi_verbose & DB_VERB_REPLICATION));
00407 #endif
00408         xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
00409                 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
00410 
00411         if (dbi->dbi_mmapsize) {
00412             xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mmapsize);
00413             xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
00414         }
00415         if (dbi->dbi_tmpdir) {
00416             const char * root;
00417             const char * tmpdir;
00418 
00419             root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00420 /*@-boundsread@*/
00421             if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00422                 root = NULL;
00423 /*@=boundsread@*/
00424 /*@-mods@*/
00425             tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00426 /*@=mods@*/
00427             xx = dbenv->set_tmp_dir(dbenv, tmpdir);
00428             xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug);
00429             tmpdir = _free(tmpdir);
00430         }
00431     }
00432 
00433 /* ==== Locking: */
00434  /* dbenv->set_lk_conflicts(???) */
00435     if (dbi->dbi_lk_detect) {
00436         xx = dbenv->set_lk_detect(dbenv, dbi->dbi_lk_detect);
00437         xx = cvtdberr(dbi, "dbenv->set_lk_detect", xx, _debug);
00438     }
00439 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
00440     if (dbi->dbi_lk_max_lockers) {
00441         xx = dbenv->set_lk_max_lockers(dbenv, dbi->dbi_lk_max_lockers);
00442         xx = cvtdberr(dbi, "dbenv->set_lk_max_lockers", xx, _debug);
00443     }
00444     if (dbi->dbi_lk_max_locks) {
00445         xx = dbenv->set_lk_max_locks(dbenv, dbi->dbi_lk_max_locks);
00446         xx = cvtdberr(dbi, "dbenv->set_lk_max_locks", xx, _debug);
00447     }
00448     if (dbi->dbi_lk_max_objects) {
00449         xx = dbenv->set_lk_max_objects(dbenv, dbi->dbi_lk_max_objects);
00450         xx = cvtdberr(dbi, "dbenv->set_lk_max_objects", xx, _debug);
00451     }
00452 /* ==== Logging: */
00453     if (dbi->dbi_lg_bsize) {
00454         xx = dbenv->set_lg_bsize(dbenv, dbi->dbi_lg_bsize);
00455         xx = cvtdberr(dbi, "dbenv->set_lg_bsize", xx, _debug);
00456     }
00457     if (dbi->dbi_lg_dir) {
00458         xx = dbenv->set_lg_dir(dbenv, dbi->dbi_lg_dir);
00459         xx = cvtdberr(dbi, "dbenv->set_lg_dir", xx, _debug);
00460     }
00461     if (dbi->dbi_lg_filemode) {
00462         xx = dbenv->set_lg_filemode(dbenv, dbi->dbi_lg_filemode);
00463         xx = cvtdberr(dbi, "dbenv->set_lg_filemode", xx, _debug);
00464     }
00465     if (dbi->dbi_lg_max) {
00466         xx = dbenv->set_lg_max(dbenv, dbi->dbi_lg_max);
00467         xx = cvtdberr(dbi, "dbenv->set_lg_max", xx, _debug);
00468     }
00469     if (dbi->dbi_lg_regionmax) {
00470         xx = dbenv->set_lg_regionmax(dbenv, dbi->dbi_lg_regionmax);
00471         xx = cvtdberr(dbi, "dbenv->set_lg_regionmax", xx, _debug);
00472     }
00473 #endif
00474 
00475 /* ==== Memory pool: */
00476     if (dbi->dbi_cachesize) {
00477         xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_cachesize, 0);
00478         xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
00479     }
00480 
00481 /* ==== Mutexes: */
00482     if (dbi->dbi_mutex_align) {
00483         xx = dbenv->mutex_set_align(dbenv, dbi->dbi_mutex_align);
00484         xx = cvtdberr(dbi, "dbenv->mutex_set_align", xx, _debug);
00485     }
00486     if (dbi->dbi_mutex_increment) {
00487         xx = dbenv->mutex_set_increment(dbenv, dbi->dbi_mutex_increment);
00488         xx = cvtdberr(dbi, "dbenv->mutex_set_increment", xx, _debug);
00489     }
00490     if (dbi->dbi_mutex_max) {
00491         xx = dbenv->mutex_set_max(dbenv, dbi->dbi_mutex_max);
00492         xx = cvtdberr(dbi, "dbenv->mutex_set_max", xx, _debug);
00493     }
00494     if (dbi->dbi_mutex_tas_spins) {
00495         xx = dbenv->mutex_set_tas_spins(dbenv, dbi->dbi_mutex_tas_spins);
00496         xx = cvtdberr(dbi, "dbenv->mutex_set_tas_spins", xx, _debug);
00497     }
00498 
00499 /* ==== Replication: */
00500 /* dbenv->rep_set_config */
00501 /* dbenv->rep_set_limit */
00502 /* dbenv->rep_set_nsites */
00503 /* dbenv->rep_set_priority */
00504 /* dbenv->rep_set_timeout */
00505 /* dbenv->rep_set_transport */
00506 
00507 /* ==== Sequences: */
00508 
00509 /* ==== Transactions: */
00510     if (dbi->dbi_tx_max) {
00511         xx = dbenv->set_tx_max(dbenv, dbi->dbi_tx_max);
00512         xx = cvtdberr(dbi, "dbenv->set_tx_max", xx, _debug);
00513     }
00514 /* XXX dbenv->txn_checkpoint */        
00515 /* XXX dbenv->txn_recover */
00516 /* XXX dbenv->txn_stat */
00517  /* 4.1 dbenv->set_timeout(???) */
00518  /* 4.1: dbenv->set_tx_timestamp(???) */
00519 
00520 
00521 /* ==== Other: */
00522     if (dbi->dbi_no_fsync) {
00523 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00524         xx = db_env_set_func_fsync(db3_fsync_disable);
00525 #else
00526         xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable);
00527 #endif
00528         xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
00529     }
00530 
00531     if (dbi->dbi_shmkey) {
00532         xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
00533         xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
00534     }
00535 
00536 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
00537     /* XXX capture dbenv->falchk output on stderr. */
00538 /*@-noeffectuncon@*/
00539     dbenv->set_msgfile(dbenv, rpmdb->db_errfile);
00540 /*@=noeffectuncon@*/
00541     /* XXX must be at least 8, and __db* files need nuking to instantiate. */
00542     if (dbi->dbi_thread_count >= 8) {
00543         xx = dbenv->set_thread_count(dbenv, dbi->dbi_thread_count);
00544         xx = cvtdberr(dbi, "dbenv->set_thread_count", xx, _debug);
00545     }
00546 #endif
00547 
00548 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00549     rc = dbenv->open(dbenv, dbhome, eflags, dbi->dbi_perms);
00550 #else
00551     rc = dbenv->open(dbenv, dbhome, NULL, eflags, dbi->dbi_perms);
00552 #endif
00553     xx = _debug;
00554 #if defined(DB_VERSION_MISMATCH)
00555     if (rc == DB_VERSION_MISMATCH) xx = 0;
00556 #endif
00557     if (rc == EINVAL) xx = 0;
00558     rc = cvtdberr(dbi, "dbenv->open", rc, xx);
00559     if (rc)
00560         goto errxit;
00561 
00562 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
00563     if (!rpmdb->db_verifying && dbi->dbi_thread_count >= 8) {
00564         /* XXX Set pid/tid is_alive probe. */
00565         xx = dbenv->set_isalive(dbenv, db3is_alive);
00566         xx = cvtdberr(dbi, "dbenv->set_isalive", xx, _debug);
00567         /* XXX Clean out stale shared read locks. */
00568         xx = dbenv->failchk(dbenv, 0);
00569         xx = cvtdberr(dbi, "dbenv->failchk", xx, _debug);
00570         if (xx == DB_RUNRECOVERY) {
00571             rc = xx;
00572             goto errxit;
00573         }
00574     }
00575 #endif
00576 
00577 /*@-boundswrite@*/
00578     *dbenvp = dbenv;
00579 /*@=boundswrite@*/
00580 
00581     return 0;
00582 
00583 errxit:
00584     if (dbenv) {
00585         xx = dbenv->close(dbenv, 0);
00586         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
00587     }
00588     return rc;
00589 }
00590 /*@=moduncon@*/
00591 
00592 static int db3sync(dbiIndex dbi, unsigned int flags)
00593         /*@globals fileSystem @*/
00594         /*@modifies fileSystem @*/
00595 {
00596     DB * db = dbi->dbi_db;
00597     int rc = 0;
00598     int _printit;
00599 
00600     if (db != NULL)
00601         rc = db->sync(db, flags);
00602 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
00603     _printit = _debug;
00604 #else
00605     /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
00606     _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
00607 #endif
00608     rc = cvtdberr(dbi, "db->sync", rc, _printit);
00609     return rc;
00610 }
00611 
00612 static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
00613                 unsigned int flags)
00614         /*@globals fileSystem @*/
00615         /*@modifies *dbcp, fileSystem @*/
00616 {
00617     int rc;
00618 
00619 /*@-boundswrite@*/
00620     if (dbcp) *dbcp = NULL;
00621 /*@=boundswrite@*/
00622     rc = dbcursor->c_dup(dbcursor, dbcp, flags);
00623     rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
00624     /*@-nullstate @*/ /* FIX: *dbcp can be NULL */
00625     return rc;
00626     /*@=nullstate @*/
00627 }
00628 
00629 /*@-mustmod@*/
00630 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
00631                 /*@unused@*/ unsigned int flags)
00632         /*@globals fileSystem @*/
00633         /*@modifies dbi, fileSystem @*/
00634 {
00635     int rc = -2;
00636 
00637     /* XXX db3copen error pathways come through here. */
00638     if (dbcursor != NULL) {
00639         rc = dbcursor->c_close(dbcursor);
00640         rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
00641     }
00642     return rc;
00643 }
00644 /*@=mustmod@*/
00645 
00646 static int db3copen(dbiIndex dbi, DB_TXN * txnid,
00647                 /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int dbiflags)
00648         /*@globals fileSystem @*/
00649         /*@modifies dbi, *dbcp, fileSystem @*/
00650 {
00651     DB * db = dbi->dbi_db;
00652     DBC * dbcursor = NULL;
00653     int flags;
00654     int rc;
00655 
00656    /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */
00657     assert(db != NULL);
00658     if ((dbiflags & DB_WRITECURSOR) &&
00659         (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
00660     {
00661         flags = DB_WRITECURSOR;
00662     } else
00663         flags = 0;
00664 
00665     rc = db->cursor(db, txnid, &dbcursor, flags);
00666     rc = cvtdberr(dbi, "db->cursor", rc, _debug);
00667 
00668     if (dbcp)
00669         /*@-boundswrite -onlytrans@*/ *dbcp = dbcursor; /*@=boundswrite =onlytrans@*/
00670     else
00671         (void) db3cclose(dbi, dbcursor, 0);
00672 
00673     return rc;
00674 }
00675 
00676 static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
00677                 /*@unused@*/ unsigned int flags)
00678         /*@globals fileSystem @*/
00679         /*@modifies fileSystem @*/
00680 {
00681     DB * db = dbi->dbi_db;
00682     int rc;
00683 
00684     assert(db != NULL);
00685     if (dbcursor == NULL) {
00686         rc = db->put(db, dbi->dbi_txnid, key, data, 0);
00687         rc = cvtdberr(dbi, "db->put", rc, _debug);
00688     } else {
00689         rc = dbcursor->c_put(dbcursor, key, data, DB_KEYLAST);
00690         rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
00691     }
00692 
00693     return rc;
00694 }
00695 
00696 /*@-mustmod@*/
00697 static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
00698                 unsigned int flags)
00699         /*@globals fileSystem @*/
00700         /*@modifies *dbcursor, fileSystem @*/
00701 {
00702     DB * db = dbi->dbi_db;
00703     int rc;
00704 
00705     assert(db != NULL);
00706     if (dbcursor == NULL) {
00707         rc = db->del(db, dbi->dbi_txnid, key, flags);
00708         rc = cvtdberr(dbi, "db->del", rc, _debug);
00709     } else {
00710         int _printit;
00711 
00712         /* XXX TODO: insure that cursor is positioned with duplicates */
00713         rc = dbcursor->c_get(dbcursor, key, data, DB_SET);
00714         /* XXX DB_NOTFOUND can be returned */
00715         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00716         rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
00717 
00718         if (rc == 0) {
00719             rc = dbcursor->c_del(dbcursor, flags);
00720             rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
00721         }
00722     }
00723 
00724     return rc;
00725 }
00726 /*@=mustmod@*/
00727 
00728 /*@-mustmod@*/
00729 static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
00730                 unsigned int flags)
00731         /*@globals fileSystem @*/
00732         /*@modifies *dbcursor, *key, *data, fileSystem @*/
00733 {
00734     DB * db = dbi->dbi_db;
00735     int _printit;
00736     int rc;
00737 
00738     assert(db != NULL);
00739     if (dbcursor == NULL) {
00740         /* XXX duplicates require cursors. */
00741         rc = db->get(db, dbi->dbi_txnid, key, data, 0);
00742         /* XXX DB_NOTFOUND can be returned */
00743         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00744         rc = cvtdberr(dbi, "db->get", rc, _printit);
00745     } else {
00746         /* XXX db3 does DB_FIRST on uninitialized cursor */
00747         rc = dbcursor->c_get(dbcursor, key, data, flags);
00748         /* XXX DB_NOTFOUND can be returned */
00749         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00750         rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
00751     }
00752 
00753     return rc;
00754 }
00755 /*@=mustmod@*/
00756 
00757 /*@-mustmod@*/
00758 static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey,
00759                 DBT * data, unsigned int flags)
00760         /*@globals fileSystem @*/
00761         /*@modifies *dbcursor, *key, *data, fileSystem @*/
00762 {
00763     DB * db = dbi->dbi_db;
00764     int _printit;
00765     int rc;
00766 
00767     assert(db != NULL);
00768     assert(dbcursor != NULL);
00769 
00770     /* XXX db3 does DB_FIRST on uninitialized cursor */
00771     rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags);
00772     /* XXX DB_NOTFOUND can be returned */
00773     _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00774     rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit);
00775 
00776     return rc;
00777 }
00778 /*@=mustmod@*/
00779 
00780 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
00781                 /*@null@*/ /*@out@*/ unsigned int * countp,
00782                 /*@unused@*/ unsigned int flags)
00783         /*@globals fileSystem @*/
00784         /*@modifies *countp, fileSystem @*/
00785 {
00786     db_recno_t count = 0;
00787     int rc = 0;
00788 
00789     flags = 0;
00790     rc = dbcursor->c_count(dbcursor, &count, flags);
00791     rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
00792     if (rc) return rc;
00793 /*@-boundswrite@*/
00794     if (countp) *countp = count;
00795 /*@=boundswrite@*/
00796 
00797     return rc;
00798 }
00799 
00800 static int db3byteswapped(dbiIndex dbi) /*@*/
00801 {
00802     DB * db = dbi->dbi_db;
00803     int rc = 0;
00804 
00805     if (db != NULL) {
00806 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
00807  || (DB_VERSION_MAJOR == 4)
00808         int isswapped = 0;
00809         rc = db->get_byteswapped(db, &isswapped);
00810         if (rc == 0)
00811             rc = isswapped;
00812 #else
00813         rc = db->get_byteswapped(db);
00814 #endif
00815     }
00816 
00817     return rc;
00818 }
00819 
00820 static int db3stat(dbiIndex dbi, unsigned int flags)
00821         /*@globals fileSystem @*/
00822         /*@modifies dbi, fileSystem @*/
00823 {
00824     DB * db = dbi->dbi_db;
00825 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
00826     DB_TXN * txnid = NULL;
00827 #endif
00828     int rc = 0;
00829 
00830     assert(db != NULL);
00831 #if defined(DB_FAST_STAT)
00832     if (flags)
00833         flags = DB_FAST_STAT;
00834     else
00835 #endif
00836         flags = 0;
00837     dbi->dbi_stats = _free(dbi->dbi_stats);
00838 /* XXX 3.3.4 change. */
00839 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00840 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
00841     rc = db->stat(db, txnid, &dbi->dbi_stats, flags);
00842 #else
00843     rc = db->stat(db, &dbi->dbi_stats, flags);
00844 #endif
00845 #else
00846     rc = db->stat(db, &dbi->dbi_stats, NULL, flags);
00847 #endif
00848     rc = cvtdberr(dbi, "db->stat", rc, _debug);
00849     return rc;
00850 }
00851 
00852 /*@-mustmod@*/
00853 static int db3associate(dbiIndex dbi, dbiIndex dbisecondary,
00854                 int (*callback)(DB *, const DBT *, const DBT *, DBT *),
00855                 unsigned int flags)
00856         /*@globals fileSystem @*/
00857         /*@modifies dbi, fileSystem @*/
00858 {
00859     DB * db = dbi->dbi_db;
00860     DB * secondary = dbisecondary->dbi_db;
00861     int rc;
00862 
00863 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00864 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
00865     DB_TXN * txnid = NULL;
00866 
00867 assert(db != NULL);
00868     rc = db->associate(db, txnid, secondary, callback, flags);
00869 #else
00870 assert(db != NULL);
00871     rc = db->associate(db, secondary, callback, flags);
00872 #endif
00873 /*@=moduncon@*/
00874     rc = cvtdberr(dbi, "db->associate", rc, _debug);
00875     return rc;
00876 }
00877 /*@=mustmod@*/
00878 
00879 /*@-mustmod@*/
00880 static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp,
00881                 unsigned int flags)
00882         /*@globals fileSystem @*/
00883         /*@modifies dbi, fileSystem @*/
00884 {
00885     DB * db = dbi->dbi_db;
00886     int rc;
00887 
00888 assert(db != NULL);
00889 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00890     rc = db->join(db, curslist, dbcp, flags);
00891 /*@=moduncon@*/
00892     rc = cvtdberr(dbi, "db->join", rc, _debug);
00893     return rc;
00894 }
00895 /*@=mustmod@*/
00896 
00897 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00898 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
00899         /*@globals rpmGlobalMacroContext, h_errno,
00900                 fileSystem @*/
00901         /*@modifies dbi, fileSystem @*/
00902 {
00903     rpmdb rpmdb = dbi->dbi_rpmdb;
00904     const char * urlfn = NULL;
00905     const char * root;
00906     const char * home;
00907     const char * dbhome;
00908     const char * dbfile;
00909     const char * dbsubfile;
00910     DB * db = dbi->dbi_db;
00911     int _printit;
00912     int rc = 0, xx;
00913 
00914     flags = 0;  /* XXX unused */
00915 
00916     /*
00917      * Get the prefix/root component and directory path.
00918      */
00919     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00920 /*@-boundsread@*/
00921     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00922         root = NULL;
00923 /*@=boundsread@*/
00924     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
00925 
00926     /*
00927      * Either the root or directory components may be a URL. Concatenate,
00928      * convert the URL to a path, and add the name of the file.
00929      */
00930     /*@-mods@*/
00931     urlfn = rpmGenPath(root, home, NULL);
00932     /*@=mods@*/
00933     (void) urlPath(urlfn, &dbhome);
00934     if (dbi->dbi_temporary) {
00935         dbfile = NULL;
00936         dbsubfile = NULL;
00937     } else {
00938 #ifdef  HACK    /* XXX necessary to support dbsubfile */
00939         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
00940         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
00941 #else
00942         dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
00943         dbsubfile = NULL;
00944 #endif
00945     }
00946 
00947     if (db) {
00948         rc = db->close(db, 0);
00949         /* XXX ignore not found error messages. */
00950         _printit = (rc == ENOENT ? 0 : _debug);
00951         rc = cvtdberr(dbi, "db->close", rc, _printit);
00952         db = dbi->dbi_db = NULL;
00953 
00954         rpmMessage(RPMMESS_DEBUG, _("closed   db index       %s/%s\n"),
00955                 dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
00956 
00957     }
00958 
00959     if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) {
00960         if (rpmdb->db_opens == 1) {
00961             /*@-nullstate@*/
00962             xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
00963             /*@=nullstate@*/
00964             rpmdb->db_dbenv = NULL;
00965         }
00966         rpmdb->db_opens--;
00967     }
00968 
00969     if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
00970         DB_ENV * dbenv = NULL;
00971         int eflags;
00972 
00973         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00974         rc = db_env_create(&dbenv, 0);
00975         /*@=moduncon@*/
00976         rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00977         if (rc || dbenv == NULL) goto exit;
00978 
00979         /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
00980         dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00981         dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00982         dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00983  /*     dbenv->set_paniccall(???) */
00984         /*@=noeffectuncon@*/
00985 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
00986         xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
00987                 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
00988 #endif
00989         xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
00990                 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
00991         xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
00992                 (dbi->dbi_verbose & DB_VERB_RECOVERY));
00993         xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
00994                 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
00995 
00996         if (dbi->dbi_tmpdir) {
00997             /*@-mods@*/
00998             const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00999             /*@=mods@*/
01000             rc = dbenv->set_tmp_dir(dbenv, tmpdir);
01001             rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
01002             tmpdir = _free(tmpdir);
01003             if (rc) goto exit;
01004         }
01005             
01006         eflags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON;
01007         rc = dbenv->open(dbenv, dbhome, eflags, 0);
01008         rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
01009         if (rc) goto exit;
01010 
01011         /*@-moduncon -nullstate@*/ /* FIX: annotate db3 methods */
01012         rc = db_create(&db, dbenv, 0);
01013         /*@=moduncon =nullstate@*/
01014         rc = cvtdberr(dbi, "db_create", rc, _debug);
01015 
01016         if (db != NULL) {
01017                 /*@-mods@*/
01018                 const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
01019                 /*@=mods@*/
01020 
01021                 rc = db->verify(db, dbf, NULL, NULL, flags);
01022                 rc = cvtdberr(dbi, "db->verify", rc, _debug);
01023 
01024                 rpmMessage(RPMMESS_DEBUG, _("verified db index       %s/%s\n"),
01025                         (dbhome ? dbhome : ""),
01026                         (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
01027 
01028                 /*
01029                  * The DB handle may not be accessed again after
01030                  * DB->verify is called, regardless of its return.
01031                  */
01032                 db = NULL;
01033                 dbf = _free(dbf);
01034         }
01035         xx = dbenv->close(dbenv, 0);
01036         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
01037         if (rc == 0 && xx) rc = xx;
01038     }
01039 
01040 exit:
01041     dbi->dbi_db = NULL;
01042 
01043     urlfn = _free(urlfn);
01044 
01045     dbi = db3Free(dbi);
01046 
01047     return rc;
01048 }
01049 /*@=moduncon@*/
01050 
01051 static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip)
01052         /*@globals rpmGlobalMacroContext, h_errno,
01053                 fileSystem, internalState @*/
01054         /*@modifies *dbip, fileSystem, internalState @*/
01055 {
01056     /*@-nestedextern -shadow@*/
01057     extern struct _dbiVec db3vec;
01058     /*@=nestedextern =shadow@*/
01059     const char * urlfn = NULL;
01060     const char * root;
01061     const char * home;
01062     const char * dbhome;
01063     const char * dbfile;
01064     const char * dbsubfile;
01065     dbiIndex dbi = NULL;
01066     int rc = 0;
01067     int xx;
01068 
01069     DB * db = NULL;
01070     DB_ENV * dbenv = NULL;
01071 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
01072     DB_TXN * txnid = NULL;
01073 #endif
01074     DBTYPE dbi_type = DB_UNKNOWN;
01075     u_int32_t oflags;
01076     int _printit;
01077 
01078 /*@-boundswrite@*/
01079     if (dbip)
01080         *dbip = NULL;
01081 /*@=boundswrite@*/
01082 
01083     /*
01084      * Parse db configuration parameters.
01085      */
01086     /*@-mods@*/
01087     if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
01088         /*@-nullstate@*/
01089         return 1;
01090         /*@=nullstate@*/
01091     /*@=mods@*/
01092     dbi->dbi_api = DB_VERSION_MAJOR;
01093 
01094     /*
01095      * Get the prefix/root component and directory path.
01096      */
01097     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
01098 /*@-boundsread@*/
01099     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
01100         root = NULL;
01101 /*@=boundsread@*/
01102     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
01103 
01104     /*
01105      * Either the root or directory components may be a URL. Concatenate,
01106      * convert the URL to a path, and add the name of the file.
01107      */
01108     /*@-mods@*/
01109     urlfn = rpmGenPath(root, home, NULL);
01110     /*@=mods@*/
01111     (void) urlPath(urlfn, &dbhome);
01112     if (dbi->dbi_temporary) {
01113         dbfile = NULL;
01114         dbsubfile = NULL;
01115     } else {
01116 #ifdef  HACK    /* XXX necessary to support dbsubfile */
01117         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
01118         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
01119 #else
01120         dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
01121         dbsubfile = NULL;
01122 #endif
01123     }
01124 
01125     oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
01126     oflags &= ~DB_TRUNCATE;     /* XXX this is dangerous */
01127 
01128 #if 0   /* XXX rpmdb: illegal flag combination specified to DB->open */
01129     if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
01130 #endif
01131 
01132     /*
01133      * Map open mode flags onto configured database/environment flags.
01134      */
01135     if (dbi->dbi_temporary) {
01136         oflags |= DB_CREATE;
01137         dbi->dbi_oeflags |= DB_CREATE;
01138         oflags &= ~DB_RDONLY;
01139         dbi->dbi_oflags &= ~DB_RDONLY;
01140     } else {
01141         if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
01142         if (dbi->dbi_mode & O_CREAT) {
01143             oflags |= DB_CREATE;
01144             dbi->dbi_oeflags |= DB_CREATE;
01145         }
01146 #ifdef  DANGEROUS
01147         if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE;
01148 #endif
01149     }
01150 
01151     /*
01152      * Create the /var/lib/rpm directory if it doesn't exist (root only).
01153      */
01154     (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
01155 
01156     /*
01157      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open.
01158      */
01159     if (dbi->dbi_use_dbenv) {
01160 
01161 #if 0
01162 #if HAVE_LIBPTHREAD
01163         if (rpmdb->db_dbenv == NULL) {
01164             /* Set DB_PRIVATE if posix mutexes are not shared. */
01165             xx = db3_pthread_nptl();
01166             if (xx) {
01167                 dbi->dbi_eflags |= DB_PRIVATE;
01168                 rpmMessage(RPMMESS_DEBUG, _("unshared posix mutexes found(%d), adding DB_PRIVATE, using fcntl lock\n"), xx);
01169             }
01170         }
01171 #endif
01172 #endif
01173 
01174         if (access(dbhome, W_OK) == -1) {
01175 
01176             /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */
01177             oflags &= ~DB_CREATE;
01178 
01179             /* ... but DBENV->open might still need DB_CREATE ... */
01180             if (dbi->dbi_eflags & DB_PRIVATE) {
01181                 dbi->dbi_eflags &= ~DB_JOINENV;
01182             } else {
01183                 dbi->dbi_eflags |= DB_JOINENV;
01184                 dbi->dbi_oeflags &= ~DB_CREATE;
01185                 dbi->dbi_oeflags &= ~DB_THREAD;
01186                 /* ... but, unless DB_PRIVATE is used, skip DBENV. */
01187                 dbi->dbi_use_dbenv = 0;
01188             }
01189 
01190             /* ... DB_RDONLY maps dbhome perms across files ...  */
01191             if (dbi->dbi_temporary) {
01192                 oflags |= DB_CREATE;
01193                 dbi->dbi_oeflags |= DB_CREATE;
01194                 oflags &= ~DB_RDONLY;
01195                 dbi->dbi_oflags &= ~DB_RDONLY;
01196             } else {
01197                 oflags |= DB_RDONLY;
01198                 /* ... and DB_WRITECURSOR won't be needed ...  */
01199                 dbi->dbi_oflags |= DB_RDONLY;
01200             }
01201 
01202         } else {        /* dbhome is writable, check for persistent dbenv. */
01203             /*@-mods@*/
01204             const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
01205             /*@=mods@*/
01206 
01207             if (access(dbf, F_OK) == -1) {
01208                 /* ... non-existent (or unwritable) DBENV, will create ... */
01209                 dbi->dbi_oeflags |= DB_CREATE;
01210                 dbi->dbi_eflags &= ~DB_JOINENV;
01211             } else {
01212                 /* ... pre-existent (or bogus) DBENV, will join ... */
01213                 if (dbi->dbi_eflags & DB_PRIVATE) {
01214                     dbi->dbi_eflags &= ~DB_JOINENV;
01215                 } else {
01216                     dbi->dbi_eflags |= DB_JOINENV;
01217                     dbi->dbi_oeflags &= ~DB_CREATE;
01218                     dbi->dbi_oeflags &= ~DB_THREAD;
01219                 }
01220             }
01221             dbf = _free(dbf);
01222         }
01223     }
01224 
01225     /*
01226      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open.
01227      */
01228     if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
01229         /* dbhome is writable, and DB->open flags may conflict. */
01230         const char * dbfn = (dbfile ? dbfile : tagName(dbi->dbi_rpmtag));
01231         /*@-mods@*/
01232         const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
01233         /*@=mods@*/
01234 
01235         if (access(dbf, F_OK) == -1) {
01236             /* File does not exist, DB->open might create ... */
01237             oflags &= ~DB_RDONLY;
01238         } else {
01239             /* File exists, DB->open need not create ... */
01240             oflags &= ~DB_CREATE;
01241         }
01242 
01243         /* Only writers need DB_WRITECURSOR ... */
01244         if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
01245             dbi->dbi_oflags &= ~DB_RDONLY;
01246         } else {
01247             dbi->dbi_oflags |= DB_RDONLY;
01248         }
01249         dbf = _free(dbf);
01250     }
01251 
01252     /*