Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

env_open.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: env_open.c,v 12.36 2005/10/31 02:22:28 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <ctype.h>
00016 #include <limits.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #endif
00020 
00021 #include "db_int.h"
00022 #include "dbinc/crypto.h"
00023 #include "dbinc/db_page.h"
00024 #include "dbinc/db_shash.h"
00025 #include "dbinc/btree.h"
00026 #include "dbinc/hash.h"
00027 #include "dbinc/fop.h"
00028 #include "dbinc/lock.h"
00029 #include "dbinc/log.h"
00030 #include "dbinc/mp.h"
00031 #include "dbinc/qam.h"
00032 #include "dbinc/txn.h"
00033 
00034 static int __db_parse __P((DB_ENV *, char *));
00035 static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, DB_FH **));
00036 static int __env_config __P((DB_ENV *, const char *, u_int32_t));
00037 static int __env_refresh __P((DB_ENV *, u_int32_t, int));
00038 static int __env_remove_int __P((DB_ENV *, const char *, u_int32_t));
00039 
00040 /*
00041  * db_version --
00042  *      Return version information.
00043  *
00044  * EXTERN: char *db_version __P((int *, int *, int *));
00045  */
00046 char *
00047 db_version(majverp, minverp, patchp)
00048         int *majverp, *minverp, *patchp;
00049 {
00050         if (majverp != NULL)
00051                 *majverp = DB_VERSION_MAJOR;
00052         if (minverp != NULL)
00053                 *minverp = DB_VERSION_MINOR;
00054         if (patchp != NULL)
00055                 *patchp = DB_VERSION_PATCH;
00056         return ((char *)DB_VERSION_STRING);
00057 }
00058 
00059 /*
00060  * __env_open_pp --
00061  *      DB_ENV->open pre/post processing.
00062  *
00063  * PUBLIC: int __env_open_pp __P((DB_ENV *, const char *, u_int32_t, int));
00064  */
00065 int
00066 __env_open_pp(dbenv, db_home, flags, mode)
00067         DB_ENV *dbenv;
00068         const char *db_home;
00069         u_int32_t flags;
00070         int mode;
00071 {
00072         DB_THREAD_INFO *ip;
00073         u_int32_t orig_flags;
00074         int need_recovery, ret, t_ret;
00075 
00076         need_recovery = 0;
00077 
00078 #undef  OKFLAGS
00079 #define OKFLAGS                                                         \
00080         (DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG |         \
00081         DB_INIT_MPOOL | DB_INIT_REP | DB_INIT_TXN | DB_LOCKDOWN |       \
00082         DB_PRIVATE | DB_RECOVER | DB_RECOVER_FATAL | DB_REGISTER |      \
00083         DB_SYSTEM_MEM | DB_THREAD | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT)
00084 #undef  OKFLAGS_CDB
00085 #define OKFLAGS_CDB                                                     \
00086         (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_LOCKDOWN |        \
00087         DB_PRIVATE | DB_SYSTEM_MEM | DB_THREAD |                        \
00088         DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT)
00089 
00090         if ((ret = __db_fchk(dbenv, "DB_ENV->open", flags, OKFLAGS)) != 0)
00091                 return (ret);
00092         if ((ret = __db_fcchk(
00093             dbenv, "DB_ENV->open", flags, DB_INIT_CDB, ~OKFLAGS_CDB)) != 0)
00094                 return (ret);
00095         if ((ret = __db_fcchk(dbenv, "DB_ENV->open", flags,
00096             DB_PRIVATE, DB_REGISTER | DB_SYSTEM_MEM)) != 0)
00097                 return (ret);
00098         if (LF_ISSET(DB_INIT_REP)) {
00099                 if (!LF_ISSET(DB_INIT_LOCK)) {
00100                         __db_err(dbenv, "replication requires locking support");
00101                         return (EINVAL);
00102                 }
00103                 if (!LF_ISSET(DB_INIT_TXN)) {
00104                         __db_err(
00105                             dbenv, "replication requires transaction support");
00106                         return (EINVAL);
00107                 }
00108         }
00109         if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) {
00110                 if ((ret = __db_fcchk(dbenv,
00111                     "DB_ENV->open", flags, DB_RECOVER, DB_RECOVER_FATAL)) != 0)
00112                         return (ret);
00113                 if (!LF_ISSET(DB_CREATE)) {
00114                         __db_err(dbenv, "recovery requires the create flag");
00115                         return (EINVAL);
00116                 }
00117                 if (!LF_ISSET(DB_INIT_TXN)) {
00118                         __db_err(
00119                             dbenv, "recovery requires transaction support");
00120                         return (EINVAL);
00121                 }
00122         }
00123 
00124         /*
00125          * Currently we support one kind of mutex that is intra-process only,
00126          * POSIX 1003.1 pthreads, because a variety of systems don't support
00127          * the full pthreads API, and our only alternative is test-and-set.
00128          */
00129 #ifdef HAVE_MUTEX_THREAD_ONLY
00130         if (!LF_ISSET(DB_PRIVATE)) {
00131                 __db_err(dbenv,
00132          "Berkeley DB library configured to support only private environments");
00133                 return (EINVAL);
00134         }
00135 #endif
00136 
00137 #if defined(HAVE_MUTEX_FCNTL)
00138         /*
00139          * !!!
00140          * We need a file descriptor for fcntl(2) locking.  We use the file
00141          * handle from the REGENV file for this purpose.
00142          *
00143          * Since we may be using shared memory regions, e.g., shmget(2), and
00144          * not a mapped-in regular file, the backing file may be only a few
00145          * bytes in length.  So, this depends on the ability to call fcntl to
00146          * lock file offsets much larger than the actual physical file.  I
00147          * think that's safe -- besides, very few systems actually need this
00148          * kind of support, SunOS is the only one still in wide use of which
00149          * I'm aware.
00150          *
00151          * The error case is if an application lacks spinlocks and wants to be
00152          * threaded.  That doesn't work because fcntl will lock the underlying
00153          * process, including all its threads.
00154          */
00155         if (F_ISSET(dbenv, DB_ENV_THREAD)) {
00156                 __db_err(dbenv,
00157             "architecture lacks fast mutexes: applications cannot be threaded");
00158                 return (EINVAL);
00159         }
00160 #endif
00161 
00162         if (LF_ISSET(DB_INIT_REP) && !__os_support_replication()) {
00163                 __db_err(dbenv,
00164              "Berkeley DB library does not support replication on this system");
00165                 return (EINVAL);
00166         }
00167 
00168         /*
00169          * If we're going to register with the environment, that's the first
00170          * thing we do.
00171          */
00172         if (LF_ISSET(DB_REGISTER)) {
00173                 if (!__os_support_db_register()) {
00174                         __db_err(dbenv,
00175              "Berkeley DB library does not support DB_REGISTER on this system");
00176                         return (EINVAL);
00177                 }
00178 
00179                 if ((ret =
00180                     __envreg_register(dbenv, db_home, &need_recovery)) != 0)
00181                         return (ret);
00182                 if (need_recovery) {
00183                         if (!LF_ISSET(DB_RECOVER)) {
00184                                 __db_err(dbenv,
00185                     "No recovery flag was specified, and recovery is needed");
00186                                 ret = DB_RUNRECOVERY;
00187                                 goto err;
00188                         }
00189                 } else
00190                         LF_CLR(DB_RECOVER | DB_RECOVER_FATAL);
00191         }
00192 
00193         /*
00194          * If we're doing recovery, destroy the environment so that we create
00195          * all the regions from scratch.  The major concern I have is if the
00196          * application stomps the environment with a rogue pointer.  We have
00197          * no way of detecting that, and we could be forced into a situation
00198          * where we start up and then crash, repeatedly.
00199          *
00200          * Note that we do not check any flags like DB_PRIVATE before calling
00201          * remove.  We don't care if the current environment was private or
00202          * not, we just want to nail any files that are left-over for whatever
00203          * reason, from whatever session.
00204          */
00205         if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) {
00206                 orig_flags = dbenv->flags;
00207                 if ((ret = __env_remove_int(dbenv, db_home, DB_FORCE)) != 0 ||
00208                     (ret = __env_refresh(dbenv, orig_flags, 0)) != 0)
00209                         goto err;
00210         }
00211 
00212         ret = __env_open(dbenv, db_home, flags, mode);
00213         if (ret == 0 && dbenv->thr_hashtab != NULL &&
00214             (t_ret = __env_set_state(dbenv, &ip, THREAD_OUT)) != 0)
00215                 ret = t_ret;
00216 
00217 err:    if (need_recovery) {
00218                 /*
00219                  * If recovery succeeded, release our exclusive lock, other
00220                  * processes can now proceed.
00221                  *
00222                  * If recovery failed, unregister now.
00223                  */
00224                 if (ret == 0 && (t_ret = __envreg_xunlock(dbenv)) != 0)
00225                         ret = t_ret;
00226                 if (ret != 0)
00227                         (void)__envreg_unregister(dbenv, 1);
00228         }
00229 
00230         return (ret);
00231 }
00232 
00233 /*
00234  * __env_open --
00235  *      DB_ENV->open.
00236  *
00237  * PUBLIC: int __env_open __P((DB_ENV *, const char *, u_int32_t, int));
00238  */
00239 int
00240 __env_open(dbenv, db_home, flags, mode)
00241         DB_ENV *dbenv;
00242         const char *db_home;
00243         u_int32_t flags;
00244         int mode;
00245 {
00246         DB_THREAD_INFO *ip;
00247         REGINFO *infop;
00248         u_int32_t init_flags, orig_flags;
00249         int rep_check, ret;
00250 
00251         orig_flags = dbenv->flags;
00252         rep_check = 0;
00253         ip = NULL;
00254 
00255         /* Initialize the DB_ENV structure. */
00256         if ((ret = __env_config(dbenv, db_home, flags)) != 0)
00257                 goto err;
00258 
00259         /* Convert the DB_ENV->open flags to internal flags. */
00260         if (LF_ISSET(DB_CREATE))
00261                 F_SET(dbenv, DB_ENV_CREATE);
00262         if (LF_ISSET(DB_LOCKDOWN))
00263                 F_SET(dbenv, DB_ENV_LOCKDOWN);
00264         if (LF_ISSET(DB_PRIVATE))
00265                 F_SET(dbenv, DB_ENV_PRIVATE);
00266         if (LF_ISSET(DB_RECOVER_FATAL))
00267                 F_SET(dbenv, DB_ENV_FATAL);
00268         if (LF_ISSET(DB_SYSTEM_MEM))
00269                 F_SET(dbenv, DB_ENV_SYSTEM_MEM);
00270         if (LF_ISSET(DB_THREAD))
00271                 F_SET(dbenv, DB_ENV_THREAD);
00272 
00273         /* Default permissions are read-write for both owner and group. */
00274         dbenv->db_mode = mode == 0 ? __db_omode("rw-rw----") : mode;
00275 
00276         /*
00277          * Flags saved in the init_flags field of the environment, representing
00278          * flags to DB_ENV->set_flags and DB_ENV->open that need to be set.
00279          */
00280 #define DB_INITENV_CDB          0x0001  /* DB_INIT_CDB */
00281 #define DB_INITENV_CDB_ALLDB    0x0002  /* DB_INIT_CDB_ALLDB */
00282 #define DB_INITENV_LOCK         0x0004  /* DB_INIT_LOCK */
00283 #define DB_INITENV_LOG          0x0008  /* DB_INIT_LOG */
00284 #define DB_INITENV_MPOOL        0x0010  /* DB_INIT_MPOOL */
00285 #define DB_INITENV_REP          0x0020  /* DB_INIT_REP */
00286 #define DB_INITENV_TXN          0x0040  /* DB_INIT_TXN */
00287 
00288         /*
00289          * Create/join the environment.  We pass in the flags of interest to
00290          * a thread subsequently joining an environment we create.  If we're
00291          * not the ones to create the environment, our flags will be updated
00292          * to match the existing environment.
00293          */
00294         init_flags = 0;
00295         if (LF_ISSET(DB_INIT_CDB))
00296                 FLD_SET(init_flags, DB_INITENV_CDB);
00297         if (LF_ISSET(DB_INIT_LOCK))
00298                 FLD_SET(init_flags, DB_INITENV_LOCK);
00299         if (LF_ISSET(DB_INIT_LOG))
00300                 FLD_SET(init_flags, DB_INITENV_LOG);
00301         if (LF_ISSET(DB_INIT_MPOOL))
00302                 FLD_SET(init_flags, DB_INITENV_MPOOL);
00303         if (LF_ISSET(DB_INIT_REP))
00304                 FLD_SET(init_flags, DB_INITENV_REP);
00305         if (LF_ISSET(DB_INIT_TXN))
00306                 FLD_SET(init_flags, DB_INITENV_TXN);
00307         if (F_ISSET(dbenv, DB_ENV_CDB_ALLDB))
00308                 FLD_SET(init_flags, DB_INITENV_CDB_ALLDB);
00309         if ((ret = __db_e_attach(dbenv, &init_flags)) != 0)
00310                 goto err;
00311 
00312         /*
00313          * __db_e_attach will return the saved init_flags field, which contains
00314          * the DB_INIT_* flags used when the environment was created.
00315          *
00316          * We may be joining an environment -- reset our flags to match the
00317          * ones in the environment.
00318          */
00319         if (FLD_ISSET(init_flags, DB_INITENV_CDB))
00320                 LF_SET(DB_INIT_CDB);
00321         if (FLD_ISSET(init_flags, DB_INITENV_LOCK))
00322                 LF_SET(DB_INIT_LOCK);
00323         if (FLD_ISSET(init_flags, DB_INITENV_LOG))
00324                 LF_SET(DB_INIT_LOG);
00325         if (FLD_ISSET(init_flags, DB_INITENV_MPOOL))
00326                 LF_SET(DB_INIT_MPOOL);
00327         if (FLD_ISSET(init_flags, DB_INITENV_REP))
00328                 LF_SET(DB_INIT_REP);
00329         if (FLD_ISSET(init_flags, DB_INITENV_TXN))
00330                 LF_SET(DB_INIT_TXN);
00331         if (FLD_ISSET(init_flags, DB_INITENV_CDB_ALLDB) &&
00332             (ret = __env_set_flags(dbenv, DB_CDB_ALLDB, 1)) != 0)
00333                 goto err;
00334 
00335         /*
00336          * Save the flags matching the database environment: we've replaced
00337          * the argument flags with the flags corresponding to the existing,
00338          * underlying set of subsystems.
00339          */
00340         dbenv->open_flags = flags;
00341 
00342         /* Initialize for CDB product. */
00343         if (LF_ISSET(DB_INIT_CDB)) {
00344                 LF_SET(DB_INIT_LOCK);
00345                 F_SET(dbenv, DB_ENV_CDB);
00346         }
00347 
00348         /*
00349          * The DB_ENV structure has been initialized.  This has to be set
00350          * before we start calling into the subsystems, some of them look
00351          * for it.
00352          */
00353         F_SET(dbenv, DB_ENV_OPEN_CALLED);
00354 
00355         /*
00356          * Initialize the subsystems.
00357          *
00358          * Initialize the mutex regions first.  There's no ordering requirement,
00359          * but it's simpler to get this in place so we don't have to keep track
00360          * of mutexes for later allocation, once the mutex region is created we
00361          * can go ahead and do the allocation for real.
00362          */
00363         if ((ret = __mutex_open(dbenv)) != 0)
00364                 goto err;
00365 
00366         /* __mutex_open creates the thread info region, enter it now. */
00367         ENV_ENTER(dbenv, ip);
00368 
00369         /*
00370          * Initialize the replication area next, so that we can lock out this
00371          * call if we're currently running recovery for replication.
00372          */
00373         if (LF_ISSET(DB_INIT_REP) && (ret = __rep_open(dbenv)) != 0)
00374                 goto err;
00375 
00376         rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0;
00377         if (rep_check && (ret = __env_rep_enter(dbenv, 0)) != 0)
00378                 goto err;
00379 
00380         if (LF_ISSET(DB_INIT_MPOOL))
00381                 if ((ret = __memp_open(dbenv)) != 0)
00382                         goto err;
00383         /*
00384          * Initialize the ciphering area prior to any running of recovery so
00385          * that we can initialize the keys, etc. before recovery.
00386          *
00387          * !!!
00388          * This must be after the mpool init, but before the log initialization
00389          * because log_open may attempt to run log_recover during its open.
00390          */
00391         if (LF_ISSET(DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN) &&
00392             (ret = __crypto_region_init(dbenv)) != 0)
00393                 goto err;
00394 
00395         /*
00396          * Transactions imply logging but do not imply locking.  While almost
00397          * all applications want both locking and logging, it would not be
00398          * unreasonable for a single threaded process to want transactions for
00399          * atomicity guarantees, but not necessarily need concurrency.
00400          */
00401         if (LF_ISSET(DB_INIT_LOG | DB_INIT_TXN))
00402                 if ((ret = __log_open(dbenv)) != 0)
00403                         goto err;
00404         if (LF_ISSET(DB_INIT_LOCK))
00405                 if ((ret = __lock_open(dbenv)) != 0)
00406                         goto err;
00407 
00408         if (LF_ISSET(DB_INIT_TXN)) {
00409                 if ((ret = __txn_open(dbenv)) != 0)
00410                         goto err;
00411 
00412                 /*
00413                  * If the application is running with transactions, initialize
00414                  * the function tables.
00415                  */
00416                 if ((ret = __bam_init_recover(dbenv, &dbenv->recover_dtab,
00417                     &dbenv->recover_dtab_size)) != 0)
00418                         goto err;
00419                 if ((ret = __crdel_init_recover(dbenv, &dbenv->recover_dtab,
00420                     &dbenv->recover_dtab_size)) != 0)
00421                         goto err;
00422                 if ((ret = __db_init_recover(dbenv, &dbenv->recover_dtab,
00423                     &dbenv->recover_dtab_size)) != 0)
00424                         goto err;
00425                 if ((ret = __dbreg_init_recover(dbenv, &dbenv->recover_dtab,
00426                     &dbenv->recover_dtab_size)) != 0)
00427                         goto err;
00428                 if ((ret = __fop_init_recover(dbenv, &dbenv->recover_dtab,
00429                     &dbenv->recover_dtab_size)) != 0)
00430                         goto err;
00431                 if ((ret = __ham_init_recover(dbenv, &dbenv->recover_dtab,
00432                     &dbenv->recover_dtab_size)) != 0)
00433                         goto err;
00434                 if ((ret = __qam_init_recover(dbenv, &dbenv->recover_dtab,
00435                     &dbenv->recover_dtab_size)) != 0)
00436                         goto err;
00437                 if ((ret = __txn_init_recover(dbenv, &dbenv->recover_dtab,
00438                     &dbenv->recover_dtab_size)) != 0)
00439                         goto err;
00440         }
00441 
00442         /*
00443          * Initialize the DB list, and its mutex as necessary.  If the env
00444          * handle isn't free-threaded we don't need a mutex because there
00445          * will never be more than a single DB handle on the list.  If the
00446          * mpool wasn't initialized, then we can't ever open a DB handle.
00447          *
00448          * We also need to initialize the MT mutex as necessary, so do them
00449          * both.
00450          *
00451          * !!!
00452          * This must come after the __memp_open call above because if we are
00453          * recording mutexes for system resources, we will do it in the mpool
00454          * region for environments and db handles.  So, the mpool region must
00455          * already be initialized.
00456          */
00457         LIST_INIT(&dbenv->dblist);
00458         if (LF_ISSET(DB_INIT_MPOOL)) {
00459                 if ((ret = __mutex_alloc(dbenv, MTX_ENV_DBLIST,
00460                     DB_MUTEX_THREAD, &dbenv->mtx_dblist)) != 0)
00461                         goto err;
00462                 if ((ret = __mutex_alloc(dbenv,
00463                     MTX_TWISTER, DB_MUTEX_THREAD, &dbenv->mtx_mt)) != 0)
00464                         goto err;
00465 
00466                 /* Register DB's pgin/pgout functions.  */
00467                 if ((ret = __memp_register(
00468                     dbenv, DB_FTYPE_SET, __db_pgin, __db_pgout)) != 0)
00469                         goto err;
00470         }
00471 
00472         /* Perform recovery for any previous run. */
00473         if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
00474             (ret = __db_apprec(dbenv, NULL, NULL, 1,
00475             LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0)
00476                 goto err;
00477 
00478         /*
00479          * If we've created the regions, are running with transactions, and did
00480          * not just run recovery, we need to log the fact that the transaction
00481          * IDs got reset.
00482          *
00483          * If we ran recovery, there may be prepared-but-not-yet-committed
00484          * transactions that need to be resolved.  Recovery resets the minimum
00485          * transaction ID and logs the reset if that's appropriate, so we
00486          * don't need to do anything here in the recover case.
00487          */
00488         infop = dbenv->reginfo;
00489         if (TXN_ON(dbenv) &&
00490             !F_ISSET(dbenv, DB_ENV_LOG_INMEMORY) &&
00491             F_ISSET(infop, REGION_CREATE) &&
00492             !LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
00493             (ret = __txn_reset(dbenv)) != 0)
00494                 goto err;
00495 
00496         /* The database environment is ready for business. */
00497         if ((ret = __db_e_golive(dbenv)) != 0)
00498                 goto err;
00499 
00500         if (rep_check && (ret = __env_db_rep_exit(dbenv)) != 0)
00501                 goto err;
00502 
00503         ENV_LEAVE(dbenv, ip);
00504         return (0);
00505 
00506 err:    /*
00507          * If we fail after creating the regions, panic and remove them.
00508          *
00509          * !!!
00510          * No need to call __env_db_rep_exit, that work is done by the calls to
00511          * __env_refresh.
00512          */
00513         infop = dbenv->reginfo;
00514         if (infop != NULL && F_ISSET(infop, REGION_CREATE)) {
00515                 ret = __db_panic(dbenv, ret);
00516 
00517                 /* Refresh the DB_ENV so we can use it to call remove. */
00518                 (void)__env_refresh(dbenv, orig_flags, rep_check);
00519                 (void)__env_remove_int(dbenv, db_home, DB_FORCE);
00520                 (void)__env_refresh(dbenv, orig_flags, 0);
00521         } else
00522                 (void)__env_refresh(dbenv, orig_flags, rep_check);
00523 
00524         if (ip != NULL)
00525                 ENV_LEAVE(dbenv, ip);
00526         return (ret);
00527 }
00528 
00529 /*
00530  * __env_remove --
00531  *      DB_ENV->remove.
00532  *
00533  * PUBLIC: int __env_remove __P((DB_ENV *, const char *, u_int32_t));
00534  */
00535 int
00536 __env_remove(dbenv, db_home, flags)
00537         DB_ENV *dbenv;
00538         const char *db_home;
00539         u_int32_t flags;
00540 {
00541         int ret, t_ret;
00542 
00543 #undef  OKFLAGS
00544 #define OKFLAGS                                                         \
00545         (DB_FORCE | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT)
00546 
00547         /* Validate arguments. */
00548         if ((ret = __db_fchk(dbenv, "DB_ENV->remove", flags, OKFLAGS)) != 0)
00549                 return (ret);
00550 
00551         ENV_ILLEGAL_AFTER_OPEN(dbenv, "DB_ENV->remove");
00552 
00553         ret = __env_remove_int(dbenv, db_home, flags);
00554 
00555         if ((t_ret = __env_close(dbenv, 0)) != 0 && ret == 0)
00556                 ret = t_ret;
00557 
00558         return (ret);
00559 }
00560 
00561 /*
00562  * __env_remove_int --
00563  *      Discard an environment, internal version.
00564  */
00565 static int
00566 __env_remove_int(dbenv, db_home, flags)
00567         DB_ENV *dbenv;
00568         const char *db_home;
00569         u_int32_t flags;
00570 {
00571         int ret;
00572 
00573         /* Initialize the DB_ENV structure. */
00574         if ((ret = __env_config(dbenv, db_home, flags)) != 0)
00575                 return (ret);
00576 
00577         /* The DB_ENV structure has been initialized. */
00578         F_SET(dbenv, DB_ENV_OPEN_CALLED);
00579 
00580         /* Remove the environment. */
00581         return (__db_e_remove(dbenv, flags));
00582 }
00583 
00584 /*
00585  * __env_config --
00586  *      Initialization of the DB_ENV structure, read the DB_CONFIG file.
00587  */
00588 static int
00589 __env_config(dbenv, db_home, flags)
00590         DB_ENV *dbenv;
00591         const char *db_home;
00592         u_int32_t flags;
00593 {
00594         FILE *fp;
00595         int ret;
00596         char *p, buf[256];
00597 
00598         /*
00599          * Set the database home.  Do this before calling __db_appname,
00600          * it uses the home directory.
00601          */
00602         if ((ret = __db_home(dbenv, db_home, flags)) != 0)
00603                 return (ret);
00604 
00605         /* Parse the config file. */
00606         p = NULL;
00607         if ((ret =
00608             __db_appname(dbenv, DB_APP_NONE, "DB_CONFIG", 0, NULL, &p)) != 0)
00609                 return (ret);
00610         if (p == NULL)
00611                 fp = NULL;
00612         else {
00613                 fp = fopen(p, "r");
00614                 __os_free(dbenv, p);
00615         }
00616 
00617         if (fp != NULL) {
00618                 while (fgets(buf, sizeof(buf), fp) != NULL) {
00619                         if ((p = strchr(buf, '\n')) != NULL)
00620                                 *p = '\0';
00621                         else if (strlen(buf) + 1 == sizeof(buf)) {
00622                                 __db_err(dbenv, "DB_CONFIG: line too long");
00623                                 (void)fclose(fp);
00624                                 return (EINVAL);
00625                         }
00626                         if (buf[0] == '\0' ||
00627                             buf[0] == '#' || isspace((int)buf[0]))
00628                                 continue;
00629 
00630                         if ((ret = __db_parse(dbenv, buf)) != 0) {
00631                                 (void)fclose(fp);
00632                                 return (ret);
00633                         }
00634                 }
00635                 (void)fclose(fp);
00636         }
00637 
00638         /*
00639          * If no temporary directory path was specified in the config file,
00640          * choose one.
00641          */
00642         if (dbenv->db_tmp_dir == NULL && (ret = __os_tmpdir(dbenv, flags)) != 0)
00643                 return (ret);
00644 
00645         return (0);
00646 }
00647 
00648 /*
00649  * __env_close_pp --
00650  *      DB_ENV->close pre/post processor.
00651  *
00652  * PUBLIC: int __env_close_pp __P((DB_ENV *, u_int32_t));
00653  */
00654 int
00655 __env_close_pp(dbenv, flags)
00656         DB_ENV *dbenv;
00657         u_int32_t flags;
00658 {
00659         DB_THREAD_INFO *ip;
00660         int rep_check, ret, t_ret;
00661 
00662         ret = 0;
00663 
00664         PANIC_CHECK(dbenv);
00665 
00666         ENV_ENTER(dbenv, ip);
00667         /*
00668          * Validate arguments, but as a DB_ENV handle destructor, we can't
00669          * fail.
00670          */
00671         if (flags != 0 &&
00672             (t_ret = __db_ferr(dbenv, "DB_ENV->close", 0)) != 0 && ret == 0)
00673                 ret = t_ret;
00674 
00675         rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0;
00676         if (rep_check && (t_ret = __env_rep_enter(dbenv, 0)) != 0 && ret == 0)
00677                 ret = t_ret;
00678 
00679         if ((t_ret = __env_close(dbenv, rep_check)) != 0 && ret == 0)
00680                 ret = t_ret;
00681 
00682         /* Don't ENV_LEAVE as we have already detached from the region. */
00683         return (ret);
00684 }
00685 
00686 /*
00687  * __env_close --
00688  *      DB_ENV->close.
00689  *
00690  * PUBLIC: int __env_close __P((DB_ENV *, int));
00691  */
00692 int
00693 __env_close(dbenv, rep_check)
00694         DB_ENV *dbenv;
00695         int rep_check;
00696 {
00697         int ret, t_ret;
00698         char **p;
00699 
00700         ret = 0;
00701 
00702         /*
00703          * Before checking the reference count, we have to see if we were in
00704          * the middle of restoring transactions and need to close the open
00705          * files.
00706          */
00707         if (TXN_ON(dbenv) && (t_ret = __txn_preclose(dbenv)) != 0 && ret == 0)
00708                 ret = t_ret;
00709 
00710         if (REP_ON(dbenv) &&
00711             (t_ret = __rep_preclose(dbenv)) != 0 && ret == 0)
00712                 ret = t_ret;
00713 
00714         /*
00715          * Detach from the regions and undo the allocations done by
00716          * DB_ENV->open.
00717          */
00718         if ((t_ret = __env_refresh(dbenv, 0, rep_check)) != 0 && ret == 0)
00719                 ret = t_ret;
00720 
00721         /* Do per-subsystem close. */
00722         if ((t_ret = __lock_dbenv_close(dbenv)) != 0 && ret == 0)
00723                 ret = t_ret;
00724 
00725         if ((t_ret = __rep_dbenv_close(dbenv)) != 0 && ret == 0)
00726                 ret = t_ret;
00727 
00728 #ifdef HAVE_CRYPTO
00729         /*
00730          * Crypto comes last, because higher level close functions need
00731          * cryptography.
00732          */
00733         if ((t_ret = __crypto_dbenv_close(dbenv)) != 0 && ret == 0)
00734                 ret = t_ret;
00735 #endif
00736 
00737         /* Release any string-based configuration parameters we've copied. */
00738         if (dbenv->db_log_dir != NULL)
00739                 __os_free(dbenv, dbenv->db_log_dir);
00740         if (dbenv->db_tmp_dir != NULL)
00741                 __os_free(dbenv, dbenv->db_tmp_dir);
00742         if (dbenv->db_data_dir != NULL) {
00743                 for (p = dbenv->db_data_dir; *p != NULL; ++p)
00744                         __os_free(dbenv, *p);
00745                 __os_free(dbenv, dbenv->db_data_dir);
00746         }
00747 
00748         /* If we're registered, clean up. */
00749         if (dbenv->registry != NULL) {
00750                 (void)__envreg_unregister(dbenv, 0);
00751                 dbenv->registry = NULL;
00752         }
00753 
00754         /* Discard the structure. */
00755         memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV));
00756         __os_free(NULL, dbenv);
00757 
00758         return (ret);
00759 }
00760 
00761 /*
00762  * __env_refresh --
00763  *      Refresh the DB_ENV structure, releasing resources allocated by
00764  * DB_ENV->open, and returning it to the state it was in just before
00765  * open was called.  (Note that this means that any state set by
00766  * pre-open configuration functions must be preserved.)
00767  */
00768 static int
00769 __env_refresh(dbenv, orig_flags, rep_check)
00770         DB_ENV *dbenv;
00771         u_int32_t orig_flags;
00772         int rep_check;
00773 {
00774         DB *ldbp;
00775         DB_THREAD_INFO *ip;
00776         int ret, t_ret;
00777 
00778         ret = 0;
00779 
00780         /*
00781          * Refresh subsystems, in the reverse order they were opened (txn
00782          * must be first, it may want to discard locks and flush the log).
00783          *
00784          * !!!
00785          * Note that these functions, like all of __env_refresh, only undo
00786          * the effects of __env_open.  Functions that undo work done by
00787          * db_env_create or by a configuration function should go in
00788          * __env_close.
00789          */
00790         if (TXN_ON(dbenv) &&
00791             (t_ret = __txn_dbenv_refresh(dbenv)) != 0 && ret == 0)
00792                 ret = t_ret;
00793 
00794         if (LOGGING_ON(dbenv) &&
00795             (t_ret = __log_dbenv_refresh(dbenv)) != 0 && ret == 0)
00796                 ret = t_ret;
00797 
00798         /*
00799          * Locking should come after logging, because closing log results
00800          * in files closing which may require locks being released.
00801          */
00802         if (LOCKING_ON(dbenv)) {
00803                 if (!F_ISSET(dbenv, DB_ENV_THREAD) &&
00804                     dbenv->env_lref != NULL && (t_ret = __lock_id_free(dbenv,
00805                     ((DB_LOCKER *)dbenv->env_lref)->id)) != 0 && ret == 0)
00806                         ret = t_ret;
00807                 dbenv->env_lref = NULL;
00808 
00809                 if ((t_ret = __lock_dbenv_refresh(dbenv)) != 0 && ret == 0)
00810                         ret = t_ret;
00811         }
00812 
00813         /*
00814          * Discard DB list and its mutex.
00815          * Discard the MT mutex.
00816          *
00817          * !!!
00818          * This must be done before we close the mpool region because we
00819          * may have allocated the DB handle mutex in the mpool region.
00820          * It must be done *after* we close the log region, though, because
00821          * we close databases and try to acquire the mutex when we close
00822          * log file handles.  Ick.
00823          */
00824         if (dbenv->db_ref != 0) {
00825                 __db_err(dbenv,
00826                     "Database handles still open at environment close");
00827                 for (ldbp = LIST_FIRST(&dbenv->dblist);
00828                     ldbp != NULL; ldbp = LIST_NEXT(ldbp, dblistlinks))
00829                         __db_err(dbenv, "Open database handle: %s%s%s",
00830                             ldbp->fname == NULL ? "unnamed" : ldbp->fname,
00831                             ldbp->dname == NULL ? "" : "/",
00832                             ldbp->dname == NULL ? "" : ldbp->dname);
00833                 if (ret == 0)
00834                         ret = EINVAL;
00835         }
00836         LIST_INIT(&dbenv->dblist);
00837 
00838         if ((t_ret = __mutex_free(dbenv, &dbenv->mtx_dblist)) != 0 && ret == 0)
00839                 ret = t_ret;
00840         if ((t_ret = __mutex_free(dbenv, &dbenv->mtx_mt)) != 0 && ret == 0)
00841                 ret = t_ret;
00842 
00843         if (dbenv->mt != NULL) {
00844                 __os_free(dbenv, dbenv->mt);
00845                 dbenv->mt = NULL;
00846         }
00847 
00848         if (MPOOL_ON(dbenv)) {
00849                 /*
00850                  * If it's a private environment, flush the contents to disk.
00851                  * Recovery would have put everything back together, but it's
00852                  * faster and cleaner to flush instead.
00853                  */
00854                 if (F_ISSET(dbenv, DB_ENV_PRIVATE) &&
00855                     (t_ret = __memp_sync(dbenv, NULL)) != 0 && ret == 0)
00856                         ret = t_ret;
00857                 if ((t_ret = __memp_dbenv_refresh(dbenv)) != 0 && ret == 0)
00858                         ret = t_ret;
00859         }
00860 
00861         /*
00862          * If we're included in a shared replication handle count, this
00863          * is our last chance to decrement that count.
00864          *
00865          * !!!
00866          * We can't afford to do anything dangerous after we decrement the
00867          * handle count, of course, as replication may be proceeding with
00868          * client recovery.  However, since we're discarding the regions
00869          * as soon as we drop the handle count, there's little opportunity
00870          * to do harm.
00871          */
00872         if (rep_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00873                 ret = t_ret;
00874 
00875         /*
00876          * Detach from the region.
00877          *
00878          * Must come after we call __env_db_rep_exit above.
00879          */
00880         __rep_dbenv_refresh(dbenv);
00881 
00882         /*
00883          * Mark the thread as out of the env before we get rid
00884          * of the handles needed to do so.
00885          */
00886         if (dbenv->thr_hashtab != NULL &&
00887             (t_ret = __env_set_state(dbenv, &ip, THREAD_OUT)) != 0 && ret == 0)
00888                 ret = t_ret;
00889 
00890         if (MUTEX_ON(dbenv) &&
00891             (t_ret = __mutex_dbenv_refresh(dbenv)) != 0 && ret == 0)
00892                 ret = t_ret;
00893 
00894         if (dbenv->reginfo != NULL) {
00895                 if ((t_ret = __db_e_detach(dbenv, 0)) != 0 && ret == 0)
00896                         ret = t_ret;
00897                 /*
00898                  * !!!
00899                  * Don't free dbenv->reginfo or set the reference to NULL,
00900                  * that was done by __db_e_detach().
00901                  */
00902         }
00903 
00904         /* Undo changes and allocations done by __env_open. */
00905         if (dbenv->db_home != NULL) {
00906                 __os_free(dbenv, dbenv->db_home);
00907                 dbenv->db_home = NULL;
00908         }
00909         if (dbenv->db_abshome != NULL) {
00910                 __os_free(dbenv, dbenv->db_abshome);
00911                 dbenv->db_abshome = NULL;
00912         }
00913         if (dbenv->mutex_iq != NULL) {
00914                 __os_free(dbenv, dbenv->mutex_iq);
00915                 dbenv->mutex_iq = NULL;
00916         }
00917 
00918         dbenv->open_flags = 0;
00919         dbenv->db_mode = 0;
00920 
00921         if (dbenv->recover_dtab != NULL) {
00922                 __os_free(dbenv, dbenv->recover_dtab);
00923                 dbenv->recover_dtab = NULL;
00924                 dbenv->recover_dtab_size = 0;
00925         }
00926 
00927         dbenv->flags = orig_flags;
00928 
00929         return (ret);
00930 }
00931 
00932 #define DB_ADDSTR(add) {                                                \
00933         /*                                                              \
00934          * The string might be NULL or zero-length, and the p[-1]       \
00935          * might indirect to before the beginning of our buffer.        \
00936          */                                                             \
00937         if ((add) != NULL && (add)[0] != '\0') {                        \
00938                 /* If leading slash, start over. */                     \
00939                 if (__os_abspath(add)) {                                \
00940                         p = str;                                        \
00941                         slash = 0;                                      \
00942                 }                                                       \
00943                 /* Append to the current string. */                     \
00944                 len = strlen(add);                                      \
00945                 if (slash)                                              \
00946                         *p++ = PATH_SEPARATOR[0];                       \
00947                 memcpy(p, add, len);                                    \
00948                 p += len;                                               \
00949                 slash = strchr(PATH_SEPARATOR, p[-1]) == NULL;          \
00950         }                                                               \
00951 }
00952 
00953 /*
00954  * __env_get_open_flags
00955  *      Retrieve the flags passed to DB_ENV->open.
00956  *
00957  * PUBLIC: int __env_get_open_flags __P((DB_ENV *, u_int32_t *));
00958  */
00959 int
00960 __env_get_open_flags(dbenv, flagsp)
00961         DB_ENV *dbenv;
00962         u_int32_t *flagsp;
00963 {
00964         ENV_ILLEGAL_BEFORE_OPEN(dbenv, "DB_ENV->get_open_flags");
00965 
00966         *flagsp = dbenv->open_flags;
00967         return (0);
00968 }
00969 
00970 /*
00971  * __db_appname --
00972  *      Given an optional DB environment, directory and file name and type
00973  *      of call, build a path based on the DB_ENV->open rules, and return
00974  *      it in allocated space.
00975  *
00976  * PUBLIC: int __db_appname __P((DB_ENV *, APPNAME,
00977  * PUBLIC:    const char *, u_int32_t, DB_FH **, char **));
00978  */
00979 int
00980 __db_appname(dbenv, appname, file, tmp_oflags, fhpp, namep)
00981         DB_ENV *dbenv;
00982         APPNAME appname;
00983         const char *file;
00984         u_int32_t tmp_oflags;
00985         DB_FH **fhpp;
00986         char **namep;
00987 {
00988         size_t len, str_len;
00989         int data_entry, ret, slash, tmp_create;
00990         const char *a, *b;
00991         char *p, *str;
00992 
00993         a = b = NULL;
00994         data_entry = -1;
00995         tmp_create = 0;
00996 
00997         /*
00998          * We don't return a name when creating temporary files, just a file
00999          * handle.  Default to an error now.
01000          */
01001         if (fhpp != NULL)
01002                 *fhpp = NULL;
01003         if (namep != NULL)
01004                 *namep = NULL;
01005 
01006         /*
01007          * Absolute path names are never modified.  If the file is an absolute
01008          * path, we're done.
01009          */
01010         if (file != NULL && __os_abspath(file))
01011                 return (__os_strdup(dbenv, file, namep));
01012 
01013         /* Everything else is relative to the environment home. */
01014         if (dbenv != NULL)
01015                 a = dbenv->db_home;
01016 
01017 retry:  /*
01018          * DB_APP_NONE:
01019          *      DB_HOME/file
01020          * DB_APP_DATA:
01021          *      DB_HOME/DB_DATA_DIR/file
01022          * DB_APP_LOG:
01023          *      DB_HOME/DB_LOG_DIR/file
01024          * DB_APP_TMP:
01025          *      DB_HOME/DB_TMP_DIR/<create>
01026          */
01027         switch (appname) {
01028         case DB_APP_NONE:
01029                 break;
01030         case DB_APP_DATA:
01031                 if (dbenv != NULL && dbenv->db_data_dir != NULL &&
01032                     (b = dbenv->db_data_dir[++data_entry]) == NULL) {
01033                         data_entry = -1;
01034                         b = dbenv->db_data_dir[0];
01035                 }
01036                 break;
01037         case DB_APP_LOG:
01038                 if (dbenv != NULL)
01039                         b = dbenv->db_log_dir;
01040                 break;
01041         case DB_APP_TMP:
01042                 if (dbenv != NULL)
01043                         b = dbenv->db_tmp_dir;
01044                 tmp_create = 1;
01045                 break;
01046         }
01047 
01048         len =
01049             (a == NULL ? 0 : strlen(a) + 1) +
01050             (b == NULL ? 0 : strlen(b) + 1) +
01051             (file == NULL ? 0 : strlen(file) + 1);
01052 
01053         /*
01054          * Allocate space to hold the current path information, as well as any
01055          * temporary space that we're going to need to create a temporary file
01056          * name.
01057          */
01058 #define DB_TRAIL        "BDBXXXXX"
01059         str_len = len + sizeof(DB_TRAIL) + 10;
01060         if ((ret = __os_malloc(dbenv, str_len, &str)) != 0)
01061                 return (ret);
01062 
01063         slash = 0;
01064         p = str;
01065         DB_ADDSTR(a);
01066         DB_ADDSTR(b);
01067         DB_ADDSTR(file);
01068         *p = '\0';
01069 
01070         /*
01071          * If we're opening a data file, see if it exists.  If it does,
01072          * return it, otherwise, try and find another one to open.
01073          */
01074         if (__os_exists(str, NULL) != 0 && data_entry != -1) {
01075                 __os_free(dbenv, str);
01076                 b = NULL;
01077                 goto retry;
01078         }
01079 
01080         /* Create the file if so requested. */
01081         if (tmp_create &&
01082             (ret = __db_tmp_open(dbenv, tmp_oflags, str, fhpp)) != 0) {
01083                 __os_free(dbenv, str);
01084                 return (ret);
01085         }
01086 
01087         if (namep == NULL)
01088                 __os_free(dbenv, str);
01089         else
01090                 *namep = str;
01091         return (0);
01092 }
01093 
01094 /*
01095  * __db_home --
01096  *      Find the database home.
01097  *
01098  * PUBLIC:      int __db_home __P((DB_ENV *, const char *, u_int32_t));
01099  */
01100 int
01101 __db_home(dbenv, db_home, flags)
01102         DB_ENV *dbenv;
01103         const char *db_home;
01104         u_int32_t flags;
01105 {
01106         int ret;
01107         const char *p;
01108         char path[MAXPATHLEN];
01109 
01110         /*
01111          * Use db_home by default, this allows utilities to reasonably
01112          * override the environment either explicitly or by using a -h
01113          * option.  Otherwise, use the environment if it's permitted
01114          * and initialized.
01115          */
01116         if ((p = db_home) == NULL &&
01117             (LF_ISSET(DB_USE_ENVIRON) ||
01118             (LF_ISSET(DB_USE_ENVIRON_ROOT) && __os_isroot())) &&
01119             (p = getenv("DB_HOME")) != NULL && p[0] == '\0') {
01120                 __db_err(dbenv, "illegal DB_HOME environment variable");
01121                 return (EINVAL);
01122         }
01123         if (p != NULL && (ret = __os_strdup(dbenv, p, &dbenv->db_home)) != 0)
01124                 return (ret);
01125 
01126         /*
01127          * Get the absolute pathname of the current directory.  We use this
01128          * to build absolute pathnames when removing log files.
01129          *
01130          * XXX
01131          * Can't trust getcwd(3) to set a valid errno, so don't try to display
01132          * one unless we know it's good.  It's likely a permissions problem:
01133          * use something bland and useless in the default return value, so we
01134          * don't send somebody off in the wrong direction.
01135          */
01136         __os_set_errno(0);
01137         if ((p = getcwd(path, sizeof(path))) == NULL) {
01138                 if ((ret = __os_get_errno()) == 0) {
01139                         __db_err(dbenv,
01140                             "no absolute path for the current directory");
01141                         ret = EAGAIN;
01142                 } else
01143                         __db_err(dbenv,
01144                             "no absolute path for the current directory: %s",
01145                             db_strerror(ret));
01146                 return (ret);
01147         }
01148         if (p != NULL && (ret = __os_strdup(dbenv, p, &dbenv->db_abshome)) != 0)
01149                 return (ret);
01150 
01151         return (0);
01152 }
01153 
01154 #define __DB_OVFL(v, max)                                               \
01155         if (v > max) {                                                  \
01156                 __v = v;                                                \
01157                 __max = max;                                            \
01158                 goto toobig;                                            \
01159         }
01160 
01161 /*
01162  * __db_parse --
01163  *      Parse a single NAME VALUE pair.
01164  */
01165 static int
01166 __db_parse(dbenv, s)
01167         DB_ENV *dbenv;
01168         char *s;
01169 {
01170         u_long __max, __v, v1, v2, v3;
01171         u_int32_t flags;
01172         char *name, *p, *value, v4;
01173 
01174         /*
01175          * !!!
01176          * The constant 40 is hard-coded into format arguments to sscanf
01177          * below, it can't be changed here without changing it there, too.
01178          * The additional bytes are for a trailing nul byte and because we
01179          * are reading user input -- I don't want to risk any off-by-ones.
01180          */
01181         char arg[40 + 5];
01182 
01183         /*
01184          * Name/value pairs are parsed as two white-space separated strings.
01185          * Leading and trailing white-space is trimmed from the value, but
01186          * it may contain embedded white-space.  Note: we use the isspace(3)
01187          * macro because it's more portable, but that means that you can use
01188          * characters like form-feed to separate the strings.
01189          */
01190         name = s;
01191         for (p = name; *p != '\0' && !isspace((int)*p); ++p)
01192                 ;
01193         if (*p == '\0' || p == name)
01194                 goto illegal;
01195         *p = '\0';
01196         for (++p; isspace((int)*p); ++p)
01197                 ;
01198         if (*p == '\0')
01199                 goto illegal;
01200         value = p;
01201         for (++p; *p != '\0'; ++p)
01202                 ;
01203         for (--p; isspace((int)*p); --p)
01204                 ;
01205         ++p;
01206         if (p == value) {
01207 illegal:        __db_err(dbenv, "mis-formatted name-value pair: %s", s);
01208                 return (EINVAL);
01209         }
01210         *p = '\0';
01211 
01212         if (strcasecmp(name, "mutex_set_align") == 0) {
01213                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01214                         goto badarg;
01215                 __DB_OVFL(v1, UINT32_MAX);
01216                 return (__mutex_set_align(dbenv, (u_int32_t)v1));
01217         }
01218 
01219         if (strcasecmp(name, "mutex_set_increment") == 0) {
01220                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01221                         goto badarg;
01222                 __DB_OVFL(v1, UINT32_MAX);
01223                 return (__mutex_set_increment(dbenv, (u_int32_t)v1));
01224         }
01225 
01226         if (strcasecmp(name, "mutex_set_max") == 0) {
01227                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01228                         goto badarg;
01229                 __DB_OVFL(v1, UINT32_MAX);
01230                 return (__mutex_set_max(dbenv, (u_int32_t)v1));
01231         }
01232 
01233         if (strcasecmp(name, "mutex_set_tas_spins") == 0) {
01234                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01235                         goto badarg;
01236                 __DB_OVFL(v1, UINT32_MAX);
01237                 return (__mutex_set_tas_spins(dbenv, (u_int32_t)v1));
01238         }
01239 
01240         if (strcasecmp(name, "rep_set_config") == 0) {
01241                 if (sscanf(value, "%40s %c", arg, &v4) != 1)
01242                         goto badarg;
01243 
01244                 if (strcasecmp(value, "rep_bulk") == 0)
01245                         return (__rep_set_config(dbenv,
01246                             DB_REP_CONF_BULK, 1));
01247                 if (strcasecmp(value, "rep_delayclient") == 0)
01248                         return (__rep_set_config(dbenv,
01249                             DB_REP_CONF_DELAYCLIENT, 1));
01250                 if (strcasecmp(value, "rep_noautoinit") == 0)
01251                         return (__rep_set_config(dbenv,
01252                             DB_REP_CONF_NOAUTOINIT, 1));
01253                 if (strcasecmp(value, "rep_nowait") == 0)
01254                         return (__rep_set_config(dbenv, DB_REP_CONF_NOWAIT, 1));
01255                 goto badarg;
01256         }
01257 
01258         if (strcasecmp(name, "set_cachesize") == 0) {
01259                 if (sscanf(value, "%lu %lu %lu %c", &v1, &v2, &v3, &v4) != 3)
01260                         goto badarg;
01261                 __DB_OVFL(v1, UINT32_MAX);
01262                 __DB_OVFL(v2, UINT32_MAX);
01263                 __DB_OVFL(v3, 10000);
01264                 return (__memp_set_cachesize(
01265                     dbenv, (u_int32_t)v1, (u_int32_t)v2, (int)v3));
01266         }
01267 
01268         if (strcasecmp(name, "set_data_dir") == 0 ||
01269             strcasecmp(name, "db_data_dir") == 0)       /* Compatibility. */
01270                 return (__env_set_data_dir(dbenv, value));
01271 
01272                                                         /* Undocumented. */
01273         if (strcasecmp(name, "set_intermediate_dir") == 0) {
01274                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01275                         goto badarg;
01276 #ifdef INT_MAX
01277                 __DB_OVFL(v1, INT_MAX);
01278 #endif
01279                 return (__env_set_intermediate_dir(dbenv, (int)v1, 0));
01280         }
01281 
01282         if (strcasecmp(name, "set_flags") == 0) {
01283                 if (sscanf(value, "%40s %c", arg, &v4) != 1)
01284                         goto badarg;
01285 
01286                 if (strcasecmp(value, "db_auto_commit") == 0)
01287                         return (__env_set_flags(dbenv, DB_AUTO_COMMIT, 1));
01288                 if (strcasecmp(value, "db_cdb_alldb") == 0)
01289                         return (__env_set_flags(dbenv, DB_CDB_ALLDB, 1));
01290                 if (strcasecmp(value, "db_direct_db") == 0)
01291                         return (__env_set_flags(dbenv, DB_DIRECT_DB, 1));
01292                 if (strcasecmp(value, "db_direct_log") == 0)
01293                         return (__env_set_flags(dbenv, DB_DIRECT_LOG, 1));
01294                 if (strcasecmp(value, "db_dsync_db") == 0)
01295                         return (__env_set_flags(dbenv, DB_DSYNC_DB, 1));
01296                 if (strcasecmp(value, "db_dsync_log") == 0)
01297                         return (__env_set_flags(dbenv, DB_DSYNC_LOG, 1));
01298                 if (strcasecmp(value, "db_log_autoremove") == 0)
01299                         return (__env_set_flags(dbenv, DB_LOG_AUTOREMOVE, 1));
01300                 if (strcasecmp(value, "db_log_inmemory") == 0)
01301                         return (__env_set_flags(dbenv, DB_LOG_INMEMORY, 1));
01302                 if (strcasecmp(value, "db_nolocking") == 0)
01303                         return (__env_set_flags(dbenv, DB_NOLOCKING, 1));
01304                 if (strcasecmp(value, "db_nommap") == 0)
01305                         return (__env_set_flags(dbenv, DB_NOMMAP, 1));
01306                 if (strcasecmp(value, "db_nopanic") == 0)
01307                         return (__env_set_flags(dbenv, DB_NOPANIC, 1));
01308                 if (strcasecmp(value, "db_overwrite") == 0)
01309                         return (__env_set_flags(dbenv, DB_OVERWRITE, 1));
01310                 if (strcasecmp(value, "db_region_init") == 0)
01311                         return (__env_set_flags(dbenv, DB_REGION_INIT, 1));
01312                 if (strcasecmp(value, "db_txn_nosync") == 0)
01313                         return (__env_set_flags(dbenv, DB_TXN_NOSYNC, 1));
01314                 if (strcasecmp(value, "db_txn_write_nosync") == 0)
01315                         return (
01316                             __env_set_flags(dbenv, DB_TXN_WRITE_NOSYNC, 1));
01317                 if (strcasecmp(value, "db_yieldcpu") == 0)
01318                         return (__env_set_flags(dbenv, DB_YIELDCPU, 1));
01319                 goto badarg;
01320         }
01321 
01322         if (strcasecmp(name, "set_lg_bsize") == 0) {
01323                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01324                         goto badarg;
01325                 __DB_OVFL(v1, UINT32_MAX);
01326                 return (__log_set_lg_bsize(dbenv, (u_int32_t)v1));
01327         }
01328 
01329         if (strcasecmp(name, "set_lg_filemode") == 0) {
01330                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01331                         goto badarg;
01332                 __DB_OVFL(v1, INT_MAX);
01333                 return (__log_set_lg_filemode(dbenv, (int)v1));
01334         }
01335 
01336         if (strcasecmp(name, "set_lg_max") == 0) {
01337                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01338                         goto badarg;
01339                 __DB_OVFL(v1, UINT32_MAX);
01340                 return (__log_set_lg_max(dbenv, (u_int32_t)v1));
01341         }
01342 
01343         if (strcasecmp(name, "set_lg_regionmax") == 0) {
01344                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01345                         goto badarg;
01346                 __DB_OVFL(v1, UINT32_MAX);
01347                 return (__log_set_lg_regionmax(dbenv, (u_int32_t)v1));
01348         }
01349 
01350         if (strcasecmp(name, "set_lg_dir") == 0 ||
01351             strcasecmp(name, "db_log_dir") == 0)        /* Compatibility. */
01352                 return (__log_set_lg_dir(dbenv, value));
01353 
01354         if (strcasecmp(name, "set_lk_detect") == 0) {
01355                 if (sscanf(value, "%40s %c", arg, &v4) != 1)
01356                         goto badarg;
01357                 if (strcasecmp(value, "db_lock_default") == 0)
01358                         flags = DB_LOCK_DEFAULT;
01359                 else if (strcasecmp(value, "db_lock_expire") == 0)
01360                         flags = DB_LOCK_EXPIRE;
01361                 else if (strcasecmp(value, "db_lock_maxlocks") == 0)
01362                         flags = DB_LOCK_MAXLOCKS;
01363                 else if (strcasecmp(value, "db_lock_maxwrite") == 0)
01364                         flags = DB_LOCK_MAXWRITE;
01365                 else if (strcasecmp(value, "db_lock_minlocks") == 0)
01366                         flags = DB_LOCK_MINLOCKS;
01367                 else if (strcasecmp(value, "db_lock_minwrite") == 0)
01368                         flags = DB_LOCK_MINWRITE;
01369                 else if (strcasecmp(value, "db_lock_oldest") == 0)
01370                         flags = DB_LOCK_OLDEST;
01371                 else if (strcasecmp(value, "db_lock_random") == 0)
01372                         flags = DB_LOCK_RANDOM;
01373                 else if (strcasecmp(value, "db_lock_youngest") == 0)
01374                         flags = DB_LOCK_YOUNGEST;
01375                 else
01376                         goto badarg;
01377                 return (__lock_set_lk_detect(dbenv, flags));
01378         }
01379 
01380         if (strcasecmp(name, "set_lk_max") == 0) {
01381                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01382                         goto badarg;
01383                 __DB_OVFL(v1, UINT32_MAX);
01384                 return (__lock_set_lk_max(dbenv, (u_int32_t)v1));
01385         }
01386 
01387         if (strcasecmp(name, "set_lk_max_locks") == 0) {
01388                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01389                         goto badarg;
01390                 __DB_OVFL(v1, UINT32_MAX);
01391                 return (__lock_set_lk_max_locks(dbenv, (u_int32_t)v1));
01392         }
01393 
01394         if (strcasecmp(name, "set_lk_max_lockers") == 0) {
01395                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01396                         goto badarg;
01397                 __DB_OVFL(v1, UINT32_MAX);
01398                 return (__lock_set_lk_max_lockers(dbenv, (u_int32_t)v1));
01399         }
01400 
01401         if (strcasecmp(name, "set_lk_max_objects") == 0) {
01402                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01403                         goto badarg;
01404                 __DB_OVFL(v1, UINT32_MAX);
01405                 return (__lock_set_lk_max_objects(dbenv, (u_int32_t)v1));
01406         }
01407 
01408         if (strcasecmp(name, "set_lock_timeout") == 0) {
01409                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01410                         goto badarg;
01411                 __DB_OVFL(v1, UINT32_MAX);
01412                 return (__lock_set_env_timeout(
01413                     dbenv, (u_int32_t)v1, DB_SET_LOCK_TIMEOUT));
01414         }
01415 
01416         if (strcasecmp(name, "set_mp_max_openfd") == 0) {
01417                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01418                         goto badarg;
01419                 __DB_OVFL(v1, INT_MAX);
01420                 return (__memp_set_mp_max_openfd(dbenv, (int)v1));
01421         }
01422 
01423         if (strcasecmp(name, "set_mp_max_write") == 0) {
01424                 if (sscanf(value, "%lu %lu %c", &v1, &v2, &v4) != 2)
01425                         goto badarg;
01426                 __DB_OVFL(v1, INT_MAX);
01427                 __DB_OVFL(v2, INT_MAX);
01428                 return (__memp_set_mp_max_write(dbenv, (int)v1, (int)v2));
01429         }
01430 
01431         if (strcasecmp(name, "set_mp_mmapsize") == 0) {
01432                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01433                         goto badarg;
01434                 __DB_OVFL(v1, UINT32_MAX);
01435                 return (__memp_set_mp_mmapsize(dbenv, (u_int32_t)v1));
01436         }
01437 
01438         if (strcasecmp(name, "set_region_init") == 0) {
01439                 if (sscanf(value, "%lu %c", &v1, &v4) != 1 || v1 != 1)
01440                         goto badarg;
01441                 return (__env_set_flags(
01442                     dbenv, DB_REGION_INIT, v1 == 0 ? 0 : 1));
01443         }
01444 
01445         if (strcasecmp(name, "set_shm_key") == 0) {
01446                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01447                         goto badarg;
01448                 return (__env_set_shm_key(dbenv, (long)v1));
01449         }
01450 
01451         /*
01452          * The set_tas_spins method has been replaced by mutex_set_tas_spins.
01453          * The set_tas_spins name remains for DB_CONFIG compatibility.
01454          */
01455         if (strcasecmp(name, "set_tas_spins") == 0) {
01456                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01457                         goto badarg;
01458                 __DB_OVFL(v1, UINT32_MAX);
01459                 return (__mutex_set_tas_spins(dbenv, (u_int32_t)v1));
01460         }
01461 
01462         if (strcasecmp(name, "set_tmp_dir") == 0 ||
01463             strcasecmp(name, "db_tmp_dir") == 0)        /* Compatibility.*/
01464                 return (__env_set_tmp_dir(dbenv, value));
01465 
01466         if (strcasecmp(name, "set_tx_max") == 0) {
01467                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01468                         goto badarg;
01469                 __DB_OVFL(v1, UINT32_MAX);
01470                 return (__txn_set_tx_max(dbenv, (u_int32_t)v1));
01471         }
01472 
01473         if (strcasecmp(name, "set_txn_timeout") == 0) {
01474                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
01475                         goto badarg;
01476                 __DB_OVFL(v1, UINT32_MAX);
01477                 return (__lock_set_env_timeout(
01478                     dbenv, (u_int32_t)v1, DB_SET_TXN_TIMEOUT));
01479         }
01480 
01481         if (strcasecmp(name, "set_verbose") == 0) {
01482                 if (sscanf(value, "%40s %c", arg, &v4) != 1)
01483                         goto badarg;
01484 
01485                 else if (strcasecmp(value, "db_verb_deadlock") == 0)
01486                         flags = DB_VERB_DEADLOCK;
01487                 else if (strcasecmp(value, "db_verb_recovery") == 0)
01488                         flags = DB_VERB_RECOVERY;
01489                 else if (strcasecmp(value, "db_verb_register") == 0)
01490                         flags = DB_VERB_REGISTER;
01491                 else if (strcasecmp(value, "db_verb_replication") == 0)
01492                         flags = DB_VERB_REPLICATION;
01493                 else if (strcasecmp(value, "db_verb_waitsfor") == 0)
01494                         flags = DB_VERB_WAITSFOR;
01495                 else
01496                         goto badarg;
01497                 return (__env_set_verbose(dbenv, flags, 1));
01498         }
01499 
01500         __db_err(dbenv, "unrecognized name-value pair: %s", s);
01501         return (EINVAL);
01502 
01503 badarg: __db_err(dbenv, "incorrect arguments for name-value pair: %s", s);
01504         return (EINVAL);
01505 
01506 toobig: __db_err(dbenv,
01507             "%s: %lu larger than maximum value %lu", s, __v, __max);
01508         return (EINVAL);
01509 }
01510 
01511 /*
01512  * __db_tmp_open --
01513  *      Create a temporary file.
01514  */
01515 static int
01516 __db_tmp_open(dbenv, tmp_oflags, path, fhpp)
01517         DB_ENV *dbenv;
01518         u_int32_t tmp_oflags;
01519         char *path;
01520         DB_FH **fhpp;
01521 {
01522         pid_t pid;
01523         db_threadid_t tid;
01524         int filenum, i, isdir, ret;
01525         char *firstx, *trv;
01526 
01527         /*
01528          * Check the target directory; if you have six X's and it doesn't
01529          * exist, this runs for a *very* long time.
01530          */
01531         if ((ret = __os_exists(path, &isdir)) != 0) {
01532                 __db_err(dbenv, "%s: %s", path, db_strerror(ret));
01533                 return (ret);
01534         }
01535         if (!isdir) {
01536                 __db_err(dbenv, "%s: %s", path, db_strerror(EINVAL));
01537                 return (EINVAL);
01538         }
01539 
01540         /* Build the path. */
01541         (void)strncat(path, PATH_SEPARATOR, 1);
01542         (void)strcat(path, DB_TRAIL);
01543 
01544         /* Replace the X's with the process ID (in decimal). */
01545         __os_id(dbenv, &pid, &tid);
01546         for (trv = path + strlen(path); *--trv == 'X'; pid /= 10)
01547                 *trv = '0' + (u_char)(pid % 10);
01548         firstx = trv + 1;
01549 
01550         /* Loop, trying to open a file. */
01551         for (filenum = 1;; filenum++) {
01552                 if ((ret = __os_open(dbenv, path,
01553                     tmp_oflags | DB_OSO_CREATE | DB_OSO_EXCL | DB_OSO_TEMP,
01554                     __db_omode(OWNER_RW), fhpp)) == 0)
01555                         return (0);
01556 
01557                 /*
01558                  * !!!:
01559                  * If we don't get an EEXIST error, then there's something
01560                  * seriously wrong.  Unfortunately, if the implementation
01561                  * doesn't return EEXIST for O_CREAT and O_EXCL regardless
01562                  * of other possible errors, we've lost.
01563                  */
01564                 if (ret != EEXIST) {
01565                         __db_err(dbenv,
01566                             "tmp_open: %s: %s", path, db_strerror(ret));
01567                         return (ret);
01568                 }
01569 
01570                 /*
01571                  * Generate temporary file names in a backwards-compatible way.
01572                  * If pid == 12345, the result is:
01573                  *   <path>/DB12345 (tried above, the first time through).
01574                  *   <path>/DBa2345 ...  <path>/DBz2345
01575                  *   <path>/DBaa345 ...  <path>/DBaz345
01576                  *   <path>/DBba345, and so on.
01577                  *
01578                  * XXX
01579                  * This algorithm is O(n**2) -- that is, creating 100 temporary
01580                  * files requires 5,000 opens, creating 1000 files requires
01581                  * 500,000.  If applications open a lot of temporary files, we
01582                  * could improve performance by switching to timestamp-based
01583                  * file names.
01584                  */
01585                 for (i = filenum, trv = firstx; i > 0; i = (i - 1) / 26)
01586                         if (*trv++ == '\0')
01587                                 return (EINVAL);
01588 
01589                 for (i = filenum; i > 0; i = (i - 1) / 26)
01590                         *--trv = 'a' + ((i - 1) % 26);
01591         }
01592         /* NOTREACHED */
01593 }

Generated on Sun Dec 25 12:14:24 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2