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