rpm 5.3.7

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 <rpmlog.h>
00016 #include <rpmmacro.h>
00017 #include <rpmbf.h>
00018 #include <rpmpgp.h>             /* XXX pgpExtractPubkeyFingerprint */
00019 #include <rpmurl.h>             /* XXX urlPath proto */
00020 
00021 #define _RPMTAG_INTERNAL
00022 #include <rpmtag.h>
00023 
00024 #define _RPMEVR_INTERNAL        /* XXX isInstallPrereq */
00025 #include <rpmevr.h>
00026 
00027 #define _RPMDB_INTERNAL
00028 #include <rpmdb.h>
00029 
00030 #include "debug.h"
00031 
00032 #ifdef  NOTYET  /* XXX syscall ACID needs --with-db=internal */
00033 extern int logio_dispatch(DB_ENV * dbenv, DBT * dbt, DB_LSN * lsn, db_recops op)
00034         /*@*/;
00035 #endif
00036 
00037 #define DBIDEBUG(_dbi, _list)   if ((_dbi)->dbi_debug) fprintf _list
00038 
00039 /*@access rpmdb @*/
00040 /*@access dbiIndex @*/
00041 /*@access dbiIndexSet @*/
00042 
00043 /*@-redef@*/
00044 union _dbswap {
00045     uint64_t ul;
00046     uint32_t ui;
00047     uint16_t us;
00048     uint8_t uc[8];
00049 };
00050 /*@=redef@*/
00051 /*@unchecked@*/
00052 static union _dbswap _endian = { .ui = 0x11223344 };
00053 
00054 static inline uint64_t _ntoh_ul(uint64_t ul)
00055         /*@*/
00056 {
00057     union _dbswap _a;
00058     _a.ul = ul;
00059     if (_endian.uc[0] == 0x44) {
00060         uint8_t _b, *_c = _a.uc; \
00061         _b = _c[7]; _c[7] = _c[0]; _c[0] = _b; \
00062         _b = _c[6]; _c[6] = _c[1]; _c[1] = _b; \
00063         _b = _c[5]; _c[5] = _c[2]; _c[2] = _b; \
00064         _b = _c[4]; _c[4] = _c[3]; _c[3] = _b; \
00065     }
00066     return _a.ul;
00067 }
00068 static inline uint64_t _hton_ul(uint64_t ul)
00069         /*@*/
00070 {
00071     return _ntoh_ul(ul);
00072 }
00073 
00074 static inline uint32_t _ntoh_ui(uint32_t ui)
00075         /*@*/
00076 {
00077     union _dbswap _a;
00078     _a.ui = ui;
00079     if (_endian.uc[0] == 0x44) {
00080         uint8_t _b, *_c = _a.uc; \
00081         _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
00082         _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
00083     }
00084     return _a.ui;
00085 }
00086 static inline uint32_t _hton_ui(uint32_t ui)
00087         /*@*/
00088 {
00089     return _ntoh_ui(ui);
00090 }
00091 
00092 static inline uint16_t _ntoh_us(uint16_t us)
00093         /*@*/
00094 {
00095     union _dbswap _a;
00096     _a.us = us;
00097     if (_endian.uc[0] == 0x44) {
00098         uint8_t _b, *_c = _a.uc; \
00099         _b = _c[1]; _c[1] = _c[0]; _c[0] = _b; \
00100     }
00101     return _a.us;
00102 }
00103 static inline uint16_t _hton_us(uint16_t us)
00104         /*@*/
00105 {
00106     return _ntoh_us(us);
00107 }
00108 
00109 #ifdef  NOTNOW
00110 static const char * bfstring(unsigned int x, const char * xbf)
00111 {
00112     const char * s = xbf;
00113     static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00114     static char buf[BUFSIZ];
00115     char * t, * te;
00116     unsigned radix;
00117     unsigned c, i, k;
00118 
00119     radix = (s != NULL ? *s++ : 16);
00120 
00121     if (radix <= 1 || radix >= 32)
00122         radix = 16;
00123 
00124     t = buf;
00125     switch (radix) {
00126     case 8:     *t++ = '0';     break;
00127     case 16:    *t++ = '0';     *t++ = 'x';     break;
00128     }
00129 
00130     i = 0;
00131     k = x;
00132     do { i++; k /= radix; } while (k);
00133 
00134     te = t + i;
00135 
00136     k = x;
00137     do { --i; t[i] = digits[k % radix]; k /= radix; } while (k);
00138 
00139     t = te;
00140     i = '<';
00141     if (s != NULL)
00142     while ((c = *s++) != '\0') {
00143         if (c > ' ') continue;
00144 
00145         k = (1 << (c - 1));
00146         if (!(x & k)) continue;
00147 
00148         if (t == te) *t++ = '=';
00149 
00150         *t++ = i;
00151         i = ',';
00152         while (*s > ' ')
00153             *t++ = *s++;
00154     }
00155     if (t > te) *t++ = '>';
00156     *t = '\0';
00157     return buf;
00158 }
00159 
00160 /* XXX checked with db-4.5.20 */
00161 static const char * dbtFlags =
00162         "\20\1APPMALLOC\2ISSET\3MALLOC\4PARTIAL\5REALLOC\6USERMEM\7DUPOK";
00163 
00164 static const char * dbenvOpenFlags =
00165         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CDB\20LOCK\21LOG\22MPOOL\23REP\24TXN\25LOCKDOWN\26PRIVATE\27RECOVER_FATAL\30REGISTER\31SYSTEM_MEM";
00166 
00167 static const char * dbOpenFlags =
00168         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17EXCL\20FCNTL_LOCKING\21NO_AUTO_COMMIT\22RDWRMASTER\23WRITEOPEN";
00169 
00170 static const char * dbenvSetFlags =
00171         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CDB_ALLDB\20DIRECT_DB\21DIRECT_LOG\22DSYNC_DB\23DSYNC_LOG\24LOG_AUTOREMOVE\25LOG_INMEMORY\26NOLOCKING\27NOPANIC\30OVERWRITE\31PANIC_ENV\36REGION_INIT\37TIME_NOTGRANTED\40YIELDCPU";
00172 
00173 static const char * dbSetFlags =
00174         "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CHKSUM\20DUP\21DUPSORT\22ENCRYPT\23INORDER\24RECNUM\25RENUMBER\26REVSPLITOFF\27SNAPSHOT";
00175 
00176 static const char * dbiModeFlags =
00177         "\20\1WRONLY\2RDWR\7CREAT\10EXCL\11NOCTTY\12TRUNC\13APPEND\14NONBLOCK\15SYNC\16ASYNC\17DIRECT\20LARGEFILE\21DIRECTORY\22NOFOLLOW";
00178 #endif  /* NOTNOW */
00179 
00180 /*@-redef@*/
00181 typedef struct key_s {
00182     uint32_t    v;
00183 /*@observer@*/
00184     const char *n;
00185 } KEY;
00186 /*@=redef@*/
00187 
00188 /*@observer@*/
00189 static const char * tblName(uint32_t v, KEY * tbl, size_t ntbl)
00190         /*@*/
00191 {
00192     const char * n = NULL;
00193     static char buf[32];
00194     size_t i;
00195 
00196     for (i = 0; i < ntbl; i++) {
00197         if (v != tbl[i].v)
00198             continue;
00199         n = tbl[i].n;
00200         break;
00201     }
00202     if (n == NULL) {
00203         (void) snprintf(buf, sizeof(buf), "0x%x", (unsigned)v);
00204         n = buf;
00205     }
00206     return n;
00207 }
00208 
00209 static const char * fmtBits(uint32_t flags, KEY tbl[], size_t ntbl, char *t)
00210         /*@modifies t @*/
00211 {
00212     char pre = '<';
00213     char * te = t;
00214     int i;
00215 
00216     sprintf(t, "0x%x", (unsigned)flags);
00217     te = t;
00218     te += strlen(te);
00219     for (i = 0; i < 32; i++) {
00220         uint32_t mask = (1 << i);
00221         const char * name;
00222 
00223         if (!(flags & mask))
00224             continue;
00225 
00226         name = tblName(mask, tbl, ntbl);
00227         *te++ = pre;
00228         pre = ',';
00229         te = stpcpy(te, name);
00230     }
00231     if (pre == ',') *te++ = '>';
00232     *te = '\0';
00233     return t;
00234 }
00235 
00236 #define _ENTRY(_v)      { DB_##_v, #_v, }
00237 
00238 /*@unchecked@*/ /*@observer@*/
00239 static KEY DBeflags[] = {
00240     _ENTRY(INIT_CDB),
00241     _ENTRY(INIT_LOCK),
00242     _ENTRY(INIT_LOG),
00243     _ENTRY(INIT_MPOOL),
00244     _ENTRY(INIT_REP),
00245     _ENTRY(INIT_TXN),
00246     _ENTRY(RECOVER),
00247     _ENTRY(RECOVER_FATAL),
00248     _ENTRY(USE_ENVIRON),
00249     _ENTRY(USE_ENVIRON_ROOT),
00250     _ENTRY(CREATE),
00251     _ENTRY(LOCKDOWN),
00252 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5)
00253     _ENTRY(FAILCHK),
00254 #endif
00255     _ENTRY(PRIVATE),
00256     _ENTRY(REGISTER),
00257     _ENTRY(SYSTEM_MEM),
00258     _ENTRY(THREAD),
00259 };
00260 /*@unchecked@*/
00261 static size_t nDBeflags = sizeof(DBeflags) / sizeof(DBeflags[0]);
00262 /*@observer@*/
00263 static const char * fmtDBeflags(uint32_t flags)
00264         /*@*/
00265 {
00266     static char buf[BUFSIZ];
00267     char * te = buf;
00268     te = stpcpy(te, "\n\tflags: ");
00269     (void) fmtBits(flags, DBeflags, nDBeflags, te);
00270     return buf;
00271 }
00272 #define _EFLAGS(_eflags)        fmtDBeflags(_eflags)
00273 
00274 /*@unchecked@*/ /*@observer@*/
00275 static KEY DBoflags[] = {
00276     _ENTRY(AUTO_COMMIT),
00277     _ENTRY(CREATE),
00278     _ENTRY(EXCL),
00279     _ENTRY(MULTIVERSION),
00280     _ENTRY(NOMMAP),
00281     _ENTRY(RDONLY),
00282     _ENTRY(READ_UNCOMMITTED),
00283     _ENTRY(THREAD),
00284     _ENTRY(TRUNCATE),
00285 };
00286 /*@unchecked@*/
00287 static size_t nDBoflags = sizeof(DBoflags) / sizeof(DBoflags[0]);
00288 /*@observer@*/
00289 static const char * fmtDBoflags(uint32_t flags)
00290         /*@*/
00291 {
00292     static char buf[BUFSIZ];
00293     char * te = buf;
00294     te = stpcpy(te, "\n\tflags: ");
00295     (void) fmtBits(flags, DBoflags, nDBoflags, te);
00296     return buf;
00297 }
00298 #define _OFLAGS(_oflags)        fmtDBoflags(_oflags)
00299 
00300 /*@unchecked@*/ /*@observer@*/
00301 static KEY DBaflags[] = {
00302     _ENTRY(CREATE),
00303     _ENTRY(IMMUTABLE_KEY),
00304 };
00305 /*@unchecked@*/
00306 static size_t nDBaflags = sizeof(DBaflags) / sizeof(DBaflags[0]);
00307 /*@observer@*/
00308 static const char * fmtDBaflags(uint32_t flags)
00309         /*@*/
00310 {
00311     static char buf[BUFSIZ];
00312     char * te = buf;
00313     te = stpcpy(te, "\n\tflags: ");
00314     (void) fmtBits(flags, DBaflags, nDBaflags, te);
00315     return buf;
00316 }
00317 #define _AFLAGS(_aflags)        fmtDBaflags(_aflags)
00318 
00319 /*@unchecked@*/ /*@observer@*/
00320 static KEY DBafflags[] = {
00321     _ENTRY(FOREIGN_ABORT),
00322     _ENTRY(FOREIGN_CASCADE),
00323     _ENTRY(FOREIGN_NULLIFY),
00324 };
00325 /*@unchecked@*/
00326 static size_t nDBafflags = sizeof(DBafflags) / sizeof(DBafflags[0]);
00327 /*@observer@*/
00328 static const char * fmtDBafflags(uint32_t flags)
00329         /*@*/
00330 {
00331     static char buf[BUFSIZ];
00332     char * te = buf;
00333     te = stpcpy(te, "\n\tflags: ");
00334     (void) fmtBits(flags, DBafflags, nDBafflags, te);
00335     return buf;
00336 }
00337 #define _AFFLAGS(_afflags)      fmtDBafflags(_afflags)
00338 
00339 /*@unchecked@*/ /*@observer@*/
00340 static KEY DBCflags[] = {
00341     _ENTRY(AFTER),              /* Dbc.put */
00342     _ENTRY(APPEND),             /* Db.put */
00343     _ENTRY(BEFORE),             /* Dbc.put */
00344     _ENTRY(CONSUME),            /* Db.get */
00345     _ENTRY(CONSUME_WAIT),       /* Db.get */
00346     _ENTRY(CURRENT),            /* Dbc.get, Dbc.put, DbLogc.get */
00347     _ENTRY(FIRST),              /* Dbc.get, DbLogc->get */
00348     _ENTRY(GET_BOTH),           /* Db.get, Dbc.get */
00349     _ENTRY(GET_BOTHC),          /* Dbc.get (internal) */
00350     _ENTRY(GET_BOTH_RANGE),     /* Db.get, Dbc.get */
00351     _ENTRY(GET_RECNO),          /* Dbc.get */
00352     _ENTRY(JOIN_ITEM),          /* Dbc.get; don't do primary lookup */
00353     _ENTRY(KEYFIRST),           /* Dbc.put */
00354     _ENTRY(KEYLAST),            /* Dbc.put */
00355     _ENTRY(LAST),               /* Dbc.get, DbLogc->get */
00356     _ENTRY(NEXT),               /* Dbc.get, DbLogc->get */
00357     _ENTRY(NEXT_DUP),           /* Dbc.get */
00358     _ENTRY(NEXT_NODUP),         /* Dbc.get */
00359     _ENTRY(NODUPDATA),          /* Db.put, Dbc.put */
00360     _ENTRY(NOOVERWRITE),        /* Db.put */
00361     _ENTRY(NOSYNC),             /* Db.close */
00362 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5)
00363     _ENTRY(OVERWRITE_DUP),      /* Dbc.put, Db.put; no DB_KEYEXIST */
00364 #endif
00365     _ENTRY(POSITION),           /* Dbc.dup */
00366     _ENTRY(PREV),               /* Dbc.get, DbLogc->get */
00367     _ENTRY(PREV_DUP),           /* Dbc.get */
00368     _ENTRY(PREV_NODUP),         /* Dbc.get */
00369     _ENTRY(SET),                /* Dbc.get, DbLogc->get */
00370     _ENTRY(SET_RANGE),          /* Dbc.get */
00371     _ENTRY(SET_RECNO),          /* Db.get, Dbc.get */
00372     _ENTRY(UPDATE_SECONDARY),   /* Dbc.get, Dbc.del (internal) */
00373 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5)
00374     _ENTRY(SET_LTE),            /* Dbc.get (internal) */
00375     _ENTRY(GET_BOTH_LTE),       /* Dbc.get (internal) */
00376 #endif
00377 
00378     _ENTRY(IGNORE_LEASE),
00379     _ENTRY(READ_COMMITTED),
00380     _ENTRY(READ_UNCOMMITTED),
00381     _ENTRY(MULTIPLE),
00382     _ENTRY(MULTIPLE_KEY),
00383     _ENTRY(RMW),
00384 };
00385 /*@unchecked@*/
00386 static size_t nDBCflags = sizeof(DBCflags) / sizeof(DBCflags[0]);
00387 /*@observer@*/
00388 static const char * fmtDBCflags(uint32_t flags)
00389         /*@*/
00390 {
00391     static char buf[BUFSIZ];
00392     char * te = buf;
00393     uint32_t op = (flags & DB_OPFLAGS_MASK);
00394     flags &= ~DB_OPFLAGS_MASK;
00395 
00396     te = stpcpy(te, "\n\tflags: ");
00397     if (op) {
00398         te = stpcpy( stpcpy(te, "DB_"), tblName(op, DBCflags, nDBCflags));
00399         *te++ = ' ';
00400         *te = '\0';
00401     }
00402     if (flags)
00403         (void) fmtBits(flags, DBCflags, nDBCflags, te);
00404     return buf;
00405 }
00406 #define _DBCFLAGS(_flags)       fmtDBCflags(_flags)
00407 
00408 #define _DBT_ENTRY(_v)      { DB_DBT_##_v, #_v, }
00409 /*@unchecked@*/ /*@observer@*/
00410 static KEY DBTflags[] = {
00411     _DBT_ENTRY(MALLOC),
00412     _DBT_ENTRY(REALLOC),
00413     _DBT_ENTRY(USERMEM),
00414     _DBT_ENTRY(PARTIAL),
00415     _DBT_ENTRY(APPMALLOC),
00416     _DBT_ENTRY(MULTIPLE),
00417 };
00418 /*@unchecked@*/
00419 static size_t nDBTflags = sizeof(DBTflags) / sizeof(DBTflags[0]);
00420 /*@observer@*/
00421 static char * fmtDBT(const DBT * K, char * te)
00422         /*@modifies te @*/
00423 {
00424     static size_t keymax = 35;
00425     int unprintable;
00426     uint32_t i;
00427 
00428     sprintf(te, "%p[%u]\t", K->data, (unsigned)K->size);
00429     te += strlen(te);
00430     (void) fmtBits(K->flags, DBTflags, nDBTflags, te);
00431     te += strlen(te);
00432     if (K->data && K->size > 0) {
00433         uint8_t * _u;
00434         size_t _nu;
00435 
00436         /* Grab the key data/size. */
00437         if (K->flags & DB_DBT_MULTIPLE) {
00438             DBT * _K = K->data;
00439             _u = _K->data;
00440             _nu = _K->size;
00441         } else {
00442             _u = K->data;
00443             _nu = K->size;
00444         }
00445         /* Verify if data is a string. */
00446         unprintable = 0;
00447         for (i = 0; i < _nu; i++)
00448             unprintable |= !xisprint(_u[i]);
00449 
00450         /* Display the data. */
00451         if (!unprintable) {
00452             size_t nb = (_nu < keymax ? _nu : keymax);
00453             char * ellipsis = (_nu < keymax ? "" : "...");
00454             sprintf(te, "\t\"%.*s%s\"", (int)nb, (char *)_u, ellipsis);
00455         } else {
00456             switch (_nu) {
00457             default: break;
00458             case 4:     sprintf(te, "\t0x%08x", (unsigned)*(uint32_t *)_u); break;
00459             }
00460         }
00461 
00462         te += strlen(te);
00463         *te = '\0';
00464     }
00465     return te;
00466 }
00467 /*@observer@*/
00468 static const char * fmtKDR(const DBT * K, const DBT * P, const DBT * D, const DBT * R)
00469         /*@*/
00470 {
00471     static char buf[BUFSIZ];
00472     char * te = buf;
00473 
00474     if (K) {
00475         te = stpcpy(te, "\n\t  key: ");
00476         te = fmtDBT(K, te);
00477     }
00478     if (P) {
00479         te = stpcpy(te, "\n\t pkey: ");
00480         te = fmtDBT(P, te);
00481     }
00482     if (D) {
00483         te = stpcpy(te, "\n\t data: ");
00484         te = fmtDBT(D, te);
00485     }
00486     if (R) {
00487         te = stpcpy(te, "\n\t  res: ");
00488         te = fmtDBT(R, te);
00489     }
00490     *te = '\0';
00491     
00492     return buf;
00493 }
00494 #define _KEYDATA(_K, _P, _D, _R)        fmtKDR(_K, _P, _D, _R)
00495 
00496 #undef  _ENTRY
00497 
00498 /*@-globuse -mustmod @*/        /* FIX: rpmError not annotated yet. */
00499 static int Xcvtdberr(/*@unused@*/ dbiIndex dbi, const char * msg,
00500                 int error, int printit,
00501                 const char * func, const char * fn, unsigned ln)
00502         /*@globals fileSystem @*/
00503         /*@modifies fileSystem @*/
00504 {
00505     int rc = error;
00506 
00507     if (printit && rc) {
00508 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00509         rpmlog(RPMLOG_ERR, "%s:%s:%u: %s(%d): %s\n",
00510                 func, fn, ln, msg, rc, db_strerror(error));
00511 /*@=moduncon@*/
00512     }
00513 
00514     return rc;
00515 }
00516 /*@=globuse =mustmod @*/
00517 #define cvtdberr(_dbi, _msg, _error, _printit)  \
00518     Xcvtdberr(_dbi, _msg, _error, _printit, __FUNCTION__, __FILE__, __LINE__)
00519 
00526 /*@observer@*/
00527 static const char * mapTagName(rpmdb rpmdb, dbiIndex dbi)
00528         /*@*/
00529 {
00530     tagStore_t dbiTags = rpmdb->db_tags;
00531     size_t dbix = 0;
00532 
00533     if (dbiTags != NULL)
00534     while (dbix < rpmdb->db_ndbi) {
00535         if (dbi->dbi_rpmtag == dbiTags->tag)
00536             return dbiTags->str;
00537         dbiTags++;
00538         dbix++;
00539     }
00540     /* XXX should never reach here */
00541     return tagName(dbi->dbi_rpmtag);
00542 }
00543 
00544 static int db_fini(dbiIndex dbi, const char * dbhome,
00545                 /*@null@*/ const char * dbfile,
00546                 /*@unused@*/ /*@null@*/ const char * dbsubfile)
00547         /*@globals fileSystem @*/
00548         /*@modifies fileSystem @*/
00549 {
00550     rpmdb rpmdb = dbi->dbi_rpmdb;
00551     DB_ENV * dbenv = rpmdb->db_dbenv;
00552     int rc;
00553 
00554 DBIDEBUG(dbi, (stderr, "--> %s(%p,%s,%s,%s)\n", __FUNCTION__, dbi, dbhome, dbfile, dbsubfile));
00555 
00556     if (dbenv == NULL)
00557         return 0;
00558 
00559     rc = dbenv->close(dbenv, 0);
00560     rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
00561     rpmdb->db_dbenv = NULL;
00562 
00563     if (dbfile)
00564         rpmlog(RPMLOG_DEBUG, D_("closed   db environment %s/%s\n"),
00565                         dbhome, dbfile);
00566 
00567     if (rpmdb->db_remove_env) {
00568         int xx;
00569 
00570         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00571         xx = db_env_create(&dbenv, 0);
00572         /*@=moduncon@*/
00573         if (!xx && dbenv != NULL) {
00574             xx = cvtdberr(dbi, "db_env_create", xx, _debug);
00575             xx = dbenv->remove(dbenv, dbhome, DB_FORCE);
00576             xx = cvtdberr(dbi, "dbenv->remove", xx, _debug);
00577 
00578             if (dbfile)
00579                 rpmlog(RPMLOG_DEBUG, D_("removed  db environment %s/%s\n"),
00580                         dbhome, dbfile);
00581         }
00582 
00583     }
00584     return rc;
00585 }
00586 
00587 static int db3_fsync_disable(/*@unused@*/ int fd)
00588         /*@*/
00589 {
00590     return 0;
00591 }
00592 
00593 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR == 5)
00594 
00602 static int db3is_alive(/*@unused@*/ DB_ENV *dbenv, pid_t pid,
00603                 /*@unused@*/ db_threadid_t tid,
00604                 rpmuint32_t flags)
00605         /*@*/
00606 {
00607     int is_alive = 1;   /* assume all processes are alive */
00608 
00609     switch (flags) {
00610     case DB_MUTEX_PROCESS_ONLY:
00611     case 0:
00612     default:
00613         is_alive = (!(kill(pid, 0) < 0 && errno == ESRCH));
00614         break;
00615     }
00616     return is_alive;
00617 }
00618 #endif
00619 
00620 /*==============================================================*/
00621 
00622 /* HAVE_SYS_SYSCTL_H */
00623 #if defined(HAVE_PHYSMEM_SYSCTL) || defined(HAVE_NCPU_SYSCTL)
00624 #include <sys/sysctl.h>
00625 #endif
00626 
00627 static uint64_t physmem(void)
00628         /*@*/
00629 {
00630     static uint64_t _physmem = 0;
00631     static int oneshot = 0;
00632 
00633     if (!oneshot) {
00634 #if defined(HAVE_PHYSMEM_SYSCONF)
00635         const long _pagesize = sysconf(_SC_PAGESIZE);
00636         const long _pages = sysconf(_SC_PHYS_PAGES);
00637         if (_pagesize != -1 || _pages != -1)
00638             _physmem = (uint64_t)(_pagesize) * (uint64_t)(_pages);
00639 #elif defined(HAVE_PHYSMEM_SYSCTL)
00640         int name[2] = { CTL_HW, HW_PHYSMEM };
00641         unsigned long mem;
00642         size_t mem_ptr_size = sizeof(mem);
00643         if (!sysctl(name, 2, &mem, &mem_ptr_size, NULL, 0)) {
00644             if (mem_ptr_size != sizeof(mem)) {
00645                 if (mem_ptr_size == sizeof(unsigned int))
00646                     _physmem = *(unsigned int *)(&mem);
00647             } else {
00648                 _physmem = mem;
00649             }
00650         }
00651 #endif
00652         oneshot++;
00653     }
00654     return _physmem;
00655 }
00656 
00657 static size_t ncores(void)
00658         /*@*/
00659 {
00660     static size_t _ncores = 1;
00661     static int oneshot = 0;
00662 
00663     if (!oneshot) {
00664 #if defined(HAVE_NCPU_SYSCONF)
00665         const long cpus = sysconf(_SC_NPROCESSORS_ONLN);
00666 #elif defined(HAVE_NCPU_SYSCTL)
00667         int name[2] = { CTL_HW, HW_NCPU };
00668         int cpus = 0;
00669         size_t cpus_size = sizeof(cpus);
00670         if (sysctl(name, 2, &cpus, &cpus_size, NULL, 0)
00671          || cpus_size != sizeof(cpus))
00672             cpus = 0;
00673 #endif
00674         if (cpus > (int)_ncores)
00675             _ncores = (size_t)(cpus);
00676         oneshot++;
00677     }
00678     return _ncores;
00679 }
00680 
00681 /*==============================================================*/
00682 #define _TABLE(_v)      { #_v, DB_EVENT_##_v }
00683 static struct _events_s {
00684     const char * n;
00685     uint32_t v;
00686 } _events[] = {
00687     _TABLE(NO_SUCH_EVENT),      /*  0 */
00688     _TABLE(PANIC),              /*  1 */
00689 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5)
00690     _TABLE(REG_ALIVE),          /*  2 */
00691     _TABLE(REG_PANIC),          /*  3 */
00692 #else
00693     _TABLE(NO_SUCH_EVENT),      /*  2 */
00694     _TABLE(NO_SUCH_EVENT),      /*  3 */
00695 #endif
00696     _TABLE(REP_CLIENT),         /*  4 */
00697     _TABLE(REP_ELECTED),        /*  5 */
00698     _TABLE(REP_MASTER),         /*  6 */
00699     _TABLE(REP_NEWMASTER),      /*  7 */
00700     _TABLE(REP_PERM_FAILED),    /*  8 */
00701     _TABLE(REP_STARTUPDONE),    /*  9 */
00702     _TABLE(WRITE_FAILED),       /* 10 */
00703     _TABLE(NO_SUCH_EVENT),      /* 11 */
00704     _TABLE(NO_SUCH_EVENT),      /* 12 */
00705     _TABLE(NO_SUCH_EVENT),      /* 13 */
00706     _TABLE(NO_SUCH_EVENT),      /* 14 */
00707     _TABLE(NO_SUCH_EVENT),      /* 15 */
00708 };
00709 #undef  _TABLE
00710 
00711 static void
00712 rpmdbe_event_notify(DB_ENV * dbenv, u_int32_t event, void * event_info)
00713 {
00714     void * o = (dbenv ? dbenv->app_private : NULL);
00715 fprintf(stderr, "==> %s(%p, %s(%u), %p) app_private %p\n", __FUNCTION__, dbenv, _events[event & 0xf].n, event, event_info, o);
00716 }
00717 
00718 static void
00719 rpmdbe_feedback(DB_ENV * dbenv, int opcode, int percent)
00720         /*@*/
00721 {
00722     dbenv = NULL;
00723     dbenv = dbenv;
00724     switch (opcode) {
00725     case DB_RECOVER:
00726         fprintf(stderr, "\rrecovery %d%% complete", percent);
00727         (void)fflush(stderr);   /* XXX unnecessary? */
00728         /*@fallthrough@*/
00729     default:
00730         break;
00731     }
00732 }
00733 
00734 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00735 static int db_init(dbiIndex dbi, const char * dbhome,
00736                 /*@null@*/ const char * dbfile,
00737                 /*@unused@*/ /*@null@*/ const char * dbsubfile,
00738                 /*@out@*/ DB_ENV ** dbenvp)
00739         /*@globals rpmGlobalMacroContext, h_errno,
00740                 fileSystem, internalState @*/
00741         /*@modifies dbi, *dbenvp, fileSystem, internalState @*/
00742 {
00743     static int oneshot = 0;
00744     uint64_t _physmem = physmem();
00745     size_t _ncores = ncores();
00746     rpmdb rpmdb = dbi->dbi_rpmdb;
00747     DB_ENV *dbenv = NULL;
00748     int eflags;
00749     int rc;
00750     int xx;
00751 
00752     if (!oneshot) {
00753         rpmlog(RPMLOG_DEBUG, D_("rpmdb: cpus %u physmem %uMb\n"),
00754                 (unsigned)_ncores, (unsigned)(_physmem/(1024 * 1024)));
00755         xx = db_env_set_func_open((int (*)(const char *, int, ...))Open);
00756         xx = cvtdberr(dbi, "db_env_set_func_open", xx, _debug);
00757         oneshot++;
00758     }
00759 
00760     if (dbenvp == NULL)
00761         return 1;
00762 
00763     /* XXX HACK */
00764     /*@-assignexpose@*/
00765     if (rpmdb->db_errfile == NULL)
00766         rpmdb->db_errfile = stderr;
00767     /*@=assignexpose@*/
00768 
00769     eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
00770     /* Try to join, rather than create, the environment. */
00771     /* XXX DB_JOINENV is defined to 0 in db-4.5.20 */
00772     if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
00773     /* XXX DB_RECOVER needs automagic */
00774     if (!(eflags & DB_INIT_TXN)) eflags &= ~DB_RECOVER;
00775 
00776     if (dbfile)
00777         rpmlog(RPMLOG_DEBUG, D_("opening  db environment %s/%s %s\n"),
00778                 dbhome, dbfile, prDbiOpenFlags(eflags, 1));
00779 
00780     /* XXX Can't do RPC w/o host. */
00781 #if defined(DB_RPCCLIENT)
00782     if (dbi->dbi_host == NULL)
00783         dbi->dbi_ecflags &= ~DB_RPCCLIENT;
00784 #endif
00785 
00786     rc = db_env_create(&dbenv, dbi->dbi_ecflags);
00787     rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00788     if (dbenv == NULL || rc)
00789         goto errxit;
00790 
00791 /*@-noeffectuncon@*/
00792 /*@-castfcnptr@*/
00793     dbenv->set_errcall(dbenv, (void *)rpmdb->db_errcall);
00794 /*@=castfcnptr@*/
00795     dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00796     dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00797 /*@=noeffectuncon@*/
00798 
00799  /* 4.1: dbenv->set_alloc(???) */
00800  /* 4.1: dbenv->set_data_dir(???) */
00801  /* 4.1: dbenv->set_encrypt(???) */
00802 
00803     xx = dbenv->set_feedback(dbenv, rpmdbe_feedback);
00804     xx = cvtdberr(dbi, "dbenv->set_feedback", xx, _debug);
00805     xx = dbenv->set_event_notify(dbenv, rpmdbe_event_notify);
00806     xx = cvtdberr(dbi, "dbenv->set_event_notify", xx, _debug);
00807 
00808  /* 4.1: dbenv->set_flags(???) */
00809 
00810  /* dbenv->set_paniccall(???) */
00811 
00812 #if defined(DB_RPCCLIENT)
00813     if ((dbi->dbi_ecflags & DB_RPCCLIENT) && dbi->dbi_host) {
00814         const char * home;
00815         int retry = 0;
00816 
00817         if ((home = strrchr(dbhome, '/')) != NULL)
00818             dbhome = ++home;
00819 
00820         while (retry++ < 5) {
00821 /* XXX 3.3.4 change. */
00822             xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
00823                 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00824             xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00825             if (!xx)
00826                 break;
00827             (void) sleep(15);
00828         }
00829     } else
00830 #endif
00831     {
00832 
00833         {   size_t _lo =  16 * 1024 * 1024;
00834             size_t _hi = 512 * 1024 * 1024;
00835             size_t _mp_mmapsize = _physmem;     /* XXX default value? */
00836             if (_mp_mmapsize < _lo) _mp_mmapsize = _lo;
00837             if (_mp_mmapsize > _hi) _mp_mmapsize = _hi;
00838             xx = dbenv->set_mp_mmapsize(dbenv, _mp_mmapsize);
00839             xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
00840         }
00841 
00842         if (dbi->dbi_tmpdir) {
00843             const char * root;
00844             const char * tmpdir;
00845 
00846             root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00847             if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00848                 root = NULL;
00849 /*@-mods@*/
00850             tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00851 /*@=mods@*/
00852             xx = dbenv->set_tmp_dir(dbenv, tmpdir);
00853             xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug);
00854             tmpdir = _free(tmpdir);
00855         }
00856     }
00857 
00858 /* ==== Locking: */
00859 #define _RPMDB_NLOCKS   8192
00860     if (eflags & DB_INIT_LOCK) {
00861         uint32_t _lk_max_lockers = _RPMDB_NLOCKS;
00862         uint32_t _lk_max_locks = _RPMDB_NLOCKS;
00863         uint32_t _lk_max_objects = _RPMDB_NLOCKS;
00864 
00865         xx = dbenv->set_lk_max_lockers(dbenv, _lk_max_lockers);
00866         xx = cvtdberr(dbi, "dbenv->set_lk_max_lockers", xx, _debug);
00867         xx = dbenv->set_lk_max_locks(dbenv, _lk_max_locks);
00868         xx = cvtdberr(dbi, "dbenv->set_lk_max_locks", xx, _debug);
00869         xx = dbenv->set_lk_max_objects(dbenv, _lk_max_objects);
00870         xx = cvtdberr(dbi, "dbenv->set_lk_max_objects", xx, _debug);
00871 
00872       { uint32_t _max = 10 * _RPMDB_NLOCKS;
00873         xx = dbenv->mutex_set_max(dbenv, _max);
00874         xx = cvtdberr(dbi, "dbenv->mutex_set_max", xx, _debug);
00875       }
00876 
00877     }
00878 
00879 /* ==== Logging: */
00880 /* ==== Memory pool: */
00881     if (eflags & DB_INIT_MPOOL) {
00882         uint32_t _lo =  16 * 1024 * 1024;
00883         uint32_t _hi = 512 * 1024 * 1024;
00884         uint32_t _gb = 0;
00885         uint32_t _bytes = _physmem;             /* XXX default value? */
00886         int _ncache = 4;
00887         if (_bytes < _lo) _bytes = _lo;
00888         if (_bytes > _hi) _bytes = _hi;
00889         xx = dbenv->set_cache_max(dbenv, _gb, _hi);
00890         xx = cvtdberr(dbi, "dbenv->set_cache_max", xx, _debug);
00891         if (_ncache > 0)
00892             _bytes /= _ncache;
00893         xx = dbenv->set_cachesize(dbenv, _gb, _bytes, _ncache);
00894         xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
00895     }
00896 
00897 /* ==== Mutexes: */
00898 /* ==== Replication: */
00899 /* ==== Sequences: */
00900 /* ==== Transactions: */
00901 #ifdef  NOTYET  /* XXX syscall ACID needs --with-db=internal */
00902     if (eflags & DB_INIT_TXN) {
00903         xx = dbenv->set_app_dispatch(dbenv, logio_dispatch);
00904         xx = cvtdberr(dbi, "dbenv->set_app_dispatch", xx, _debug);
00905     }
00906 #endif
00907 
00908 /* ==== Other: */
00909     if (dbi->dbi_no_fsync) {
00910         xx = db_env_set_func_fsync(db3_fsync_disable);
00911         xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
00912     }
00913 
00914     /* XXX Set a default shm_key. */
00915     if ((eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
00916 #if defined(HAVE_FTOK)
00917         dbi->dbi_shmkey = ftok(dbhome, 0);
00918 #else
00919         dbi->dbi_shmkey = 0x44631380;
00920 #endif
00921     }
00922     if (dbi->dbi_shmkey) {
00923         xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
00924         xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
00925     }
00926 
00927 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR == 5)
00928     /* XXX capture dbenv->falchk output on stderr. */
00929 /*@-noeffectuncon@*/
00930     dbenv->set_msgfile(dbenv, rpmdb->db_errfile);
00931 /*@=noeffectuncon@*/
00932     if (dbi->dbi_thread_count >= 8) {
00933         xx = dbenv->set_thread_count(dbenv, dbi->dbi_thread_count);
00934         xx = cvtdberr(dbi, "dbenv->set_thread_count", xx, _debug);
00935     }
00936 #endif
00937 
00938     /* XXX Attempt db_recover -ev (i.e. dbenv w DB_INIT_LOCK) */
00939     if (eflags & DB_RECOVER) {
00940         eflags |= DB_CREATE;
00941         xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1);
00942         xx = cvtdberr(dbi, "dbenv->set_verbose", xx, _debug);
00943     }
00944 
00945     rc = (dbenv->open)(dbenv, dbhome, eflags, dbi->dbi_perms);
00946     xx = _debug;
00947 #if defined(DB_VERSION_MISMATCH)
00948     if (rc == DB_VERSION_MISMATCH) xx = 0;
00949 #endif
00950     if (rc == EINVAL) xx = 0;
00951     rc = cvtdberr(dbi, "dbenv->open", rc, xx);
00952     if (rc)
00953         goto errxit;
00954 
00955 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR == 5)
00956     if (dbi->dbi_thread_count >= 8) {
00957         /* XXX Set pid/tid is_alive probe. */
00958         xx = dbenv->set_isalive(dbenv, db3is_alive);
00959         xx = cvtdberr(dbi, "dbenv->set_isalive", xx, _debug);
00960         /* XXX Clean out stale shared read locks. */
00961         xx = dbenv->failchk(dbenv, 0);
00962         xx = cvtdberr(dbi, "dbenv->failchk", xx, _debug);
00963         if (xx == DB_RUNRECOVERY) {
00964             rc = xx;
00965             goto errxit;
00966         }
00967     }
00968 #endif
00969 
00970     *dbenvp = dbenv;
00971 
00972 DBIDEBUG(dbi, (stderr, "<-- %s(%p(%s),%s,%s,%s,%p) dbenv %p %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbhome, dbfile, dbsubfile, dbenvp, dbenv, _EFLAGS(eflags)));
00973 
00974     return 0;
00975 
00976 errxit:
00977     if (dbenv) {
00978         xx = dbenv->close(dbenv, 0);
00979         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
00980     }
00981     return rc;
00982 }
00983 /*@=moduncon@*/
00984 
00985 #ifdef  NOTYET
00986 /*@-mustmod@*/
00987 static int db3remove(dbiIndex dbi, /*@null@*/ const char * dbfile,
00988                 /*@unused@*/ /*@null@*/ const char * dbsubfile,
00989                 unsigned int flags)
00990         /*@globals fileSystem @*/
00991         /*@modifies dbi, fileSystem @*/
00992 {
00993     DB * db = dbi->dbi_db;
00994     int rc;
00995 
00996 assert(db != NULL);
00997     rc = db->remove(db, dbfile, dbsubfile, flags);
00998     rc = cvtdberr(dbi, "db->remove", rc, _debug);
00999 
01000 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%s,0x%x) rc %d\n", __FUNCTION__, dbi, dbfile, dbsubfile, flags, rc));
01001 
01002     return rc;
01003 }
01004 /*@=mustmod@*/
01005 
01006 /*@-mustmod@*/
01007 static int db3rename(dbiIndex dbi, /*@null@*/ const char * dbfile,
01008                 /*@unused@*/ /*@null@*/ const char * dbsubfile,
01009                 /*@unused@*/ /*@null@*/ const char * newname,
01010                 unsigned int flags)
01011         /*@globals fileSystem @*/
01012         /*@modifies dbi, fileSystem @*/
01013 {
01014     DB * db = dbi->dbi_db;
01015     int rc;
01016 
01017 assert(db != NULL);
01018     rc = db->rename(db, dbfile, dbsubfile, newname, flags);
01019     rc = cvtdberr(dbi, "db->rename", rc, _debug);
01020 
01021 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%s,%s,0x%x) rc %d %s\n", __FUNCTION__, dbi, dbfile, dbsubfile, newname, flags, rc, _DBCFLAGS(flags)));
01022 
01023     return rc;
01024 }
01025 /*@=mustmod@*/
01026 
01027 /*@-mustmod@*/
01028 static int db3truncate(dbiIndex dbi, unsigned int * countp, unsigned int flags)
01029         /*@globals fileSystem @*/
01030         /*@modifies *countp, fileSystem @*/
01031 {
01032     DB * db = dbi->dbi_db;
01033     DB_TXN * _txnid = dbiTxnid(dbi);
01034     int rc;
01035 
01036 assert(db != NULL);
01037     rc = db->truncate(db, _txnid, countp, flags);
01038     rc = cvtdberr(dbi, "db->truncate", rc, _debug);
01039 
01040 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, countp, flags, rc));
01041 
01042     return rc;
01043 }
01044 /*@=mustmod@*/
01045 
01046 /*@-mustmod@*/
01047 static int db3upgrade(dbiIndex dbi, /*@null@*/ const char * dbfile,
01048                 unsigned int flags)
01049         /*@globals fileSystem @*/
01050         /*@modifies fileSystem @*/
01051 {
01052     DB * db = dbi->dbi_db;
01053     int rc;
01054 
01055 assert(db != NULL);
01056     rc = db->upgrade(db, dbfile, flags);
01057     rc = cvtdberr(dbi, "db->upgrade", rc, _debug);
01058 
01059 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,0x%x) rc %d\n", __FUNCTION__, dbi, dbfile, flags, rc));
01060 
01061     return rc;
01062 }
01063 /*@=mustmod@*/
01064 #endif  /* NOTYET */
01065 
01066 static int db3sync(dbiIndex dbi, unsigned int flags)
01067         /*@globals fileSystem @*/
01068         /*@modifies fileSystem @*/
01069 {
01070     DB * db = dbi->dbi_db;
01071     int rc = 0;
01072     int _printit;
01073 
01074     if (db != NULL)
01075         rc = db->sync(db, flags);
01076     _printit = _debug;
01077     rc = cvtdberr(dbi, "db->sync", rc, _printit);
01078 
01079 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc));
01080 
01081     return rc;
01082 }
01083 
01084 /*@-mustmod@*/
01085 static int db3exists(dbiIndex dbi, DBT * key, unsigned int flags)
01086         /*@globals fileSystem @*/
01087         /*@modifies fileSystem @*/
01088 {
01089     DB * db = dbi->dbi_db;
01090     DB_TXN * _txnid = dbiTxnid(dbi);
01091     int _printit;
01092     int rc;
01093 
01094 assert(db != NULL);
01095     rc = db->exists(db, _txnid, key, flags);
01096     /* XXX DB_NOTFOUND can be returned */
01097     _printit = (rc == DB_NOTFOUND ? 0 : _debug);
01098     rc = cvtdberr(dbi, "db->exists", rc, _printit);
01099 
01100 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, key, flags, rc, _KEYDATA(key, NULL, NULL, NULL)));
01101 
01102     return rc;
01103 }
01104 /*@=mustmod@*/
01105 
01106 /*@-mustmod@*/
01107 static int db3seqno(dbiIndex dbi, int64_t * seqnop, unsigned int flags)
01108         /*@globals fileSystem @*/
01109         /*@modifies *seqnop, fileSystem @*/
01110 {
01111     DB * db = dbi->dbi_db;
01112     DB_TXN * _txnid = dbiTxnid(dbi);
01113     DB_SEQUENCE * seq = dbi->dbi_seq;
01114     int32_t _delta = 1;
01115     db_seq_t seqno = 0;
01116     int rc;
01117 
01118 assert(db != NULL);
01119 assert(seq != NULL);
01120 
01121     if (seqnop && *seqnop)
01122         _delta = *seqnop;
01123 
01124     rc = seq->get(seq, _txnid, _delta, &seqno, 0);  
01125     rc = cvtdberr(dbi, "seq->get", rc, _debug);
01126     if (rc) goto exit;
01127 
01128     if (seqnop)
01129         *seqnop = seqno;
01130 
01131 exit:
01132 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) seqno %lld rc %d\n", __FUNCTION__, dbi, seqnop, flags, (long long)seqno, rc));
01133 
01134     return rc;
01135 }
01136 /*@=mustmod@*/
01137 
01138 static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
01139                 unsigned int flags)
01140         /*@globals fileSystem @*/
01141         /*@modifies *dbcp, fileSystem @*/
01142 {
01143     int rc;
01144 
01145     if (dbcp) *dbcp = NULL;
01146 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5)
01147     rc = dbcursor->dup(dbcursor, dbcp, flags);
01148     rc = cvtdberr(dbi, "dbcursor->dup", rc, _debug);
01149 #else
01150     rc = dbcursor->c_dup(dbcursor, dbcp, flags);
01151     rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
01152 #endif
01153 
01154 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, dbcursor, dbcp, flags, rc));
01155 
01156     return rc;
01157 }
01158 
01159 /*@-mustmod@*/
01160 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
01161                 /*@unused@*/ unsigned int flags)
01162         /*@globals fileSystem @*/
01163         /*@modifies dbi, fileSystem @*/
01164 {
01165     int rc = -2;
01166 
01167     /* XXX db3copen error pathways come through here. */
01168     if (dbcursor != NULL) {
01169 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5)
01170         rc = dbcursor->close(dbcursor);
01171         rc = cvtdberr(dbi, "dbcursor->close", rc, _debug);
01172 #else
01173         rc = dbcursor->c_close(dbcursor);
01174         rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
01175 #endif
01176     }
01177 
01178 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, dbcursor, flags, rc));
01179 
01180     return rc;
01181 }
01182 /*@=mustmod@*/
01183 
01184 static int db3copen(dbiIndex dbi, DB_TXN * txnid,
01185                 /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int dbiflags)
01186         /*@globals fileSystem @*/
01187         /*@modifies dbi, *dbcp, fileSystem @*/
01188 {
01189     DB * db = dbi->dbi_db;
01190     DBC * dbcursor = NULL;
01191     int flags;
01192     int rc;
01193 
01194    /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */
01195     assert(db != NULL);
01196     if ((dbiflags & DB_WRITECURSOR) &&
01197         (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
01198     {
01199         flags = DB_WRITECURSOR;
01200     } else
01201         flags = 0;
01202 
01203     rc = db->cursor(db, txnid, &dbcursor, flags);
01204     rc = cvtdberr(dbi, "db->cursor", rc, _debug);
01205 
01206     if (dbcp)
01207         *dbcp = dbcursor;
01208     else
01209         (void) db3cclose(dbi, dbcursor, 0);
01210 
01211 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) dbc %p rc %d\n", __FUNCTION__, dbi, txnid, dbcp, dbiflags, dbcursor, rc));
01212     return rc;
01213 }
01214 
01215 static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
01216                 /*@unused@*/ unsigned int flags)
01217         /*@globals fileSystem @*/
01218         /*@modifies fileSystem @*/
01219 {
01220     DB * db = dbi->dbi_db;
01221     DB_TXN * _txnid = dbiTxnid(dbi);
01222     int rc;
01223 
01224     assert(db != NULL);
01225     if (dbcursor == NULL) {
01226 flags = 0;
01227         rc = db->put(db, _txnid, key, data, flags);
01228         rc = cvtdberr(dbi, "db->put", rc, _debug);
01229     } else {
01230 flags = DB_KEYLAST;
01231 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5)
01232         rc = dbcursor->put(dbcursor, key, data, flags);
01233         rc = cvtdberr(dbi, "dbcursor->put", rc, _debug);
01234 #else
01235         rc = dbcursor->c_put(dbcursor, key, data, flags);
01236         rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
01237 #endif
01238     }
01239 
01240 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL)));
01241     return rc;
01242 }
01243 
01244 /*@-mustmod@*/
01245 static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
01246                 unsigned int flags)
01247         /*@globals fileSystem @*/
01248         /*@modifies *dbcursor, *key, *data, fileSystem @*/
01249 {
01250     DB * db = dbi->dbi_db;
01251     DB_TXN * _txnid = dbiTxnid(dbi);
01252     int _printit;
01253     int rc;
01254 
01255 assert(db != NULL);
01256     if (dbcursor == NULL) {
01257         /* XXX duplicates require cursors. */
01258         rc = db->get(db, _txnid, key, data, flags);
01259         /* XXX DB_NOTFOUND can be returned */
01260         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
01261         rc = cvtdberr(dbi, "db->get", rc, _printit);
01262     } else {
01263 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5)
01264         /* XXX db3 does DB_FIRST on uninitialized cursor */
01265         rc = dbcursor->get(dbcursor, key, data, flags);
01266         /* XXX DB_NOTFOUND can be returned */
01267         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
01268         /* XXX Permit DB_BUFFER_SMALL to be returned (more restrictive?) */
01269         _printit = (rc == DB_BUFFER_SMALL ? 0 : _printit);
01270         rc = cvtdberr(dbi, "dbcursor->get", rc, _printit);
01271 #else
01272         /* XXX db3 does DB_FIRST on uninitialized cursor */
01273         rc = dbcursor->c_get(dbcursor, key, data, flags);
01274         /* XXX DB_NOTFOUND can be returned */
01275         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
01276         rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
01277 #endif
01278     }
01279 
01280 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL)));
01281     return rc;
01282 }
01283 /*@=mustmod@*/
01284 
01285 /*@-mustmod@*/
01286 static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey,
01287                 DBT * data, unsigned int flags)
01288         /*@globals fileSystem @*/
01289         /*@modifies *dbcursor, *key, *data, fileSystem @*/
01290 {
01291     DB * db = dbi->dbi_db;
01292     DB_TXN * _txnid = dbiTxnid(dbi);
01293     int _printit;
01294     int rc;
01295 
01296 assert(db != NULL);
01297     if (dbcursor == NULL) {
01298         /* XXX duplicates require cursors. */
01299         rc = db->pget(db, _txnid, key, pkey, data, flags);
01300         /* XXX DB_NOTFOUND can be returned */
01301         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
01302         rc = cvtdberr(dbi, "db->pget", rc, _printit);
01303     } else {
01304 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5)
01305         /* XXX db3 does DB_FIRST on uninitialized cursor */
01306         rc = dbcursor->pget(dbcursor, key, pkey, data, flags);
01307         /* XXX DB_NOTFOUND can be returned */
01308         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
01309         rc = cvtdberr(dbi, "dbcursor->pget", rc, _printit);
01310 #else
01311         /* XXX db3 does DB_FIRST on uninitialized cursor */
01312         rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags);
01313         /* XXX DB_NOTFOUND can be returned */
01314         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
01315         rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit);
01316 #endif
01317     }
01318 
01319 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, pkey, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, pkey, data, NULL)));
01320     return rc;
01321 }
01322 /*@=mustmod@*/
01323 
01324 /*@-mustmod@*/
01325 static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
01326                 unsigned int flags)
01327         /*@globals fileSystem @*/
01328         /*@modifies *dbcursor, fileSystem @*/
01329 {
01330     DB * db = dbi->dbi_db;
01331     DB_TXN * _txnid = dbiTxnid(dbi);
01332     int rc;
01333 
01334 assert(db != NULL);
01335     if (dbcursor == NULL) {
01336         rc = db->del(db, _txnid, key, flags);
01337         rc = cvtdberr(dbi, "db->del", rc, _debug);
01338     } else {
01339 
01340         /* XXX TODO: insure that cursor is positioned with duplicates */
01341         rc = db3cget(dbi, dbcursor, key, data, DB_SET);
01342 
01343         if (rc == 0) {
01344 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5)
01345             rc = dbcursor->del(dbcursor, flags);
01346             rc = cvtdberr(dbi, "dbcursor->del", rc, _debug);
01347 #else
01348             rc = dbcursor->c_del(dbcursor, flags);
01349             rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
01350 #endif
01351         }
01352     }
01353 
01354 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL)));
01355     return rc;
01356 }
01357 /*@=mustmod@*/
01358 
01359 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
01360                 /*@null@*/ /*@out@*/ unsigned int * countp,
01361                 /*@unused@*/ unsigned int flags)
01362         /*@globals fileSystem @*/
01363         /*@modifies *countp, fileSystem @*/
01364 {
01365     db_recno_t count = 0;
01366     int rc = 0;
01367 
01368     flags = 0;
01369 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5)
01370     rc = dbcursor->count(dbcursor, &count, flags);
01371     rc = cvtdberr(dbi, "dbcursor->count", rc, _debug);
01372 #else
01373     rc = dbcursor->c_count(dbcursor, &count, flags);
01374     rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
01375 #endif
01376     if (countp) *countp = (!rc ? count : 0);
01377 
01378 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) count %d\n", __FUNCTION__, dbi, dbcursor, countp, flags, count));
01379 
01380     return rc;
01381 }
01382 
01383 static int db3byteswapped(dbiIndex dbi) /*@*/
01384 {
01385     DB * db = dbi->dbi_db;
01386     int rc = 0;
01387 
01388     if (db != NULL) {
01389         int isswapped = 0;
01390         rc = db->get_byteswapped(db, &isswapped);
01391         if (rc == 0)
01392             rc = isswapped;
01393     }
01394 
01395     return rc;
01396 }
01397 
01398 static int db3stat(dbiIndex dbi, unsigned int flags)
01399         /*@globals fileSystem @*/
01400         /*@modifies dbi, fileSystem @*/
01401 {
01402     DB * db = dbi->dbi_db;
01403 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR == 5)
01404     DB_TXN * _txnid = dbiTxnid(dbi);
01405 #endif
01406     int rc = 0;
01407 
01408     assert(db != NULL);
01409 #if defined(DB_FAST_STAT)
01410     if (flags)
01411         flags = DB_FAST_STAT;
01412     else
01413 #endif
01414         flags = 0;
01415     dbi->dbi_stats = _free(dbi->dbi_stats);
01416 /* XXX 3.3.4 change. */
01417 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR == 5)
01418     rc = db->stat(db, _txnid, &dbi->dbi_stats, flags);
01419 #else
01420     rc = db->stat(db, &dbi->dbi_stats, flags);
01421 #endif
01422     rc = cvtdberr(dbi, "db->stat", rc, _debug);
01423 
01424 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc));
01425 
01426     return rc;
01427 }
01428 
01429 /*@-mustmod@*/
01430 static int db3associate(dbiIndex dbi, dbiIndex dbisecondary,
01431                 int (*callback)(DB *, const DBT *, const DBT *, DBT *),
01432                 unsigned int flags)
01433         /*@globals fileSystem @*/
01434         /*@modifies dbi, fileSystem @*/
01435 {
01436     DB * db = dbi->dbi_db;
01437     DB * secondary = dbisecondary->dbi_db;
01438     DB_TXN * _txnid = dbiTxnid(dbi);
01439     int rc;
01440 
01441 assert(db != NULL);
01442 
01443 /*@-moduncon@*/ /* FIX: annotate db3 methods */
01444     rc = db->associate(db, _txnid, secondary, callback, flags);
01445 /*@=moduncon@*/
01446     rc = cvtdberr(dbi, "db->associate", rc, _debug);
01447 
01448     if (dbi->dbi_debug || dbisecondary->dbi_debug) {
01449         const char * tag2 = xstrdup(tagName(dbisecondary->dbi_rpmtag));
01450 fprintf(stderr, "<-- %s(%p(%s),%p(%s),%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbisecondary, tag2, (void *)callback, flags, rc, _AFLAGS(flags));
01451         tag2 = _free(tag2);
01452     }
01453 
01454     return rc;
01455 }
01456 /*@=mustmod@*/
01457 
01458 /*@-mustmod@*/
01459 static int db3associate_foreign(dbiIndex dbi, dbiIndex dbisecondary,
01460                 int (*callback)(DB *, const DBT *, DBT *, const DBT *, int *),
01461                 unsigned int flags)
01462         /*@globals fileSystem @*/
01463         /*@modifies dbi, fileSystem @*/
01464 {
01465     int rc = ENOTSUP;;
01466 
01467 #if !defined(__LCLINT__)
01468 /*@-moduncon@*/ /* FIX: annotate db3 methods */
01469 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5)
01470     DB * db = dbi->dbi_db;
01471     DB * secondary = dbisecondary->dbi_db;
01472 assert(db != NULL);
01473     rc = db->associate_foreign(db, secondary, callback, flags);
01474 #endif
01475 /*@=moduncon@*/
01476 #endif  /* !defined(__LCLINT__) */
01477     rc = cvtdberr(dbi, "db->associate_foreign", rc, _debug);
01478 
01479     if (dbi->dbi_debug || dbisecondary->dbi_debug) {
01480         const char * tag2 = xstrdup(tagName(dbisecondary->dbi_rpmtag));
01481 fprintf(stderr, "<-- %s(%p(%s),%p(%s),%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbisecondary, tag2, callback, flags, rc, _AFFLAGS(flags));
01482         tag2 = _free(tag2);
01483     }
01484 
01485     return rc;
01486 }
01487 /*@=mustmod@*/
01488 
01489 /*@-mustmod@*/
01490 static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp,
01491                 unsigned int flags)
01492         /*@globals fileSystem @*/
01493         /*@modifies dbi, fileSystem @*/
01494 {
01495     DB * db = dbi->dbi_db;
01496     int rc;
01497 
01498 DBIDEBUG(dbi, (stderr, "--> %s(%p,%p,%p,0x%x)\n", __FUNCTION__, dbi, curslist, dbcp, flags));
01499 assert(db != NULL);
01500 /*@-moduncon@*/ /* FIX: annotate db3 methods */
01501     rc = db->join(db, curslist, dbcp, flags);
01502 /*@=moduncon@*/
01503     rc = cvtdberr(dbi, "db->join", rc, _debug);
01504     return rc;
01505 }
01506 /*@=mustmod@*/
01507 
01508 /*@-moduncon@*/ /* FIX: annotate db3 methods */
01509 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
01510         /*@globals rpmGlobalMacroContext, h_errno,
01511                 fileSystem, internalState @*/
01512         /*@modifies dbi, fileSystem, internalState @*/
01513 {
01514     rpmdb rpmdb = dbi->dbi_rpmdb;
01515     const char * urlfn = NULL;
01516     const char * root;
01517     const char * home;
01518     const char * dbhome;
01519     const char * dbfile;
01520     const char * dbsubfile;
01521     DB * db = dbi->dbi_db;
01522     DB_SEQUENCE * seq = dbi->dbi_seq;
01523     const char * dbiBN = mapTagName(rpmdb, dbi);
01524     int _printit;
01525     int rc = 0, xx;
01526 
01527     flags = 0;  /* XXX unused */
01528 
01529     /*
01530      * Get the prefix/root component and directory path.
01531      */
01532     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
01533     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
01534         root = NULL;
01535     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
01536 
01537     /*
01538      * Either the root or directory components may be a URL. Concatenate,
01539      * convert the URL to a path, and add the name of the file.
01540      */
01541     /*@-mods@*/
01542     urlfn = rpmGenPath(root, home, NULL);
01543     /*@=mods@*/
01544     (void) urlPath(urlfn, &dbhome);
01545     if (dbi->dbi_temporary) {
01546         dbfile = NULL;
01547         dbsubfile = NULL;
01548     } else {
01549 #ifdef  HACK    /* XXX necessary to support dbsubfile */
01550         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
01551         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : dbiBN);
01552 #else
01553         dbfile = (dbi->dbi_file ? dbi->dbi_file : dbiBN);
01554         dbsubfile = NULL;
01555 #endif
01556     }
01557 
01558     if (seq) {
01559         rc = seq->close(seq, 0);  
01560         rc = cvtdberr(dbi, "seq->close", rc, _debug);
01561         seq = dbi->dbi_seq = NULL;
01562 
01563         rpmlog(RPMLOG_DEBUG, D_("closed   db seqno       %s/%s\n"),
01564                 dbhome, (dbfile ? dbfile : dbiBN));
01565 
01566     }
01567     if (db) {
01568         rc = db->close(db, 0);
01569         /* XXX ignore not found error messages. */
01570         _printit = (rc == ENOENT ? 0 : _debug);
01571         rc = cvtdberr(dbi, "db->close", rc, _printit);
01572         db = dbi->dbi_db = NULL;
01573 
01574         rpmlog(RPMLOG_DEBUG, D_("closed   db index       %s/%s\n"),
01575                 dbhome, (dbfile ? dbfile : dbiBN));
01576 
01577     }
01578 
01579     if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) {
01580         if (rpmdb->db_opens == 1) {
01581             /*@-nullstate@*/
01582             xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
01583             /*@=nullstate@*/
01584             rpmdb->db_dbenv = NULL;
01585         }
01586         rpmdb->db_opens--;
01587     }
01588 
01589 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc));
01590 
01591     dbi->dbi_db = NULL;
01592 
01593     urlfn = _free(urlfn);
01594 
01595     dbi = db3Free(dbi);
01596 
01597     return rc;
01598 }
01599 /*@=moduncon@*/
01600 
01606 static inline unsigned char nibble(char c)
01607         /*@*/
01608 {
01609     if (c >= '0' && c <= '9')
01610         return (unsigned char)(c - '0');
01611     if (c >= 'A' && c <= 'F')
01612         return (unsigned char)((int)(c - 'A') + 10);
01613     if (c >= 'a' && c <= 'f')
01614         return (unsigned char)((int)(c - 'a') + 10);
01615     return '\0';
01616 }
01617 
01618 static int loadDBT(DBT * _r, rpmTag tag, const void * _s, size_t ns)
01619         /*@modifies *_r @*/
01620 {
01621     const char * s = _s;
01622     void * data = NULL;
01623     size_t size = 0;
01624     uint8_t * t = NULL;
01625     uint32_t i;
01626     int xx;
01627 
01628     if (ns == 0) ns = strlen(s);
01629     switch (tag) {
01630     case RPMTAG_FILEDIGESTS:
01631         /* Convert hex to binary, filter out odd hex strings. */
01632         if (ns > 0 && !(ns & 1)) {
01633             ns /= 2;
01634             data = t = xmalloc(ns);
01635             for (i = 0; i < ns; i++, t++, s += 2) {
01636                 if (!(isxdigit(s[0]) && isxdigit(s[1])))
01637                     /*@loopbreak@*/ break;
01638                 *t = (uint8_t) (nibble(s[0]) << 4) | nibble(s[1]);
01639             }
01640             if (i == ns)
01641                 size = ns;
01642             else
01643                 data = _free(data);
01644         }
01645         break;
01646     case RPMTAG_PUBKEYS:
01647         /* Extract pubkey id from the base64 blob. */
01648         t = xmalloc(32);
01649         if ((xx = pgpExtractPubkeyFingerprint(s, t)) > 0) {
01650             data = t;
01651             size = xx;
01652         } else
01653             t = _free(t);
01654         break;
01655     default:
01656         data = (void *) memcpy(xmalloc(ns), _s, ns);
01657         size = ns;
01658         break;
01659     }
01660     if ((_r->data = data) != NULL) _r->flags |= DB_DBT_APPMALLOC;
01661     return (_r->size = size);
01662 }
01663 
01664 static int uint32Cmp(const void * _a, const void * _b)
01665         /*@*/
01666 {
01667     const uint32_t * a = _a;
01668     const uint32_t * b = _b;
01669     return ((*a < *b) ? -1 :
01670            ((*a > *b) ?  1 : 0));
01671 }
01672 
01673 static int uint64Cmp(const void * _a, const void * _b)
01674         /*@*/
01675 {
01676     const uint64_t * a = _a;
01677     const uint64_t * b = _b;
01678     return ((*a < *b) ? -1 :
01679            ((*a > *b) ?  1 : 0));
01680 }
01681 
01682 static int
01683 db3Acallback(DB * db, const DBT * key, const DBT * data, DBT * _r)
01684         /*@globals internalState @*/
01685         /*@modifies *_r, internalState @*/
01686 {
01687     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01688     HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
01689 #ifdef  NOTYET
01690     HE_t FMhe = memset(alloca(sizeof(*FMhe)), 0, sizeof(*FMhe));
01691 #endif
01692     dbiIndex dbi = db->app_private;
01693     rpmdb rpmdb = NULL;
01694     Header h = NULL;
01695     uint32_t hdrNum;
01696     DBT * A = NULL;
01697     const char * s = NULL;
01698     size_t ns = 0;
01699     int rc = DB_DONOTINDEX;     /* assume no-op */
01700     uint32_t i;
01701     int xx;
01702 
01703 assert(key->size == sizeof(hdrNum));
01704     memcpy(&hdrNum, key->data, key->size);
01705     hdrNum = _ntoh_ui(hdrNum);
01706 
01707     /* XXX Don't index the header instance counter at record 0. */
01708     if (hdrNum == 0)
01709         goto exit;
01710 
01711 assert(dbi);
01712     rpmdb = dbi->dbi_rpmdb;
01713 assert(rpmdb);
01714 
01715     /* XXX Track the maximum primary key value. */
01716     if (hdrNum > rpmdb->db_maxkey)
01717         rpmdb->db_maxkey = hdrNum;
01718 
01719     h = headerLink(rpmdb->db_h);
01720     if (h == NULL) {
01721         /* XXX needs PROT_READ somewhen. */
01722         h = headerLoad(data->data);
01723         if (h == NULL) {
01724             rpmlog(RPMLOG_ERR,
01725                 _("db3: header #%u cannot be loaded -- skipping.\n"),
01726                 (unsigned)hdrNum);
01727             goto exit;
01728         }
01729     }
01730 
01731     memset(_r, 0, sizeof(*_r));
01732 
01733     he->tag = dbi->dbi_rpmtag;
01734     if (!headerGet(h, he, 0))
01735         goto exit;
01736 
01737     /* XXX catch busted headerGet() rc on RPMTAG_FILEPATHS w empty list. */
01738 assert(he->p.ptr != NULL && he->c > 0);
01739 
01740     /* Retrieve other tags needed for filtering decisions. */
01741     switch (he->tag) {
01742     default:
01743         break;
01744 #ifdef  NOTYET
01745     case RPMTAG_BASENAMES:
01746     case RPMTAG_FILEPATHS:
01747         /* XXX Add the pesky trailing '/' to directories. */
01748         FMhe->tag = RPMTAG_FILEMODES;
01749         (void) headerGet(h, FMhe, 0);
01750         break;
01751 #endif
01752     case RPMTAG_REQUIREYAMLENTRY:
01753     case RPMTAG_REQUIRENAME:
01754         /* The Requires: F is needed to filter install context dependencies. */
01755         Fhe->tag = RPMTAG_REQUIREFLAGS;
01756         (void) headerGet(h, Fhe, 0);
01757         break;
01758     }
01759 
01760     switch (he->t) {
01761     default:
01762 assert(0);
01763         /*@notreached@*/ break;
01764     case RPM_UINT8_TYPE:        /* XXX coerce to uint32_t */
01765     {   uint8_t * _u = he->p.ui8p;
01766         he->p.ui32p = xmalloc(he->c * sizeof(*he->p.ui32p));
01767         for (i = 0; i < he->c; i++)
01768             he->p.ui32p[i] = _u[i];
01769         _u = _free(_u);
01770         goto _ifill;
01771     }   /*@notreached@*/ break;
01772     case RPM_UINT16_TYPE:       /* XXX coerce to uint32_t */
01773     {   uint16_t * _u = he->p.ui16p;
01774         he->p.ui32p = xmalloc(he->c * sizeof(*he->p.ui32p));
01775         for (i = 0; i < he->c; i++)
01776             he->p.ui32p[i] = _u[i];
01777         _u = _free(_u);
01778         goto _ifill;
01779     }   /*@notreached@*/ break;
01780     case RPM_UINT32_TYPE:
01781 _ifill:
01782     {   uint32_t * _u = he->p.ui32p;
01783         size_t _ulen = sizeof(*_u);
01784         uint32_t _ube;                  /* XXX network order integer keys */
01785 
01786         /* Drop the transaction id usecs field (if present) when indexing. */
01787         switch (he->tag) {
01788         case RPMTAG_INSTALLTID:
01789         case RPMTAG_REMOVETID:
01790             he->c = 1;
01791             /*@innerbreak@*/ break;
01792         default:
01793             /*@innerbreak@*/ break;
01794         }
01795         if (he->c == 1) {
01796             _ube = _hton_ui(*_u);       /* XXX network order integer keys */
01797             /* XXX is it worth avoiding the realloc here? */
01798             xx = loadDBT(_r, he->tag, &_ube, _ulen);
01799             break;
01800         }
01801         _r->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC;
01802         _r->data = A = xcalloc(he->c, sizeof(*A));
01803         _r->size = 0;
01804         if (he->c > 1)
01805             qsort(_u, he->c, _ulen, uint32Cmp);
01806         for (i = 0; i < he->c; i++, _u++) {
01807             /* Don't add identical (key,val) item to secondary. */
01808             if (i > 0 && _u[-1] == _u[0])
01809                 continue;
01810             _ube = _hton_ui(*_u);       /* XXX network order integer keys */
01811             if (!loadDBT(A, he->tag, &_ube, _ulen))
01812                 continue;
01813             A++;
01814             _r->size++;
01815         }
01816     }   break;
01817     case RPM_UINT64_TYPE:
01818     {   uint64_t * _u = he->p.ui64p;
01819         size_t _ulen = sizeof(*_u);
01820         uint64_t _ube;                  /* XXX network order integer keys */
01821 
01822         if (he->c == 1) {
01823             _ube = _hton_ul(*_u);       /* XXX network order integer keys */
01824             /* XXX is it worth avoiding the realloc here? */
01825             xx = loadDBT(_r, he->tag, _u, _ulen);
01826             break;
01827         }
01828         _r->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC;
01829         _r->data = A = xcalloc(he->c, sizeof(*A));
01830         _r->size = 0;
01831         if (he->c > 1)
01832             qsort(_u, he->c, _ulen, uint64Cmp);
01833         for (i = 0; i < he->c; i++, _u++) {
01834             /* Don't add identical (key,val) item to secondary. */
01835             if (i > 0 && _u[-1] == _u[0])
01836                 continue;
01837             _ube = _hton_ul(*_u);       /* XXX network order integer keys */
01838             if (!loadDBT(A, he->tag, &_ube, _ulen))
01839                 continue;
01840             A++;
01841             _r->size++;
01842         }
01843     }   break;
01844     case RPM_BIN_TYPE:
01845         s = he->p.ptr; ns = he->c;
01846         /* XXX is it worth avoiding the realloc here? */
01847         if (ns > 0)                     /* No "" empty keys please. */
01848             xx = loadDBT(_r, he->tag, s, ns);
01849         break;
01850     case RPM_I18NSTRING_TYPE:           /* XXX never occurs */
01851     case RPM_STRING_TYPE:
01852         s = he->p.str; ns = strlen(s);
01853         /* XXX is it worth avoiding the realloc here? */
01854         if (ns > 0)                     /* No "" empty keys please. */
01855             xx = loadDBT(_r, he->tag, s, ns);
01856         break;
01857     case RPM_STRING_ARRAY_TYPE:
01858         if (he->c == 1) {
01859             s = he->p.argv[0]; ns = strlen(s);
01860             if (ns > 0)                 /* No "" empty keys please. */
01861                 xx = loadDBT(_r, he->tag, s, ns);
01862         } else {
01863             static double e = 1.0e-4;
01864             size_t m = 0;
01865             size_t k = 0;
01866             rpmbf bf;
01867             rpmbfParams(he->c, e, &m, &k);
01868             bf = rpmbfNew(m, k, 0);
01869 
01870             _r->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC;
01871             _r->data = A = xcalloc(he->c, sizeof(*A));
01872             _r->size = 0;
01873             for (i = 0; i < he->c; i++) {
01874                 s = he->p.argv[i]; ns = strlen(s);
01875 
01876                 /* XXX Skip YAML "- ..." lead-in mark up if present. */
01877                 if (s[0] == '-' && s[1] == ' ') {
01878                     s += 2, ns -= 2;
01879                 }
01880 
01881 #ifdef  NOTYET
01882                 /* Add the pesky trailing '/' to directories. */
01883                 if (FMhe->p.ui16p && !S_ISREG((mode_t)FMhe->p.ui16p[i])) {
01884                     continue;
01885                 }
01886 #endif
01887 
01888                 if (ns == 0)            /* No "" empty keys please. */
01889                     continue;
01890 
01891                 /* Filter install context dependencies. */
01892                 if (Fhe->p.ui32p && isInstallPreReq(Fhe->p.ui32p[i]))
01893                     continue;
01894 
01895                 /* Don't add identical (key,val) item to secondary. */
01896                 if (rpmbfChk(bf, s, ns) > 0)
01897                     continue;
01898                 xx = rpmbfAdd(bf, s, ns);
01899 assert(xx == 0);
01900 
01901                 if (!loadDBT(A, he->tag, s, ns))
01902                     continue;
01903                 A++;
01904                 _r->size++;
01905             }
01906             bf = rpmbfFree(bf);
01907         }
01908         break;
01909     }
01910     if (_r->data && _r->size > 0)
01911         rc = 0;
01912     else if (_r->flags & DB_DBT_APPMALLOC) {
01913         _r->data = _free(_r->data);
01914         memset(_r, 0, sizeof(*_r));
01915     }
01916 
01917 exit:
01918     if (!dbi->dbi_no_dbsync && rc != DB_DONOTINDEX)
01919         xx = dbiSync(dbi, 0);
01920 #ifdef  NOTYET
01921     FMhe->p.ptr = _free(FMhe->p.ptr);
01922 #endif
01923     Fhe->p.ptr = _free(Fhe->p.ptr);
01924     he->p.ptr = _free(he->p.ptr);
01925     h = headerFree(h);
01926 
01927 DBIDEBUG(dbi, (stderr, "<-- %s(%p, %p, %p, %p) rc %d\n\tdbi %p(%s) rpmdb %p h %p %s\n", __FUNCTION__, db, key, data, _r, rc, dbi, tagName(dbi->dbi_rpmtag), rpmdb, h, _KEYDATA(key, NULL, data, _r)));
01928 
01929     return rc;
01930 }
01931 
01932 static int seqid_init(dbiIndex dbi, const char * keyp, size_t keylen,
01933                 DB_SEQUENCE ** seqp)
01934         /*@modifies *seqp @*/
01935 {
01936     DB * db = dbi->dbi_db;
01937     DBT k = {0};
01938     DB_TXN * _txnid = dbiTxnid(dbi);
01939     DB_SEQUENCE * seq = NULL;
01940     db_seq_t _rangemin = -922337203685477600LL;
01941     db_seq_t _rangemax =  922337203685477600LL;
01942     db_seq_t _value = 0;
01943     int32_t _cachesize = 0;
01944     uint32_t _flags = DB_SEQ_INC;
01945     uint32_t _oflags = DB_CREATE;
01946     int rc;
01947 
01948 assert(db != NULL);
01949     if (seqp) *seqp = NULL;
01950 
01951 /*@-moduncon@*/
01952     rc = db_sequence_create(&seq, db, 0);
01953 /*@=moduncon@*/
01954     rc = cvtdberr(dbi, "db_sequence_create", rc, _debug);
01955     if (rc) goto exit;
01956 assert(seq != NULL);
01957 
01958     if (dbi->dbi_seq_cachesize) {
01959         _cachesize = dbi->dbi_seq_cachesize;
01960         rc = seq->set_cachesize(seq, _cachesize);
01961         rc = cvtdberr(dbi, "seq->set_cachesize", rc, _debug);
01962         if (rc) goto exit;
01963     }
01964 
01965     if (dbi->dbi_seq_initial)
01966         _value = dbi->dbi_seq_initial;
01967     if (_value <= 0) _value = 1;
01968     rc = seq->initial_value(seq, _value);
01969     rc = cvtdberr(dbi, "seq->initial_value", rc, _debug);
01970     if (rc) goto exit;
01971 
01972     if (dbi->dbi_seq_min)
01973         _rangemin = dbi->dbi_seq_min;
01974     if (dbi->dbi_seq_max)
01975         _rangemax = dbi->dbi_seq_max;
01976     rc = seq->set_range(seq, _rangemin, _rangemax);
01977     rc = cvtdberr(dbi, "seq->set_range", rc, _debug);
01978     if (rc) goto exit;
01979 
01980     if (dbi->dbi_seq_flags)
01981         _flags = dbi->dbi_seq_flags;
01982     rc = seq->set_flags(seq, _flags);
01983     rc = cvtdberr(dbi, "seq->set_flags", rc, _debug);
01984     if (rc) goto exit;
01985 
01986     k.data = (void *)keyp;
01987     k.size = (u_int32_t) (keylen > 0 ? keylen : strlen(keyp));
01988     rc = seq->open(seq, _txnid, &k, _oflags);
01989     rc = cvtdberr(dbi, "seq->open", rc, _debug);
01990     if (rc) goto exit;
01991 
01992 exit:
01993     if (rc == 0 && seqp != NULL)
01994         *seqp = seq;
01995     else {
01996         int xx = seq->close(seq, 0);  
01997         xx = cvtdberr(dbi, "seq->close", xx, _debug);
01998     }
01999 
02000 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p[%u],%p) seq %p rc %d %s\n", __FUNCTION__, dbi, keyp, (unsigned)keylen, seqp, (seqp ? *seqp : NULL), rc, _KEYDATA(&k, NULL, NULL, NULL)));
02001 
02002     return rc;
02003 }
02004 
02012 static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip)
02013         /*@globals rpmGlobalMacroContext, h_errno,
02014                 fileSystem, internalState @*/
02015         /*@modifies *dbip, fileSystem, internalState @*/
02016 {
02017     /*@-nestedextern -shadow@*/
02018     extern struct _dbiVec db3vec;
02019     /*@=nestedextern =shadow@*/
02020     const char * urlfn = NULL;
02021     const char * root;
02022     const char * home;
02023     const char * dbhome;
02024     const char * dbfile;
02025     const char * dbsubfile;
02026     const char * dbiBN;
02027     dbiIndex dbi = NULL;
02028     int rc = 0;
02029     int xx;
02030 
02031     DB * db = NULL;
02032     DB_ENV * dbenv = NULL;
02033     DB_TXN * _txnid = NULL;
02034     DBTYPE dbi_type = DB_UNKNOWN;
02035     rpmuint32_t oflags;
02036     int _printit;
02037 
02038     if (dbip)
02039         *dbip = NULL;
02040 
02041     /*
02042      * Parse db configuration parameters.
02043      */
02044     /*@-mods@*/
02045     if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
02046         /*@-nullstate@*/
02047         return 1;
02048         /*@=nullstate@*/
02049     /*@=mods@*/
02050     dbi->dbi_api = DB_VERSION_MAJOR;
02051     dbiBN = mapTagName(rpmdb, dbi);
02052     dbi->dbi_txnid = NULL;
02053     _txnid = NULL;
02054 
02055     /*
02056      * Get the prefix/root component and directory path.
02057      */
02058     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
02059     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
02060         root = NULL;
02061     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
02062 
02063     /*
02064      * Either the root or directory components may be a URL. Concatenate,
02065      * convert the URL to a path, and add the name of the file.
02066      */
02067     /*@-mods@*/
02068     urlfn = rpmGenPath(root, home, NULL);
02069     /*@=mods@*/
02070     (void) urlPath(urlfn, &dbhome);
02071     if (dbi->dbi_temporary) {
02072         dbfile = NULL;
02073         dbsubfile = NULL;
02074     } else {
02075 #ifdef  HACK    /* XXX necessary to support dbsubfile */
02076         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
02077         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : dbiBN);
02078 #else
02079         dbfile = (dbi->dbi_file ? dbi->dbi_file : dbiBN);
02080         dbsubfile = NULL;
02081 #endif
02082     }
02083 
02084     oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
02085     /* XXX permit DB_TRUNCATE iff a secondary index. */
02086     if (dbi->dbi_primary) oflags &= ~DB_TRUNCATE;
02087 
02088 #if 0   /* XXX rpmdb: illegal flag combination specified to DB->open */
02089     if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
02090 #endif
02091 
02092     /*
02093      * Map open mode flags onto configured database/environment flags.
02094      */
02095     if (dbi->dbi_temporary) {
02096         oflags |= DB_CREATE;
02097         dbi->dbi_oeflags |= DB_CREATE;
02098         oflags &= ~DB_RDONLY;
02099         dbi->dbi_oflags &= ~DB_RDONLY;
02100     } else {
02101         if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
02102         if (dbi->dbi_mode & O_CREAT) {
02103             oflags |= DB_CREATE;
02104             dbi->dbi_oeflags |= DB_CREATE;
02105         }
02106         /* XXX permit DB_TRUNCATE iff a secondary index. */
02107         if (dbi->dbi_primary && (dbi->dbi_mode & O_TRUNC))
02108             oflags |= DB_TRUNCATE;
02109     }
02110 
02111     /*
02112      * Create the /var/lib/rpm directory if it doesn't exist (root only).
02113      */
02114     (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
02115 
02116     /*
02117      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open.
02118      */
02119     if (dbi->dbi_use_dbenv) {
02120 
02121         if (access(dbhome, W_OK) == -1) {
02122 
02123             /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */
02124             oflags &= ~DB_CREATE;
02125             oflags &= ~DB_AUTO_COMMIT;
02126 
02127             /* ... but DBENV->open might still need DB_CREATE ... */
02128             if (dbi->dbi_eflags & DB_PRIVATE) {
02129                 dbi->dbi_eflags &= ~DB_JOINENV;
02130             } else {
02131                 dbi->dbi_eflags |= DB_JOINENV;
02132                 dbi->dbi_oeflags &= ~DB_CREATE;
02133 #ifdef  DYING
02134                 dbi->dbi_oeflags &= ~DB_THREAD;
02135 #endif
02136                 /* ... but, unless DB_PRIVATE is used, skip DBENV. */
02137                 dbi->dbi_use_dbenv = 0;
02138             }
02139 
02140             /* ... DB_RDONLY maps dbhome perms across files ...  */
02141             if (dbi->dbi_temporary) {
02142                 oflags |= DB_CREATE;
02143                 dbi->dbi_oeflags |= DB_CREATE;
02144                 oflags &= ~DB_RDONLY;
02145                 dbi->dbi_oflags &= ~DB_RDONLY;
02146             } else {
02147                 oflags |= DB_RDONLY;
02148                 /* ... and DB_WRITECURSOR won't be needed ...  */
02149                 dbi->dbi_oflags |= DB_RDONLY;
02150             }
02151 
02152         } else {        /* dbhome is writable, check for persistent dbenv. */
02153             /*@-mods@*/
02154             const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
02155             /*@=mods@*/
02156 
02157 #if defined(RPM_VENDOR_OPENPKG) /* bdb-allow-zero-sized-files */
02158             /* Make sure RPM passes DB_CREATE to Berkeley-DB also
02159                if file exists, but is (still) zero-sized. */
02160             struct stat sb;
02161             long size = -1;
02162             if (stat(dbf, &sb) == 0)
02163                 size = (long)sb.st_size;
02164             if (access(dbf, F_OK) == -1 || size == 0)
02165 #else
02166             if (access(dbf, F_OK) == -1)
02167 #endif
02168             {
02169                 /* ... non-existent (or unwritable) DBENV, will create ... */
02170                 dbi->dbi_oeflags |= DB_CREATE;
02171                 dbi->dbi_eflags &= ~DB_JOINENV;
02172             } else {
02173                 /* ... pre-existent (or bogus) DBENV, will join ... */
02174                 if (dbi->dbi_eflags & DB_PRIVATE) {
02175                     dbi->dbi_eflags &= ~DB_JOINENV;
02176                 } else {
02177                     dbi->dbi_eflags |= DB_JOINENV;
02178                     dbi->dbi_oeflags &= ~DB_CREATE;
02179 #ifdef  DYING
02180                     dbi->dbi_oeflags &= ~DB_THREAD;
02181 #endif
02182                 }
02183             }
02184             /* ... transactionally protected open's need DB_AUTO_COMMIT ... */
02185             if (rpmdb->_dbi[0]
02186              && rpmdb->_dbi[0]->dbi_eflags & DB_INIT_TXN)
02187                 oflags |= DB_AUTO_COMMIT;
02188             dbf = _free(dbf);
02189         }
02190     }
02191 
02192     /*
02193      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open.
02194      */
02195     if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
02196         /* dbhome is writable, and DB->open flags may conflict. */
02197         const char * dbfn = (dbfile ? dbfile : dbiBN);
02198         /*@-mods@*/
02199         const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
02200         /*@=mods@*/
02201 
02202         if (access(dbf, F_OK) == -1) {
02203             /* File does not exist, DB->open might create ... */
02204             oflags &= ~DB_RDONLY;
02205         } else {
02206             /* File exists, DB->open need not create ... */
02207             oflags &= ~DB_CREATE;
02208         }
02209 
02210         /* Only writers need DB_WRITECURSOR ... */
02211         if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
02212             dbi->dbi_oflags &= ~DB_RDONLY;
02213         } else {
02214             dbi->dbi_oflags |= DB_RDONLY;
02215         }
02216         dbf = _free(dbf);
02217     }
02218 
02219     /*
02220      * Set db type if creating or truncating.
02221      */
02222     if (oflags & (DB_CREATE|DB_TRUNCATE))
02223         dbi_type = dbi->dbi_type;
02224 
02225     if (dbi->dbi_use_dbenv) {
02226         /*@-mods@*/
02227         if (rpmdb->db_dbenv == NULL) {
02228             rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
02229             switch (rc) {
02230             default:
02231                 break;
02232             case DB_RUNRECOVERY:
02233                 if (getuid() != 0)
02234                     break;
02235                 rpmlog(RPMLOG_NOTICE, _("Re-opening dbenv with DB_RECOVER ...\n"));
02236                 /* XXX Attempt db_recover -ev (i.e. dbenv w DB_INIT_LOCK) */
02237                 dbi->dbi_eflags |= DB_RECOVER;
02238                 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
02239                 dbi->dbi_eflags &= ~DB_RECOVER;
02240                 if (rc) {
02241                     rpmlog(RPMLOG_NOTICE, _("\nrecovery failed. Exiting ...\n"));
02242                     exit(EXIT_FAILURE);
02243                 }
02244                 rpmlog(RPMLOG_NOTICE, _(".\nrecovery succeeded.\n"));
02245 assert(dbenv);
02246                 rpmdb->db_dbenv = dbenv;
02247                 rpmdb->db_opens = 1;
02248                 break;
02249 
02250 #if defined(DB_VERSION_MISMATCH) /* Nuke __db* files and retry open once. */
02251             case DB_VERSION_MISMATCH:
02252 #endif
02253             case EINVAL:
02254                 if (getuid() != 0)
02255                     break;
02256                 {   char * filename = alloca(BUFSIZ);
02257                     struct stat st;
02258                     int i;
02259 
02260                     for (i = 0; i < 16; i++) {
02261                         sprintf(filename, "%s/__db.%03d", dbhome, i);
02262                         (void)rpmCleanPath(filename);
02263                         if (Stat(filename, &st)
02264                           && (errno == ENOENT || errno == EINVAL))
02265                             continue;
02266                         xx = Unlink(filename);
02267                     }
02268                 }
02269                 dbi->dbi_oeflags |= DB_CREATE;
02270                 dbi->dbi_eflags &= ~DB_JOINENV;
02271                 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
02272                 /* XXX db_init EINVAL was masked. */
02273                 rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
02274                 if (rc)
02275                     break;
02276                 /*@fallthrough@*/
02277             case 0:
02278 assert(dbenv);
02279                 rpmdb->db_dbenv = dbenv;
02280                 rpmdb->db_opens = 1;
02281                 break;
02282             }
02283         } else {
02284 assert(rpmdb && rpmdb->db_dbenv);
02285             dbenv = rpmdb->db_dbenv;
02286             rpmdb->db_opens++;
02287         }
02288         /*@=mods@*/
02289     }
02290 
02291     rpmlog(RPMLOG_DEBUG, D_("opening  db index       %s/%s %s mode=0x%x\n"),
02292                 dbhome, (dbfile ? dbfile : dbiBN),
02293                 prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
02294 
02295     if (rc == 0) {
02296         static int _lockdbfd = 0;
02297 
02298         /*@-moduncon@*/ /* FIX: annotate db3 methods */
02299         rc = db_create(&db, dbenv, dbi->dbi_cflags);
02300         /*@=moduncon@*/
02301         rc = cvtdberr(dbi, "db_create", rc, _debug);
02302         if (rc == 0 && db != NULL) {
02303 
02304 /* XXX 3.3.4 change. */
02305             if (rc == 0 &&
02306                         rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
02307             {
02308                 rc = db->set_alloc(db,
02309                         rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
02310                 rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
02311             }
02312 
02313 /* 4.1: db->set_cache_priority(???) */
02314 /* 4.1: db->set_encrypt(???) */
02315 
02316             if (rc == 0 && dbi->dbi_lorder) {
02317                 rc = db->set_lorder(db, dbi->dbi_lorder);
02318                 rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
02319             }
02320             if (rc == 0 && dbi->dbi_pagesize) {
02321                 rc = db->set_pagesize(db, dbi->dbi_pagesize);
02322                 rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
02323             }
02324  /* 4.1: db->set_paniccall(???) */
02325             if (rc == 0 && oflags & DB_CREATE) {
02326                 switch(dbi->dbi_type) {
02327                 default:
02328                 case DB_HASH:
02329                     if (dbi->dbi_h_ffactor) {
02330                         rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor);
02331                         rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug);
02332                         if (rc) break;
02333                     }
02334                     if (dbi->dbi_h_nelem) {
02335                         rc = db->set_h_nelem(db, dbi->dbi_h_nelem);
02336                         rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug);
02337                         if (rc) break;
02338                     }
02339                     if (dbi->dbi_h_flags) {
02340                         rc = db->set_flags(db, dbi->dbi_h_flags);
02341                         rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug);
02342                         if (rc) break;
02343                     }
02344                     if (dbi->dbi_h_hash_fcn) {
02345                         rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn);
02346                         rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug);
02347                         if (rc) break;
02348                     }
02349                     if (dbi->dbi_h_dup_compare_fcn) {
02350                         rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn);
02351                         rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
02352                         if (rc) break;
02353                     }
02354                     break;
02355                 case DB_BTREE:
02356 /* 4.1: db->set_append_recno(???) */
02357                     if (dbi->dbi_bt_flags) {
02358                         rc = db->set_flags(db, dbi->dbi_bt_flags);
02359                         rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
02360                         if (rc) break;
02361                     }
02362                     if (dbi->dbi_bt_minkey) {
02363                         rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey);
02364                         rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug);
02365                         if (rc) break;
02366                     }
02367                     if (dbi->dbi_bt_compare_fcn) {
02368                         rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn);
02369                         rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug);
02370                         if (rc) break;
02371                     }
02372                     if (dbi->dbi_bt_dup_compare_fcn) {
02373                         rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn);
02374                         rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
02375                         if (rc) break;
02376                     }
02377                     if (dbi->dbi_bt_prefix_fcn) {
02378                         rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn);
02379                         rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug);
02380                         if (rc) break;
02381                     }
02382                     break;
02383                 case DB_RECNO:
02384 /* 4.1: db->set_append_recno(???) */
02385                     if (dbi->dbi_re_delim) {
02386                         rc = db->set_re_delim(db, dbi->dbi_re_delim);
02387                         rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
02388                         if (rc) break;
02389                     }
02390                     if (dbi->dbi_re_len) {
02391                         rc = db->set_re_len(db, dbi->dbi_re_len);
02392                         rc = cvtdberr(dbi, "db->set_re_len", rc, _debug);
02393                         if (rc) break;
02394                     }
02395                     if (dbi->dbi_re_pad) {
02396                         rc = db->set_re_pad(db, dbi->dbi_re_pad);
02397                         rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug);
02398                         if (rc) break;
02399                     }
02400                     if (dbi->dbi_re_source) {
02401                         rc = db->set_re_source(db, dbi->dbi_re_source);
02402                         rc = cvtdberr(dbi, "db->set_re_source", rc, _debug);
02403                         if (rc) break;
02404                     }
02405                     break;
02406                 case DB_QUEUE:
02407                     if (dbi->dbi_q_extentsize) {
02408                         rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize);
02409                         rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug);
02410                         if (rc) break;
02411                     }
02412                     break;
02413                 }
02414             }
02415 
02416             if (rc == 0) {
02417                 const char * dbfullpath;
02418                 const char * dbpath;
02419                 char * t;
02420                 int nb;
02421 
02422                 nb = strlen(dbhome);
02423                 if (dbfile)     nb += 1 + strlen(dbfile);
02424                 dbfullpath = t = alloca(nb + 1);
02425 
02426                 t = stpcpy(t, dbhome);
02427                 if (dbfile)
02428                     t = stpcpy( stpcpy( t, "/"), dbfile);
02429 #ifdef  HACK    /* XXX necessary to support dbsubfile */
02430                 dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
02431                         ? dbfullpath : dbfile;
02432 #else
02433 #ifdef  PLD_CHROOT
02434                 /* XXX Make dbpath relative. */
02435                 dbpath = (!dbi->dbi_use_dbenv)
02436                         ? dbfullpath : dbfile;
02437 #else
02438                 dbpath = (!dbi->dbi_temporary)
02439                         ? dbfullpath : dbfile;
02440 #endif  /* PLD_CHROOT */
02441 #endif  /* HACK */
02442 
02443                 rc = (db->open)(db, _txnid, dbpath, dbsubfile,
02444                     dbi_type, oflags, dbi->dbi_perms);
02445 
02446                 if (rc == 0 && dbi_type == DB_UNKNOWN) {
02447                     xx = db->get_type(db, &dbi_type);
02448                     if (xx == 0)
02449                         dbi->dbi_type = dbi_type;
02450                 }
02451             }
02452 
02453             /* XXX return rc == errno without printing */
02454             _printit = (rc > 0 ? 0 : _debug);
02455             xx = cvtdberr(dbi, "db->open", rc, _printit);
02456 
02457             /*
02458              * Lock a file using fcntl(2). Traditionally this is Packages,
02459              * the file used to store metadata of installed header(s),
02460              * as Packages is always opened, and should be opened first,
02461              * for any rpmdb access.
02462              *
02463              * If no DBENV is used, then access is protected with a
02464              * shared/exclusive locking scheme, as always.
02465              *
02466              * With a DBENV, the fcntl(2) lock is necessary only to keep
02467              * the riff-raff from playing where they don't belong, as
02468              * the DBENV should provide it's own locking scheme. So try to
02469              * acquire a lock, but permit failures, as some other
02470              * DBENV player may already have acquired the lock.
02471              *
02472              * With NPTL posix mutexes, revert to fcntl lock on non-functioning
02473              * glibc/kernel combinations.
02474              */
02475             if (rc == 0 && dbi->dbi_lockdbfd &&
02476 #if defined(DB_RPCCLIENT)
02477                 !((dbi->dbi_ecflags & DB_RPCCLIENT) && dbi->dbi_host) &&
02478 #endif
02479                 (!dbi->dbi_use_dbenv || _lockdbfd++ == 0))
02480             {
02481                 int fdno = -1;
02482 
02483                 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
02484                     rc = 1;
02485                 } else {
02486                     struct flock l;
02487                     memset(&l, 0, sizeof(l));
02488                     l.l_whence = 0;
02489                     l.l_start = 0;
02490                     l.l_len = 0;
02491                     l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY))
02492                                 ? F_WRLCK : F_RDLCK;
02493                     l.l_pid = 0;
02494 
02495                     rc = fcntl(fdno, F_SETLK, (void *) &l);
02496                     if (rc) {
02497                         /* Warning iff using non-private CDB locking. */
02498                         rc = ((dbi->dbi_use_dbenv &&
02499                                 (dbi->dbi_eflags & DB_INIT_CDB) &&
02500                                 !(dbi->dbi_eflags & DB_PRIVATE))
02501                             ? 0 : 1);
02502                         rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING),
02503                                 _("cannot get %s lock on %s/%s\n"),
02504                                 ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
02505                                         ? _("exclusive") : _("shared")),
02506                                 dbhome, (dbfile ? dbfile : ""));
02507                     } else if (dbfile) {
02508                         rpmlog(RPMLOG_DEBUG,
02509                                 D_("locked   db index       %s/%s\n"),
02510                                 dbhome, dbfile);
02511                     }
02512                 }
02513             }
02514         }
02515     }
02516 
02517     dbi->dbi_db = db;
02518     if (db)
02519         db->app_private = dbi;
02520 
02521 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%p) dbi %p rc %d %s\n", __FUNCTION__, rpmdb, tagName(rpmtag), dbip, dbi, rc, _OFLAGS(dbi->dbi_oflags)));
02522 
02523     if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
02524         dbi->dbi_vec = &db3vec;
02525         *dbip = dbi;
02526         if (dbi->dbi_primary) {
02527             rpmTag Ptag = tagValue(dbi->dbi_primary);
02528             dbiIndex Pdbi = NULL;
02529             int (*_callback)(DB *, const DBT *, const DBT *, DBT *)
02530                         = db3Acallback;
02531 #ifdef  NOTYET  /* XXX KISS for now */
02532             int _flags = DB_IMMUTABLE_KEY;
02533 #else
02534             int _flags = 0;
02535 #endif
02536 assert(Ptag == RPMDBI_PACKAGES && Ptag != rpmtag);
02537             Pdbi = dbiOpen(rpmdb, Ptag, 0);
02538 assert(Pdbi != NULL);
02539             if (oflags & (DB_CREATE|DB_TRUNCATE)) _flags |= DB_CREATE;
02540             xx = db3associate(Pdbi, dbi, _callback, _flags);
02541         }
02542         if (dbi->dbi_seq_id) {
02543             char * end = NULL;
02544             uint32_t u = (uint32_t) strtoll(dbi->dbi_seq_id, &end, 0);
02545 
02546             /* Reset the Seqno counter to the next primary key */
02547             if (oflags & (DB_CREATE|DB_TRUNCATE))
02548                 dbi->dbi_seq_initial = rpmdb->db_maxkey + 1;
02549 
02550             if (*end == '\0')
02551                 xx = seqid_init(dbi,(const char *)&u, sizeof(u), &dbi->dbi_seq);
02552             else
02553                 xx = seqid_init(dbi, dbi->dbi_seq_id, 0, &dbi->dbi_seq);
02554             if (xx) {
02555                 (void) db3close(dbi, 0);
02556                 dbi = NULL;
02557                 if (dbip) *dbip = dbi;
02558             }
02559         }
02560     } else {
02561         (void) db3close(dbi, 0);
02562         dbi = NULL;
02563         if (dbip) *dbip = dbi;
02564     }
02565 
02566     urlfn = _free(urlfn);
02567 
02568     /*@-nullstate -compmempass@*/
02569     return rc;
02570     /*@=nullstate =compmempass@*/
02571 }
02572 
02575 /*@-exportheadervar@*/
02576 /*@observer@*/ /*@unchecked@*/
02577 struct _dbiVec db3vec = {
02578     DB_VERSION_STRING, DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
02579     db3open, db3close, db3sync, db3associate, db3associate_foreign, db3join,
02580     db3exists, db3seqno,
02581     db3copen, db3cclose, db3cdup, db3cdel, db3cget, db3cpget, db3cput, db3ccount,
02582     db3byteswapped, db3stat
02583 };
02584 /*@=exportheadervar@*/
02585 /*@=type@*/