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