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

Generated on Sun Feb 2 23:32:04 2003 for rpm by doxygen1.2.18