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

Generated on Tue Jun 12 18:41:34 2007 for rpm by doxygen 1.3.5