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 
00179 static const char * mapTagName(int value)
00180         /*@*/
00181 {
00182     const char * s = tagName(value);
00183     if (s == NULL)
00184         s = "";
00185 #ifdef  NOTYET
00186     else if (!strcmp(s, "Filedigests"))
00187         s = "Filemd5s";
00188 #endif
00189     return s;
00190 }
00191 
00192 static int db_fini(dbiIndex dbi, const char * dbhome,
00193                 /*@null@*/ const char * dbfile,
00194                 /*@unused@*/ /*@null@*/ const char * dbsubfile)
00195         /*@globals fileSystem @*/
00196         /*@modifies fileSystem @*/
00197 {
00198     rpmdb rpmdb = dbi->dbi_rpmdb;
00199     DB_ENV * dbenv = rpmdb->db_dbenv;
00200     int rc;
00201 
00202     if (dbenv == NULL)
00203         return 0;
00204 
00205     rc = dbenv->close(dbenv, 0);
00206     rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
00207 
00208     if (dbfile)
00209         rpmMessage(RPMMESS_DEBUG, D_("closed   db environment %s/%s\n"),
00210                         dbhome, dbfile);
00211 
00212     if (rpmdb->db_remove_env) {
00213         int xx;
00214 
00215         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00216         xx = db_env_create(&dbenv, 0);
00217         /*@=moduncon@*/
00218         if (!xx && dbenv != NULL) {
00219             xx = cvtdberr(dbi, "db_env_create", xx, _debug);
00220 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00221             xx = dbenv->remove(dbenv, dbhome, DB_FORCE);
00222 #else
00223             xx = dbenv->remove(dbenv, dbhome, NULL, 0);
00224 #endif
00225             xx = cvtdberr(dbi, "dbenv->remove", xx, _debug);
00226 
00227             if (dbfile)
00228                 rpmMessage(RPMMESS_DEBUG, D_("removed  db environment %s/%s\n"),
00229                         dbhome, dbfile);
00230         }
00231 
00232     }
00233     return rc;
00234 }
00235 
00236 static int db3_fsync_disable(/*@unused@*/ int fd)
00237         /*@*/
00238 {
00239     return 0;
00240 }
00241 
00242 #if 0
00243 #if HAVE_LIBPTHREAD
00244 #if HAVE_PTHREAD_H
00245 #include <pthread.h>
00246 #endif
00247 
00252 static int db3_pthread_nptl(void)
00253         /*@*/
00254 {
00255     pthread_mutex_t mutex;
00256     pthread_mutexattr_t mutexattr, *mutexattrp = NULL;
00257     pthread_cond_t cond;
00258     pthread_condattr_t condattr, *condattrp = NULL;
00259     int ret = 0;
00260 
00261     ret = pthread_mutexattr_init(&mutexattr);
00262     if (ret == 0) {
00263         ret = pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
00264         mutexattrp = &mutexattr;
00265     }
00266 
00267     if (ret == 0)
00268         ret = pthread_mutex_init(&mutex, mutexattrp);
00269     if (mutexattrp != NULL)
00270         pthread_mutexattr_destroy(mutexattrp);
00271     if (ret)
00272         return ret;
00273     (void) pthread_mutex_destroy(&mutex);
00274 
00275     ret = pthread_condattr_init(&condattr);
00276     if (ret == 0) {
00277         ret = pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED);
00278         condattrp = &condattr;
00279     }
00280 
00281     if (ret == 0)
00282         ret = pthread_cond_init(&cond, condattrp);
00283 
00284     if (condattrp != NULL)
00285         (void)pthread_condattr_destroy(condattrp);
00286     if (ret == 0)
00287         (void) pthread_cond_destroy(&cond);
00288     return ret;
00289 }
00290 #endif
00291 #endif
00292 
00293 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
00294 
00302 static int db3is_alive(/*@unused@*/ DB_ENV *dbenv, pid_t pid, /*@unused@*/ db_threadid_t tid,
00303                 u_int32_t flags)
00304         /*@*/
00305 {
00306     int is_alive = 1;   /* assume all processes are alive */
00307 
00308     switch (flags) {
00309     case DB_MUTEX_PROCESS_ONLY:
00310     case 0:
00311     default:
00312         is_alive = (!(kill(pid, 0) < 0 && errno == ESRCH));
00313         break;
00314     }
00315     return is_alive;
00316 }
00317 #endif
00318 
00319 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00320 static int db_init(dbiIndex dbi, const char * dbhome,
00321                 /*@null@*/ const char * dbfile,
00322                 /*@unused@*/ /*@null@*/ const char * dbsubfile,
00323                 /*@out@*/ DB_ENV ** dbenvp)
00324         /*@globals rpmGlobalMacroContext, h_errno,
00325                 fileSystem @*/
00326         /*@modifies dbi, *dbenvp, fileSystem @*/
00327 {
00328     rpmdb rpmdb = dbi->dbi_rpmdb;
00329     DB_ENV *dbenv = NULL;
00330     int eflags;
00331     int rc;
00332     int xx;
00333 
00334     if (dbenvp == NULL)
00335         return 1;
00336 
00337     /* XXX HACK */
00338     /*@-assignexpose@*/
00339     if (rpmdb->db_errfile == NULL)
00340         rpmdb->db_errfile = stderr;
00341     /*@=assignexpose@*/
00342 
00343     eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
00344     /* Try to join, rather than create, the environment. */
00345     /* XXX DB_JOINENV is defined to 0 in db-4.5.20 */
00346     if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
00347 
00348     if (dbfile)
00349         rpmMessage(RPMMESS_DEBUG, D_("opening  db environment %s/%s %s\n"),
00350                 dbhome, dbfile, prDbiOpenFlags(eflags, 1));
00351 
00352     /* XXX Can't do RPC w/o host. */
00353     if (dbi->dbi_host == NULL)
00354         dbi->dbi_ecflags &= ~DB_CLIENT;
00355 
00356     /* XXX Set a default shm_key. */
00357     if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
00358 #if defined(HAVE_FTOK)
00359         dbi->dbi_shmkey = ftok(dbhome, 0);
00360 #else
00361         dbi->dbi_shmkey = 0x44631380;
00362 #endif
00363     }
00364 
00365     rc = db_env_create(&dbenv, dbi->dbi_ecflags);
00366     rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00367     if (dbenv == NULL || rc)
00368         goto errxit;
00369 
00370     /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
00371 
00372  /* 4.1: dbenv->set_app_dispatch(???) */
00373  /* 4.1: dbenv->set_alloc(???) */
00374  /* 4.1: dbenv->set_data_dir(???) */
00375  /* 4.1: dbenv->set_encrypt(???) */
00376 
00377     dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00378     dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00379     dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00380     /*@=noeffectuncon@*/
00381 
00382  /* 4.1: dbenv->set_feedback(???) */
00383  /* 4.1: dbenv->set_flags(???) */
00384 
00385  /* dbenv->set_paniccall(???) */
00386 
00387     if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
00388         const char * home;
00389         int retry = 0;
00390 
00391         if ((home = strrchr(dbhome, '/')) != NULL)
00392             dbhome = ++home;
00393 
00394         while (retry++ < 5) {
00395 /* XXX 3.3.4 change. */
00396 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00397             xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
00398                 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00399             xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00400 #else
00401             xx = dbenv->set_server(dbenv, dbi->dbi_host,
00402                 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00403             xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00404 #endif
00405             if (!xx)
00406                 break;
00407             (void) sleep(15);
00408         }
00409     } else {
00410 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
00411         xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
00412                 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
00413 #endif
00414         xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
00415                 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
00416         xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
00417                 (dbi->dbi_verbose & DB_VERB_RECOVERY));
00418 #if defined(DB_VERB_REGISTER)
00419         xx = dbenv->set_verbose(dbenv, DB_VERB_REGISTER,
00420                 (dbi->dbi_verbose & DB_VERB_REGISTER));
00421 #endif
00422 #if defined(DB_VERB_REPLICATION)
00423         xx = dbenv->set_verbose(dbenv, DB_VERB_REPLICATION,
00424                 (dbi->dbi_verbose & DB_VERB_REPLICATION));
00425 #endif
00426         xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
00427                 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
00428 
00429         if (dbi->dbi_mmapsize) {
00430             xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mmapsize);
00431             xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
00432         }
00433         if (dbi->dbi_tmpdir) {
00434             const char * root;
00435             const char * tmpdir;
00436 
00437             root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00438 /*@-boundsread@*/
00439             if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00440                 root = NULL;
00441 /*@=boundsread@*/
00442 /*@-mods@*/
00443             tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00444 /*@=mods@*/
00445             xx = dbenv->set_tmp_dir(dbenv, tmpdir);
00446             xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug);
00447             tmpdir = _free(tmpdir);
00448         }
00449     }
00450 
00451 /* ==== Locking: */
00452  /* dbenv->set_lk_conflicts(???) */
00453     if (dbi->dbi_lk_detect) {
00454         xx = dbenv->set_lk_detect(dbenv, dbi->dbi_lk_detect);
00455         xx = cvtdberr(dbi, "dbenv->set_lk_detect", xx, _debug);
00456     }
00457 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
00458     if (dbi->dbi_lk_max_lockers) {
00459         xx = dbenv->set_lk_max_lockers(dbenv, dbi->dbi_lk_max_lockers);
00460         xx = cvtdberr(dbi, "dbenv->set_lk_max_lockers", xx, _debug);
00461     }
00462     if (dbi->dbi_lk_max_locks) {
00463         xx = dbenv->set_lk_max_locks(dbenv, dbi->dbi_lk_max_locks);
00464         xx = cvtdberr(dbi, "dbenv->set_lk_max_locks", xx, _debug);
00465     }
00466     if (dbi->dbi_lk_max_objects) {
00467         xx = dbenv->set_lk_max_objects(dbenv, dbi->dbi_lk_max_objects);
00468         xx = cvtdberr(dbi, "dbenv->set_lk_max_objects", xx, _debug);
00469     }
00470 /* ==== Logging: */
00471     if (dbi->dbi_lg_bsize) {
00472         xx = dbenv->set_lg_bsize(dbenv, dbi->dbi_lg_bsize);
00473         xx = cvtdberr(dbi, "dbenv->set_lg_bsize", xx, _debug);
00474     }
00475     if (dbi->dbi_lg_dir) {
00476         xx = dbenv->set_lg_dir(dbenv, dbi->dbi_lg_dir);
00477         xx = cvtdberr(dbi, "dbenv->set_lg_dir", xx, _debug);
00478     }
00479     if (dbi->dbi_lg_filemode) {
00480         xx = dbenv->set_lg_filemode(dbenv, dbi->dbi_lg_filemode);
00481         xx = cvtdberr(dbi, "dbenv->set_lg_filemode", xx, _debug);
00482     }
00483     if (dbi->dbi_lg_max) {
00484         xx = dbenv->set_lg_max(dbenv, dbi->dbi_lg_max);
00485         xx = cvtdberr(dbi, "dbenv->set_lg_max", xx, _debug);
00486     }
00487     if (dbi->dbi_lg_regionmax) {
00488         xx = dbenv->set_lg_regionmax(dbenv, dbi->dbi_lg_regionmax);
00489         xx = cvtdberr(dbi, "dbenv->set_lg_regionmax", xx, _debug);
00490     }
00491 #endif
00492 
00493 /* ==== Memory pool: */
00494     if (dbi->dbi_cachesize) {
00495         xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_cachesize, 0);
00496         xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
00497     }
00498 
00499 /* ==== Mutexes: */
00500     if (dbi->dbi_mutex_align) {
00501         xx = dbenv->mutex_set_align(dbenv, dbi->dbi_mutex_align);
00502         xx = cvtdberr(dbi, "dbenv->mutex_set_align", xx, _debug);
00503     }
00504     if (dbi->dbi_mutex_increment) {
00505         xx = dbenv->mutex_set_increment(dbenv, dbi->dbi_mutex_increment);
00506         xx = cvtdberr(dbi, "dbenv->mutex_set_increment", xx, _debug);
00507     }
00508     if (dbi->dbi_mutex_max) {
00509         xx = dbenv->mutex_set_max(dbenv, dbi->dbi_mutex_max);
00510         xx = cvtdberr(dbi, "dbenv->mutex_set_max", xx, _debug);
00511     }
00512     if (dbi->dbi_mutex_tas_spins) {
00513         xx = dbenv->mutex_set_tas_spins(dbenv, dbi->dbi_mutex_tas_spins);
00514         xx = cvtdberr(dbi, "dbenv->mutex_set_tas_spins", xx, _debug);
00515     }
00516 
00517 /* ==== Replication: */
00518 /* dbenv->rep_set_config */
00519 /* dbenv->rep_set_limit */
00520 /* dbenv->rep_set_nsites */
00521 /* dbenv->rep_set_priority */
00522 /* dbenv->rep_set_timeout */
00523 /* dbenv->rep_set_transport */
00524 
00525 /* ==== Sequences: */
00526 
00527 /* ==== Transactions: */
00528     if (dbi->dbi_tx_max) {
00529         xx = dbenv->set_tx_max(dbenv, dbi->dbi_tx_max);
00530         xx = cvtdberr(dbi, "dbenv->set_tx_max", xx, _debug);
00531     }
00532 /* XXX dbenv->txn_checkpoint */        
00533 /* XXX dbenv->txn_recover */
00534 /* XXX dbenv->txn_stat */
00535  /* 4.1 dbenv->set_timeout(???) */
00536  /* 4.1: dbenv->set_tx_timestamp(???) */
00537 
00538 
00539 /* ==== Other: */
00540     if (dbi->dbi_no_fsync) {
00541 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00542         xx = db_env_set_func_fsync(db3_fsync_disable);
00543 #else
00544         xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable);
00545 #endif
00546         xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
00547     }
00548 
00549     if (dbi->dbi_shmkey) {
00550         xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
00551         xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
00552     }
00553 
00554 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
00555     /* XXX capture dbenv->falchk output on stderr. */
00556 /*@-noeffectuncon@*/
00557     dbenv->set_msgfile(dbenv, rpmdb->db_errfile);
00558 /*@=noeffectuncon@*/
00559     /* XXX must be at least 8, and __db* files need nuking to instantiate. */
00560     if (dbi->dbi_thread_count >= 8) {
00561         xx = dbenv->set_thread_count(dbenv, dbi->dbi_thread_count);
00562         xx = cvtdberr(dbi, "dbenv->set_thread_count", xx, _debug);
00563     }
00564 #endif
00565 
00566 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00567     rc = dbenv->open(dbenv, dbhome, eflags, dbi->dbi_perms);
00568 #else
00569     rc = dbenv->open(dbenv, dbhome, NULL, eflags, dbi->dbi_perms);
00570 #endif
00571     xx = _debug;
00572 #if defined(DB_VERSION_MISMATCH)
00573     if (rc == DB_VERSION_MISMATCH) xx = 0;
00574 #endif
00575     if (rc == EINVAL) xx = 0;
00576     rc = cvtdberr(dbi, "dbenv->open", rc, xx);
00577     if (rc)
00578         goto errxit;
00579 
00580 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
00581     if (!rpmdb->db_verifying && dbi->dbi_thread_count >= 8) {
00582         /* XXX Set pid/tid is_alive probe. */
00583         xx = dbenv->set_isalive(dbenv, db3is_alive);
00584         xx = cvtdberr(dbi, "dbenv->set_isalive", xx, _debug);
00585         /* XXX Clean out stale shared read locks. */
00586         xx = dbenv->failchk(dbenv, 0);
00587         xx = cvtdberr(dbi, "dbenv->failchk", xx, _debug);
00588         if (xx == DB_RUNRECOVERY) {
00589             rc = xx;
00590             goto errxit;
00591         }
00592     }
00593 #endif
00594 
00595 /*@-boundswrite@*/
00596     *dbenvp = dbenv;
00597 /*@=boundswrite@*/
00598 
00599     return 0;
00600 
00601 errxit:
00602     if (dbenv) {
00603         xx = dbenv->close(dbenv, 0);
00604         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
00605     }
00606     return rc;
00607 }
00608 /*@=moduncon@*/
00609 
00610 static int db3sync(dbiIndex dbi, unsigned int flags)
00611         /*@globals fileSystem @*/
00612         /*@modifies fileSystem @*/
00613 {
00614     DB * db = dbi->dbi_db;
00615     int rc = 0;
00616     int _printit;
00617 
00618     if (db != NULL)
00619         rc = db->sync(db, flags);
00620 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
00621     _printit = _debug;
00622 #else
00623     /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
00624     _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
00625 #endif
00626     rc = cvtdberr(dbi, "db->sync", rc, _printit);
00627     return rc;
00628 }
00629 
00630 static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
00631                 unsigned int flags)
00632         /*@globals fileSystem @*/
00633         /*@modifies *dbcp, fileSystem @*/
00634 {
00635     int rc;
00636 
00637 /*@-boundswrite@*/
00638     if (dbcp) *dbcp = NULL;
00639 /*@=boundswrite@*/
00640     rc = dbcursor->c_dup(dbcursor, dbcp, flags);
00641     rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
00642     /*@-nullstate @*/ /* FIX: *dbcp can be NULL */
00643     return rc;
00644     /*@=nullstate @*/
00645 }
00646 
00647 /*@-mustmod@*/
00648 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
00649                 /*@unused@*/ unsigned int flags)
00650         /*@globals fileSystem @*/
00651         /*@modifies dbi, fileSystem @*/
00652 {
00653     int rc = -2;
00654 
00655     /* XXX db3copen error pathways come through here. */
00656     if (dbcursor != NULL) {
00657         rc = dbcursor->c_close(dbcursor);
00658         rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
00659     }
00660     return rc;
00661 }
00662 /*@=mustmod@*/
00663 
00664 static int db3copen(dbiIndex dbi, DB_TXN * txnid,
00665                 /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int dbiflags)
00666         /*@globals fileSystem @*/
00667         /*@modifies dbi, *dbcp, fileSystem @*/
00668 {
00669     DB * db = dbi->dbi_db;
00670     DBC * dbcursor = NULL;
00671     int flags;
00672     int rc;
00673 
00674    /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */
00675     assert(db != NULL);
00676     if ((dbiflags & DB_WRITECURSOR) &&
00677         (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
00678     {
00679         flags = DB_WRITECURSOR;
00680     } else
00681         flags = 0;
00682 
00683     rc = db->cursor(db, txnid, &dbcursor, flags);
00684     rc = cvtdberr(dbi, "db->cursor", rc, _debug);
00685 
00686     if (dbcp)
00687         /*@-boundswrite -onlytrans@*/ *dbcp = dbcursor; /*@=boundswrite =onlytrans@*/
00688     else
00689         (void) db3cclose(dbi, dbcursor, 0);
00690 
00691     return rc;
00692 }
00693 
00694 static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
00695                 /*@unused@*/ unsigned int flags)
00696         /*@globals fileSystem @*/
00697         /*@modifies fileSystem @*/
00698 {
00699     DB * db = dbi->dbi_db;
00700     int rc;
00701 
00702     assert(db != NULL);
00703     if (dbcursor == NULL) {
00704         rc = db->put(db, dbi->dbi_txnid, key, data, 0);
00705         rc = cvtdberr(dbi, "db->put", rc, _debug);
00706     } else {
00707         rc = dbcursor->c_put(dbcursor, key, data, DB_KEYLAST);
00708         rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
00709     }
00710 
00711     return rc;
00712 }
00713 
00714 /*@-mustmod@*/
00715 static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
00716                 unsigned int flags)
00717         /*@globals fileSystem @*/
00718         /*@modifies *dbcursor, fileSystem @*/
00719 {
00720     DB * db = dbi->dbi_db;
00721     int rc;
00722 
00723     assert(db != NULL);
00724     if (dbcursor == NULL) {
00725         rc = db->del(db, dbi->dbi_txnid, key, flags);
00726         rc = cvtdberr(dbi, "db->del", rc, _debug);
00727     } else {
00728         int _printit;
00729 
00730         /* XXX TODO: insure that cursor is positioned with duplicates */
00731         rc = dbcursor->c_get(dbcursor, key, data, DB_SET);
00732         /* XXX DB_NOTFOUND can be returned */
00733         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00734         rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
00735 
00736         if (rc == 0) {
00737             rc = dbcursor->c_del(dbcursor, flags);
00738             rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
00739         }
00740     }
00741 
00742     return rc;
00743 }
00744 /*@=mustmod@*/
00745 
00746 /*@-mustmod@*/
00747 static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
00748                 unsigned int flags)
00749         /*@globals fileSystem @*/
00750         /*@modifies *dbcursor, *key, *data, fileSystem @*/
00751 {
00752     DB * db = dbi->dbi_db;
00753     int _printit;
00754     int rc;
00755 
00756     assert(db != NULL);
00757     if (dbcursor == NULL) {
00758         /* XXX duplicates require cursors. */
00759         rc = db->get(db, dbi->dbi_txnid, key, data, 0);
00760         /* XXX DB_NOTFOUND can be returned */
00761         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00762         rc = cvtdberr(dbi, "db->get", rc, _printit);
00763     } else {
00764         /* XXX db3 does DB_FIRST on uninitialized cursor */
00765         rc = dbcursor->c_get(dbcursor, key, data, flags);
00766         /* XXX DB_NOTFOUND can be returned */
00767         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00768         rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
00769     }
00770 
00771     return rc;
00772 }
00773 /*@=mustmod@*/
00774 
00775 /*@-mustmod@*/
00776 static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey,
00777                 DBT * data, unsigned int flags)
00778         /*@globals fileSystem @*/
00779         /*@modifies *dbcursor, *key, *data, fileSystem @*/
00780 {
00781     DB * db = dbi->dbi_db;
00782     int _printit;
00783     int rc;
00784 
00785     assert(db != NULL);
00786     assert(dbcursor != NULL);
00787 
00788     /* XXX db3 does DB_FIRST on uninitialized cursor */
00789     rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags);
00790     /* XXX DB_NOTFOUND can be returned */
00791     _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00792     rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit);
00793 
00794     return rc;
00795 }
00796 /*@=mustmod@*/
00797 
00798 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
00799                 /*@null@*/ /*@out@*/ unsigned int * countp,
00800                 /*@unused@*/ unsigned int flags)
00801         /*@globals fileSystem @*/
00802         /*@modifies *countp, fileSystem @*/
00803 {
00804     db_recno_t count = 0;
00805     int rc = 0;
00806 
00807     flags = 0;
00808     rc = dbcursor->c_count(dbcursor, &count, flags);
00809     rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
00810     if (rc) return rc;
00811 /*@-boundswrite@*/
00812     if (countp) *countp = count;
00813 /*@=boundswrite@*/
00814 
00815     return rc;
00816 }
00817 
00818 static int db3byteswapped(dbiIndex dbi) /*@*/
00819 {
00820     DB * db = dbi->dbi_db;
00821     int rc = 0;
00822 
00823     if (db != NULL) {
00824 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
00825  || (DB_VERSION_MAJOR == 4)
00826         int isswapped = 0;
00827         rc = db->get_byteswapped(db, &isswapped);
00828         if (rc == 0)
00829             rc = isswapped;
00830 #else
00831         rc = db->get_byteswapped(db);
00832 #endif
00833     }
00834 
00835     return rc;
00836 }
00837 
00838 static int db3stat(dbiIndex dbi, unsigned int flags)
00839         /*@globals fileSystem @*/
00840         /*@modifies dbi, fileSystem @*/
00841 {
00842     DB * db = dbi->dbi_db;
00843 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
00844     DB_TXN * txnid = NULL;
00845 #endif
00846     int rc = 0;
00847 
00848     assert(db != NULL);
00849 #if defined(DB_FAST_STAT)
00850     if (flags)
00851         flags = DB_FAST_STAT;
00852     else
00853 #endif
00854         flags = 0;
00855     dbi->dbi_stats = _free(dbi->dbi_stats);
00856 /* XXX 3.3.4 change. */
00857 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00858 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
00859     rc = db->stat(db, txnid, &dbi->dbi_stats, flags);
00860 #else
00861     rc = db->stat(db, &dbi->dbi_stats, flags);
00862 #endif
00863 #else
00864     rc = db->stat(db, &dbi->dbi_stats, NULL, flags);
00865 #endif
00866     rc = cvtdberr(dbi, "db->stat", rc, _debug);
00867     return rc;
00868 }
00869 
00870 /*@-mustmod@*/
00871 static int db3associate(dbiIndex dbi, dbiIndex dbisecondary,
00872                 int (*callback)(DB *, const DBT *, const DBT *, DBT *),
00873                 unsigned int flags)
00874         /*@globals fileSystem @*/
00875         /*@modifies dbi, fileSystem @*/
00876 {
00877     DB * db = dbi->dbi_db;
00878     DB * secondary = dbisecondary->dbi_db;
00879     int rc;
00880 
00881 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00882 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
00883     DB_TXN * txnid = NULL;
00884 
00885 assert(db != NULL);
00886     rc = db->associate(db, txnid, secondary, callback, flags);
00887 #else
00888 assert(db != NULL);
00889     rc = db->associate(db, secondary, callback, flags);
00890 #endif
00891 /*@=moduncon@*/
00892     rc = cvtdberr(dbi, "db->associate", rc, _debug);
00893     return rc;
00894 }
00895 /*@=mustmod@*/
00896 
00897 /*@-mustmod@*/
00898 static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp,
00899                 unsigned int flags)
00900         /*@globals fileSystem @*/
00901         /*@modifies dbi, fileSystem @*/
00902 {
00903     DB * db = dbi->dbi_db;
00904     int rc;
00905 
00906 assert(db != NULL);
00907 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00908     rc = db->join(db, curslist, dbcp, flags);
00909 /*@=moduncon@*/
00910     rc = cvtdberr(dbi, "db->join", rc, _debug);
00911     return rc;
00912 }
00913 /*@=mustmod@*/
00914 
00915 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00916 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
00917         /*@globals rpmGlobalMacroContext, h_errno,
00918                 fileSystem @*/
00919         /*@modifies dbi, fileSystem @*/
00920 {
00921     rpmdb rpmdb = dbi->dbi_rpmdb;
00922     const char * urlfn = NULL;
00923     const char * root;
00924     const char * home;
00925     const char * dbhome;
00926     const char * dbfile;
00927     const char * dbsubfile;
00928     DB * db = dbi->dbi_db;
00929     int _printit;
00930     int rc = 0, xx;
00931 
00932     flags = 0;  /* XXX unused */
00933 
00934     /*
00935      * Get the prefix/root component and directory path.
00936      */
00937     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00938 /*@-boundsread@*/
00939     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00940         root = NULL;
00941 /*@=boundsread@*/
00942     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
00943 
00944     /*
00945      * Either the root or directory components may be a URL. Concatenate,
00946      * convert the URL to a path, and add the name of the file.
00947      */
00948     /*@-mods@*/
00949     urlfn = rpmGenPath(root, home, NULL);
00950     /*@=mods@*/
00951     (void) urlPath(urlfn, &dbhome);
00952     if (dbi->dbi_temporary) {
00953         dbfile = NULL;
00954         dbsubfile = NULL;
00955     } else {
00956 #ifdef  HACK    /* XXX necessary to support dbsubfile */
00957         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
00958         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : mapTagName(dbi->dbi_rpmtag));
00959 #else
00960         dbfile = (dbi->dbi_file ? dbi->dbi_file : mapTagName(dbi->dbi_rpmtag));
00961         dbsubfile = NULL;
00962 #endif
00963     }
00964 
00965     if (db) {
00966         rc = db->close(db, 0);
00967         /* XXX ignore not found error messages. */
00968         _printit = (rc == ENOENT ? 0 : _debug);
00969         rc = cvtdberr(dbi, "db->close", rc, _printit);
00970         db = dbi->dbi_db = NULL;
00971 
00972         rpmMessage(RPMMESS_DEBUG, D_("closed   db index       %s/%s\n"),
00973                 dbhome, (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)));
00974 
00975     }
00976 
00977     if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) {
00978         if (rpmdb->db_opens == 1) {
00979             /*@-nullstate@*/
00980             xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
00981             /*@=nullstate@*/
00982             rpmdb->db_dbenv = NULL;
00983         }
00984         rpmdb->db_opens--;
00985     }
00986 
00987     if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
00988         DB_ENV * dbenv = NULL;
00989         int eflags;
00990 
00991         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00992         rc = db_env_create(&dbenv, 0);
00993         /*@=moduncon@*/
00994         rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00995         if (rc || dbenv == NULL) goto exit;
00996 
00997         /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
00998         dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00999         dbenv->set_errfile(dbenv, rpmdb->db_errfile);
01000         dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
01001  /*     dbenv->set_paniccall(???) */
01002         /*@=noeffectuncon@*/
01003 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
01004         xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
01005                 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
01006 #endif
01007         xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
01008                 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
01009         xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
01010                 (dbi->dbi_verbose & DB_VERB_RECOVERY));
01011         xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
01012                 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
01013 
01014         if (dbi->dbi_tmpdir) {
01015             /*@-mods@*/
01016             const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
01017             /*@=mods@*/
01018             rc = dbenv->set_tmp_dir(dbenv, tmpdir);
01019             rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
01020             tmpdir = _free(tmpdir);
01021             if (rc) goto exit;
01022         }
01023             
01024         eflags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON;
01025         rc = dbenv->open(dbenv, dbhome, eflags, 0);
01026         rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
01027         if (rc) goto exit;
01028 
01029         /*@-moduncon -nullstate@*/ /* FIX: annotate db3 methods */
01030         rc = db_create(&db, dbenv, 0);
01031         /*@=moduncon =nullstate@*/
01032         rc = cvtdberr(dbi, "db_create", rc, _debug);
01033 
01034         if (db != NULL) {
01035                 /*@-mods@*/
01036                 const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
01037                 /*@=mods@*/
01038 
01039                 rc = db->verify(db, dbf, NULL, NULL, flags);
01040                 rc = cvtdberr(dbi, "db->verify", rc, _debug);
01041 
01042                 rpmMessage(RPMMESS_DEBUG, D_("verified db index       %s/%s\n"),
01043                         (dbhome ? dbhome : ""),
01044                         (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)));
01045 
01046                 /*
01047                  * The DB handle may not be accessed again after
01048                  * DB->verify is called, regardless of its return.
01049                  */
01050                 db = NULL;
01051                 dbf = _free(dbf);
01052         }
01053         xx = dbenv->close(dbenv, 0);
01054         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
01055         if (rc == 0 && xx) rc = xx;
01056     }
01057 
01058 exit:
01059     dbi->dbi_db = NULL;
01060 
01061     urlfn = _free(urlfn);
01062 
01063     dbi = db3Free(dbi);
01064 
01065     return rc;
01066 }
01067 /*@=moduncon@*/
01068 
01069 static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip)
01070         /*@globals rpmGlobalMacroContext, h_errno,
01071                 fileSystem, internalState @*/
01072         /*@modifies *dbip, fileSystem, internalState @*/
01073 {
01074     /*@-nestedextern -shadow@*/
01075     extern struct _dbiVec db3vec;
01076     /*@=nestedextern =shadow@*/
01077     const char * urlfn = NULL;
01078     const char * root;
01079     const char * home;
01080     const char * dbhome;
01081     const char * dbfile;
01082     const char * dbsubfile;
01083     dbiIndex dbi = NULL;
01084     int rc = 0;
01085     int xx;
01086 
01087     DB * db = NULL;
01088     DB_ENV * dbenv = NULL;
01089 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
01090     DB_TXN * txnid = NULL;
01091 #endif
01092     DBTYPE dbi_type = DB_UNKNOWN;
01093     u_int32_t oflags;
01094     int _printit;
01095 
01096 /*@-boundswrite@*/
01097     if (dbip)
01098         *dbip = NULL;
01099 /*@=boundswrite@*/
01100 
01101     /*
01102      * Parse db configuration parameters.
01103      */
01104     /*@-mods@*/
01105     if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
01106         /*@-nullstate@*/
01107         return 1;
01108         /*@=nullstate@*/
01109     /*@=mods@*/
01110     dbi->dbi_api = DB_VERSION_MAJOR;
01111 
01112     /*
01113      * Get the prefix/root component and directory path.
01114      */
01115     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
01116 /*@-boundsread@*/
01117     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
01118         root = NULL;
01119 /*@=boundsread@*/
01120     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
01121 
01122     /*
01123      * Either the root or directory components may be a URL. Concatenate,
01124      * convert the URL to a path, and add the name of the file.
01125      */
01126     /*@-mods@*/
01127     urlfn = rpmGenPath(root, home, NULL);
01128     /*@=mods@*/
01129     (void) urlPath(urlfn, &dbhome);
01130     if (dbi->dbi_temporary) {
01131         dbfile = NULL;
01132         dbsubfile = NULL;
01133     } else {
01134 #ifdef  HACK    /* XXX necessary to support dbsubfile */
01135         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
01136         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : mapTagName(dbi->dbi_rpmtag));
01137 #else
01138         dbfile = (dbi->dbi_file ? dbi->dbi_file : mapTagName(dbi->dbi_rpmtag));
01139         dbsubfile = NULL;
01140 #endif
01141     }
01142 
01143     oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
01144     oflags &= ~DB_TRUNCATE;     /* XXX this is dangerous */
01145 
01146 #if 0   /* XXX rpmdb: illegal flag combination specified to DB->open */
01147     if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
01148 #endif
01149 
01150     /*
01151      * Map open mode flags onto configured database/environment flags.
01152      */
01153     if (dbi->dbi_temporary) {
01154         oflags |= DB_CREATE;
01155         dbi->dbi_oeflags |= DB_CREATE;
01156         oflags &= ~DB_RDONLY;
01157         dbi->dbi_oflags &= ~DB_RDONLY;
01158     } else {
01159         if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
01160         if (dbi->dbi_mode & O_CREAT) {
01161             oflags |= DB_CREATE;
01162             dbi->dbi_oeflags |= DB_CREATE;
01163         }
01164 #ifdef  DANGEROUS
01165         if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE;
01166 #endif
01167     }
01168 
01169     /*
01170      * Create the /var/lib/rpm directory if it doesn't exist (root only).
01171      */
01172     (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
01173 
01174     /*
01175      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open.
01176      */
01177     if (dbi->dbi_use_dbenv) {
01178 
01179 #if 0
01180 #if HAVE_LIBPTHREAD
01181         if (rpmdb->db_dbenv == NULL) {
01182             /* Set DB_PRIVATE if posix mutexes are not shared. */
01183             xx = db3_pthread_nptl();
01184             if (xx) {
01185                 dbi->dbi_eflags |= DB_PRIVATE;
01186                 rpmMessage(RPMMESS_DEBUG, D_("unshared posix mutexes found(%d), adding DB_PRIVATE, using fcntl lock\n"), xx);
01187             }
01188         }
01189 #endif
01190 #endif
01191 
01192         if (access(dbhome, W_OK) == -1) {
01193 
01194             /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */
01195             oflags &= ~DB_CREATE;
01196 
01197             /* ... but DBENV->open might still need DB_CREATE ... */
01198             if (dbi->dbi_eflags & DB_PRIVATE) {
01199                 dbi->dbi_eflags &= ~DB_JOINENV;
01200             } else {
01201                 dbi->dbi_eflags |= DB_JOINENV;
01202                 dbi->dbi_oeflags &= ~DB_CREATE;
01203                 dbi->dbi_oeflags &= ~DB_THREAD;
01204                 /* ... but, unless DB_PRIVATE is used, skip DBENV. */
01205                 dbi->dbi_use_dbenv = 0;
01206             }
01207 
01208             /* ... DB_RDONLY maps dbhome perms across files ...  */
01209             if (dbi->dbi_temporary) {
01210                 oflags |= DB_CREATE;
01211                 dbi->dbi_oeflags |= DB_CREATE;
01212                 oflags &= ~DB_RDONLY;
01213                 dbi->dbi_oflags &= ~DB_RDONLY;
01214             } else {
01215                 oflags |= DB_RDONLY;
01216                 /* ... and DB_WRITECURSOR won't be needed ...  */
01217                 dbi->dbi_oflags |= DB_RDONLY;
01218             }
01219 
01220         } else {        /* dbhome is writable, check for persistent dbenv. */
01221             /*@-mods@*/
01222             const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
01223             /*@=mods@*/
01224 
01225             if (access(dbf, F_OK) == -1) {
01226                 /* ... non-existent (or unwritable) DBENV, will create ... */
01227                 dbi->dbi_oeflags |= DB_CREATE;
01228                 dbi->dbi_eflags &= ~DB_JOINENV;
01229             } else {
01230                 /* ... pre-existent (or bogus) DBENV, will join ... */
01231                 if (dbi->dbi_eflags & DB_PRIVATE) {
01232                     dbi->dbi_eflags &= ~DB_JOINENV;
01233                 } else {
01234                     dbi->dbi_eflags |= DB_JOINENV;
01235                     dbi->dbi_oeflags &= ~DB_CREATE;
01236                     dbi->dbi_oeflags &= ~DB_THREAD;
01237                 }
01238             }
01239             dbf = _free(dbf);
01240         }
01241     }
01242 
01243     /*
01244      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open.
01245      */
01246     if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
01247         /* dbhome is writable, and DB->open flags may conflict. */
01248         const char * dbfn = (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag));
01249         /*@-mods@*/
01250         const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
01251         /*@=mods@*/
01252 
01253         if (access(dbf, F_OK) == -1) {
01254             /* File does not exist, DB->open might create ... */
01255             oflags &= ~DB_RDONLY;
01256         } else {
01257             /* File exists, DB->open need not create ... */
01258             oflags &= ~DB_CREATE;
01259         }
01260 
01261         /* Only writers need DB_WRITECURSOR ... */
01262         if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
01263             dbi->dbi_oflags &= ~DB_RDONLY;
01264         } else {
01265             dbi->dbi_oflags |= DB_RDONLY;
01266         }
01267         dbf = _free(dbf);
01268     }
01269 
01270     /*
01271      * Set db type if creating.
01272      */
01273     if (oflags & DB_CREATE)
01274         dbi_type = dbi->dbi_type;
01275 
01276     /*
01277      * Turn off verify-on-close if opening read-only.
01278      */
01279     if (oflags & DB_RDONLY)
01280         dbi->dbi_verify_on_close = 0;
01281 
01282 /*@-branchstate@*/
01283     if (dbi->dbi_use_dbenv) {
01284         /*@-mods@*/
01285         if (rpmdb->db_dbenv == NULL) {
01286             rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
01287             switch (rc) {
01288             default:
01289                 break;
01290 
01291             case DB_RUNRECOVERY:
01292                 rpmError(RPMERR_DBERR, _("Runnning db->verify ...\n"));
01293                 rpmdb = rpmdbLink(rpmdb, "DB_RUNRECOVERY");
01294                 rpmdb->db_remove_env = 1;
01295                 rpmdb->db_verifying = 1;
01296                 xx = rpmdbVerifyAllDBI(rpmdb);
01297                 xx = cvtdberr(dbi, "db->verify", xx, _debug);
01298                 rpmdb->db_remove_env = 0;
01299                 rpmdb->db_verifying = 0;
01300 
01301                 dbi->dbi_oeflags |= DB_CREATE;
01302                 dbi->dbi_eflags &= ~DB_JOINENV;
01303                 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
01304                 /* XXX db_init EINVAL was masked. */
01305                 rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
01306                 if (rc)
01307                     break;
01308 
01309 assert(dbenv);
01310                 rpmdb->db_dbenv = dbenv;
01311                 rpmdb->db_opens = 1;
01312                 break;
01313 
01314 #if defined(DB_VERSION_MISMATCH) /* Nuke __db* files and retry open once. */
01315             case DB_VERSION_MISMATCH:
01316 #endif
01317             case EINVAL:
01318                 if (getuid() != 0)
01319                     break;
01320                 {   char * filename = alloca(BUFSIZ);
01321                     struct stat st;
01322                     int i;
01323 
01324                     for (i = 0; i < 16; i++) {
01325                         sprintf(filename, "%s/__db.%03d", dbhome, i);
01326                         (void)rpmCleanPath(filename);
01327                         if (Stat(filename, &st)
01328                           && (errno == ENOENT || errno == EINVAL))
01329                             continue;
01330                         xx = Unlink(filename);
01331                     }
01332                 }
01333                 dbi->dbi_oeflags |= DB_CREATE;
01334                 dbi->dbi_eflags &= ~DB_JOINENV;
01335                 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
01336                 /* XXX db_init EINVAL was masked. */
01337                 rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
01338                 if (rc)
01339                     break;
01340                 /*@fallthrough@*/
01341             case 0:
01342 assert(dbenv);
01343                 rpmdb->db_dbenv = dbenv;
01344                 rpmdb->db_opens = 1;
01345                 break;
01346             }
01347         } else {
01348 assert(rpmdb && rpmdb->db_dbenv);
01349             dbenv = rpmdb->db_dbenv;
01350             rpmdb->db_opens++;
01351         }
01352         /*@=mods@*/
01353     }
01354 /*@=branchstate@*/
01355 
01356     rpmMessage(RPMMESS_DEBUG, D_("opening  db index       %s/%s %s mode=0x%x\n"),
01357                 dbhome, (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)),
01358                 prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
01359 
01360     if (rc == 0) {
01361         static int _lockdbfd = 0;
01362 
01363         /*@-moduncon@*/ /* FIX: annotate db3 methods */
01364         rc = db_create(&db, dbenv, dbi->dbi_cflags);
01365         /*@=moduncon@*/
01366         rc = cvtdberr(dbi, "db_create", rc, _debug);
01367         if (rc == 0 && db != NULL) {
01368 
01369 /* XXX 3.3.4 change. */
01370 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
01371             if (rc == 0 &&
01372                         rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
01373             {
01374                 rc = db->set_alloc(db,
01375                         rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
01376                 rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
01377             }
01378 #else
01379             if (rc == 0 && rpmdb->db_malloc) {
01380                 rc = db->set_malloc(db, rpmdb->db_malloc);
01381                 rc = cvtdberr(dbi, "db->set_malloc", rc, _debug);
01382             }
01383 #endif
01384 
01385 /* 4.1: db->set_cache_priority(???) */
01386             if (rc == 0 && !dbi->dbi_use_dbenv && dbi->dbi_cachesize) {
01387                 rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0);
01388                 rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug);
01389             }
01390 /* 4.1: db->set_encrypt(???) */
01391 /* 4.1: db->set_errcall(dbenv, rpmdb->db_errcall); */
01392 /* 4.1: db->set_errfile(dbenv, rpmdb->db_errfile); */
01393 /* 4.1: db->set_errpfx(dbenv, rpmdb->db_errpfx); */
01394  /* 4.1: db->set_feedback(???) */
01395 
01396             if (rc == 0 && dbi->dbi_lorder) {
01397                 rc = db->set_lorder(db, dbi->dbi_lorder);
01398                 rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
01399             }
01400             if (rc == 0 && dbi->dbi_pagesize) {
01401                 rc = db->set_pagesize(db, dbi->dbi_pagesize);
01402                 rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
01403             }
01404  /* 4.1: db->set_paniccall(???) */
01405             if (rc == 0 && oflags & DB_CREATE) {
01406                 switch(dbi->dbi_type) {
01407                 default:
01408                 case DB_HASH:
01409                     if (dbi->dbi_h_ffactor) {
01410                         rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor);
01411                         rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug);
01412                         if (rc) break;
01413                     }
01414                     if (dbi->dbi_h_nelem) {
01415                         rc = db->set_h_nelem(db, dbi->dbi_h_nelem);
01416                         rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug);
01417                         if (rc) break;
01418                     }
01419                     if (dbi->dbi_h_flags) {
01420                         rc = db->set_flags(db, dbi->dbi_h_flags);
01421                         rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug);
01422                         if (rc) break;
01423                     }
01424 /* XXX db-3.2.9 has added a DB arg to the call. */
01425 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
01426                     if (dbi->dbi_h_hash_fcn) {
01427                         rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn);
01428                         rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug);
01429                         if (rc) break;
01430                     }
01431                     if (dbi->dbi_h_dup_compare_fcn) {
01432                         rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn);
01433                         rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
01434                         if (rc) break;
01435                     }
01436 #endif
01437                     break;
01438                 case DB_BTREE:
01439 /* 4.1: db->set_append_recno(???) */
01440                     if (dbi->dbi_bt_flags) {
01441                         rc = db->set_flags(db, dbi->dbi_bt_flags);
01442                         rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
01443                         if (rc) break;
01444                     }
01445                     if (dbi->dbi_bt_minkey) {
01446                         rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey);
01447                         rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug);
01448                         if (rc) break;
01449                     }
01450 /* XXX db-3.2.9 has added a DB arg to the call. */
01451 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
01452                     if (dbi->dbi_bt_compare_fcn) {
01453                         rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn);
01454                         rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug);
01455                         if (rc) break;
01456                     }
01457                     if (dbi->dbi_bt_dup_compare_fcn) {
01458                         rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn);
01459                         rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
01460                         if (rc) break;
01461                     }
01462                     if (dbi->dbi_bt_prefix_fcn) {
01463                         rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn);
01464                         rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug);
01465                         if (rc) break;
01466                     }
01467 #endif
01468                     break;
01469                 case DB_RECNO:
01470                     if (dbi->dbi_re_delim) {
01471 /* 4.1: db->set_append_recno(???) */
01472                         rc = db->set_re_delim(db, dbi->dbi_re_delim);
01473                         rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
01474                         if (rc) break;
01475                     }
01476                     if (dbi->dbi_re_len) {
01477                         rc = db->set_re_len(db, dbi->dbi_re_len);
01478                         rc = cvtdberr(dbi, "db->set_re_len", rc, _debug);
01479                         if (rc) break;
01480                     }
01481                     if (dbi->dbi_re_pad) {
01482                         rc = db->set_re_pad(db, dbi->dbi_re_pad);
01483                         rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug);
01484                         if (rc) break;
01485                     }
01486                     if (dbi->dbi_re_source) {
01487                         rc = db->set_re_source(db, dbi->dbi_re_source);
01488                         rc = cvtdberr(dbi, "db->set_re_source", rc, _debug);
01489                         if (rc) break;
01490                     }
01491                     break;
01492                 case DB_QUEUE:
01493                     if (dbi->dbi_q_extentsize) {
01494                         rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize);
01495                         rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug);
01496                         if (rc) break;
01497                     }
01498                     break;
01499                 }
01500             }
01501 
01502             if (rc == 0) {
01503                 const char * dbfullpath;
01504                 const char * dbpath;
01505                 char * t;
01506                 int nb;
01507 
01508                 nb = strlen(dbhome);
01509                 if (dbfile)     nb += 1 + strlen(dbfile);
01510                 dbfullpath = t = alloca(nb + 1);
01511 
01512 /*@-boundswrite@*/
01513                 t = stpcpy(t, dbhome);
01514                 if (dbfile)
01515                     t = stpcpy( stpcpy( t, "/"), dbfile);
01516 /*@=boundswrite@*/
01517 #ifdef  HACK    /* XXX necessary to support dbsubfile */
01518                 dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
01519                         ? dbfullpath : dbfile;
01520 #else
01521                 dbpath = (!dbi->dbi_temporary)
01522                         ? dbfullpath : dbfile;
01523 #endif
01524 
01525 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
01526                 rc = db->open(db, txnid, dbpath, dbsubfile,
01527                     dbi_type, oflags, dbi->dbi_perms);
01528 #else
01529                 rc = db->open(db, dbpath, dbsubfile,
01530                     dbi_type, oflags, dbi->dbi_perms);
01531 #endif
01532 
01533                 if (rc == 0 && dbi_type == DB_UNKNOWN) {
01534 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
01535  || (DB_VERSION_MAJOR == 4)
01536                     xx = db->get_type(db, &dbi_type);
01537                     if (xx == 0)
01538                         dbi->dbi_type = dbi_type;
01539 #else
01540                     dbi->dbi_type = db->get_type(db);
01541 #endif
01542                 }
01543             }
01544 
01545             /* XXX return rc == errno without printing */
01546             _printit = (rc > 0 ? 0 : _debug);
01547             xx = cvtdberr(dbi, "db->open", rc, _printit);
01548 
01549             dbi->dbi_txnid = NULL;
01550 
01551             /*
01552              * Lock a file using fcntl(2). Traditionally this is Packages,
01553              * the file used to store metadata of installed header(s),
01554              * as Packages is always opened, and should be opened first,
01555              * for any rpmdb access.
01556              *
01557              * If no DBENV is used, then access is protected with a
01558              * shared/exclusive locking scheme, as always.
01559              *
01560              * With a DBENV, the fcntl(2) lock is necessary only to keep
01561              * the riff-raff from playing where they don't belong, as
01562              * the DBENV should provide it's own locking scheme. So try to
01563              * acquire a lock, but permit failures, as some other
01564              * DBENV player may already have acquired the lock.
01565              *
01566              * With NPTL posix mutexes, revert to fcntl lock on non-functioning
01567              * glibc/kernel combinations.
01568              */
01569             if (rc == 0 && dbi->dbi_lockdbfd &&
01570                 !((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) &&
01571                 (!dbi->dbi_use_dbenv || _lockdbfd++ == 0))
01572             {
01573                 int fdno = -1;
01574 
01575                 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
01576                     rc = 1;
01577                 } else {
01578                     struct flock l;
01579 /*@-boundswrite@*/
01580                     memset(&l, 0, sizeof(l));
01581 /*@=boundswrite@*/
01582                     l.l_whence = 0;
01583                     l.l_start = 0;
01584                     l.l_len = 0;
01585                     l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY))
01586                                 ? F_WRLCK : F_RDLCK;
01587                     l.l_pid = 0;
01588 
01589                     rc = fcntl(fdno, F_SETLK, (void *) &l);
01590                     if (rc) {
01591                         /* Warning iff using non-private CDB locking. */
01592                         rc = ((dbi->dbi_use_dbenv &&
01593                                 (dbi->dbi_eflags & DB_INIT_CDB) &&
01594                                 !(dbi->dbi_eflags & DB_PRIVATE))
01595                             ? 0 : 1);
01596                         rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK),
01597                                 _("cannot get %s lock on %s/%s\n"),
01598                                 ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
01599                                         ? _("exclusive") : _("shared")),
01600                                 dbhome, (dbfile ? dbfile : ""));
01601                     } else if (dbfile) {
01602                         rpmMessage(RPMMESS_DEBUG,
01603                                 D_("locked   db index       %s/%s\n"),
01604                                 dbhome, dbfile);
01605                     }
01606                 }
01607             }
01608         }
01609     }
01610 
01611     dbi->dbi_db = db;
01612 
01613     if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
01614         dbi->dbi_vec = &db3vec;
01615 /*@-boundswrite@*/
01616         *dbip = dbi;
01617 /*@=boundswrite@*/
01618     } else {
01619         dbi->dbi_verify_on_close = 0;
01620         (void) db3close(dbi, 0);
01621     }
01622 
01623     urlfn = _free(urlfn);
01624 
01625     /*@-nullstate -compmempass@*/
01626     return rc;
01627     /*@=nullstate =compmempass@*/
01628 }
01629 
01632 /*@-exportheadervar@*/
01633 /*@observer@*/ /*@unchecked@*/
01634 struct _dbiVec db3vec = {
01635     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
01636     db3open, db3close, db3sync, db3associate, db3join,
01637     db3copen, db3cclose, db3cdup, db3cdel, db3cget, db3cpget, db3cput, db3ccount,
01638     db3byteswapped, db3stat
01639 };
01640 /*@=exportheadervar@*/
01641 /*@=type@*/

Generated on Fri Aug 31 10:50:46 2007 for rpm by  doxygen 1.5.1