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