Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

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

Generated on Sun Oct 26 13:02:02 2003 for rpm by doxygen1.2.18