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

# rpmdb/db3.c

Go to the documentation of this file.

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