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

Generated on Fri Dec 7 15:30:07 2007 for rpm by  doxygen 1.5.2