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

rpmdb/db3.c

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

Generated at Wed Mar 27 03:56:52 2002 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001