env_open.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: env__open_8c-source.html,v 1.1 2008/06/08 10:18:42 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <ctype.h>
00018 #include <errno.h>
00019 #include <stdlib.h>
00020 #include <string.h>
00021 #include <unistd.h>
00022 #endif
00023 
00024 #include "db_int.h"
00025 #include "db_page.h"
00026 #include "db_shash.h"
00027 #include "btree.h"
00028 #include "hash.h"
00029 #include "qam.h"
00030 #include "lock.h"
00031 #include "log.h"
00032 #include "mp.h"
00033 #include "txn.h"
00034 #include "clib.h"
00035 
00036 static int __dbenv_config __P((DB_ENV *, const char *, u_int32_t));
00037 static int __dbenv_refresh __P((DB_ENV *));
00038 static int __db_home __P((DB_ENV *, const char *, u_int32_t));
00039 static int __db_parse __P((DB_ENV *, char *));
00040 static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, DB_FH *));
00041 
00042 /*
00043  * CDB_db_version --
00044  *      Return version information.
00045  */
00046 char *
00047 CDB_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  * CDB___dbenv_open --
00061  *      Initialize an environment.
00062  *
00063  * PUBLIC: int CDB___dbenv_open __P((DB_ENV *, const char *, u_int32_t, int));
00064  */
00065 int
00066 CDB___dbenv_open(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_ENV *rm_dbenv;
00073         int ret;
00074 
00075 #undef  OKFLAGS
00076 #define OKFLAGS                                                         \
00077         DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG |          \
00078         DB_INIT_MPOOL | DB_INIT_TXN | DB_LOCKDOWN | DB_NOMMAP |         \
00079         DB_PRIVATE | DB_RECOVER | DB_RECOVER_FATAL | DB_SYSTEM_MEM |    \
00080         DB_THREAD | DB_TXN_NOSYNC | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
00081 #undef  OKFLAGS_CDB
00082 #define OKFLAGS_CDB                                                     \
00083         DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_LOCKDOWN |         \
00084         DB_NOMMAP | DB_PRIVATE | DB_SYSTEM_MEM | DB_THREAD |            \
00085         DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
00086 
00087         if ((ret = CDB___db_fchk(dbenv, "DBENV->open", flags, OKFLAGS)) != 0)
00088                 return (ret);
00089         if (LF_ISSET(DB_INIT_CDB) &&
00090             (ret = CDB___db_fchk(dbenv, "DBENV->open", flags, OKFLAGS_CDB)) != 0)
00091                 return (ret);
00092         if ((ret = CDB___db_fcchk(dbenv,
00093             "DBENV->open", flags, DB_PRIVATE, DB_SYSTEM_MEM)) != 0)
00094                 return (ret);
00095 
00096         /*
00097          * If we're doing recovery, destroy the environment so that we create
00098          * all the regions from scratch.  I'd like to reuse already created
00099          * regions, but that's hard.  We would have to create the environment
00100          * region from scratch, at least, as we have no way of knowing if its
00101          * linked lists are corrupted.
00102          *
00103          * I suppose we could set flags while modifying those links, but that
00104          * is going to be difficult to get right.  The major concern I have
00105          * is if the application stomps the environment with a rogue pointer.
00106          * We have no way of detecting that, and we could be forced into a
00107          * situation where we start up and then crash, repeatedly.
00108          *
00109          * Note that we do not check any flags like DB_PRIVATE before calling
00110          * remove.  We don't care if the current environment was private or
00111          * not, we just want to nail any files that are left-over for whatever
00112          * reason, from whatever session.
00113          */
00114         if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) {
00115                 if ((ret = CDB_db_env_create(&rm_dbenv, 0)) != 0)
00116                         return (ret);
00117                 if ((ret = dbenv->remove(rm_dbenv, db_home, DB_FORCE)) != 0)
00118                         return (ret);
00119         }
00120 
00121         /* Initialize the DB_ENV structure. */
00122         if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0)
00123                 goto err;
00124 
00125         /* Convert the DBENV->open flags to internal flags. */
00126         if (LF_ISSET(DB_CREATE))
00127                 F_SET(dbenv, DB_ENV_CREATE);
00128         if (LF_ISSET(DB_LOCKDOWN))
00129                 F_SET(dbenv, DB_ENV_LOCKDOWN);
00130         if (LF_ISSET(DB_NOMMAP))
00131                 F_SET(dbenv, DB_ENV_NOMMAP);
00132         if (LF_ISSET(DB_PRIVATE))
00133                 F_SET(dbenv, DB_ENV_PRIVATE);
00134         if (LF_ISSET(DB_SYSTEM_MEM))
00135                 F_SET(dbenv, DB_ENV_SYSTEM_MEM);
00136         if (LF_ISSET(DB_THREAD))
00137                 F_SET(dbenv, DB_ENV_THREAD);
00138         if (LF_ISSET(DB_TXN_NOSYNC))
00139                 F_SET(dbenv, DB_ENV_TXN_NOSYNC);
00140 
00141         /* Default permissions are read-write for both owner and group. */
00142         dbenv->db_mode = mode == 0 ? CDB___db_omode("rwrw--") : mode;
00143 
00144         /* Initialize for CDB product. */
00145         if (LF_ISSET(DB_INIT_CDB)) {
00146                 LF_SET(DB_INIT_LOCK);
00147                 F_SET(dbenv, DB_ENV_CDB);
00148         }
00149 
00150         /* Create/join the environment. */
00151         if ((ret = CDB___db_e_attach(dbenv)) != 0)
00152                 goto err;
00153 
00154         /*
00155          * Initialize the subsystems.  Transactions imply logging but do not
00156          * imply locking.  While almost all applications want both locking
00157          * and logging, it would not be unreasonable for a single threaded
00158          * process to want transactions for atomicity guarantees, but not
00159          * necessarily need concurrency.
00160          */
00161         if (LF_ISSET(DB_INIT_MPOOL))
00162                 if ((ret = CDB___memp_open(dbenv)) != 0)
00163                         goto err;
00164         if (LF_ISSET(DB_INIT_LOG | DB_INIT_TXN))
00165                 if ((ret = CDB___log_open(dbenv)) != 0)
00166                         goto err;
00167         if (LF_ISSET(DB_INIT_LOCK))
00168                 if ((ret = CDB___lock_open(dbenv)) != 0)
00169                         goto err;
00170         if (LF_ISSET(DB_INIT_TXN)) {
00171                 if ((ret = CDB___txn_open(dbenv)) != 0)
00172                         goto err;
00173 
00174                 /*
00175                  * If the application is running with transactions, initialize
00176                  * the function tables.
00177                  */
00178                 if ((ret = CDB___bam_init_recover(dbenv)) != 0)
00179                         goto err;
00180                 if ((ret = CDB___crdel_init_recover(dbenv)) != 0)
00181                         goto err;
00182                 if ((ret = CDB___db_init_recover(dbenv)) != 0)
00183                         goto err;
00184                 if ((ret = CDB___ham_init_recover(dbenv)) != 0)
00185                         goto err;
00186                 if ((ret = CDB___log_init_recover(dbenv)) != 0)
00187                         goto err;
00188                 if ((ret = CDB___qam_init_recover(dbenv)) != 0)
00189                         goto err;
00190                 if ((ret = CDB___txn_init_recover(dbenv)) != 0)
00191                         goto err;
00192 
00193                 /*
00194                  * If the application specified their own recovery
00195                  * initialization function, call it.
00196                  */
00197                 if (dbenv->db_recovery_init != NULL &&
00198                     (ret = dbenv->db_recovery_init(dbenv)) != 0)
00199                         goto err;
00200 
00201                 /* Perform recovery for any previous run. */
00202                 if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
00203                     (ret = CDB___db_apprec(dbenv,
00204                     LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0)
00205                         goto err;
00206         }
00207         return (0);
00208 
00209 err:    (void)__dbenv_refresh(dbenv);
00210         return (ret);
00211 }
00212 
00213 /*
00214  * CDB___dbenv_remove --
00215  *      Discard an environment.
00216  *
00217  * PUBLIC: int CDB___dbenv_remove __P((DB_ENV *, const char *, u_int32_t));
00218  */
00219 int
00220 CDB___dbenv_remove(dbenv, db_home, flags)
00221         DB_ENV *dbenv;
00222         const char *db_home;
00223         u_int32_t flags;
00224 {
00225         int ret, t_ret;
00226 
00227 #undef  OKFLAGS
00228 #define OKFLAGS                                                         \
00229         DB_FORCE | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
00230 
00231         /* Validate arguments. */
00232         if ((ret = CDB___db_fchk(dbenv, "DBENV->remove", flags, OKFLAGS)) != 0)
00233                 return (ret);
00234 
00235         /* Initialize the DB_ENV structure. */
00236         if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0)
00237                 goto err;
00238 
00239         /* Remove the environment. */
00240         ret = CDB___db_e_remove(dbenv, LF_ISSET(DB_FORCE) ? 1 : 0);
00241 
00242         /* Discard any resources we've acquired. */
00243 err:    if ((t_ret = __dbenv_refresh(dbenv)) != 0 && ret == 0)
00244                 ret = t_ret;
00245 
00246         memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV));
00247         CDB___os_free(dbenv, sizeof(DB_ENV));
00248 
00249         return (ret);
00250 }
00251 
00252 /*
00253  * __dbenv_config --
00254  *      Initialize the DB_ENV structure.
00255  */
00256 static int
00257 __dbenv_config(dbenv, db_home, flags)
00258         DB_ENV *dbenv;
00259         const char *db_home;
00260         u_int32_t flags;
00261 {
00262         FILE *fp;
00263         int ret;
00264         char *lp, buf[MAXPATHLEN * 2];
00265 
00266         /* Set the database home. */
00267         if ((ret = __db_home(dbenv, db_home, flags)) != 0)
00268                 return (ret);
00269 
00270         /*
00271          * Parse the config file.
00272          *
00273          * !!!
00274          * Don't use sprintf(3)/snprintf(3) -- the former is dangerous, and
00275          * the latter isn't standard, and we're manipulating strings handed
00276          * us by the application.
00277          */
00278         if (dbenv->db_home != NULL) {
00279 #define CONFIG_NAME     "/DB_CONFIG"
00280                 if (strlen(dbenv->db_home) +
00281                     strlen(CONFIG_NAME) + 1 > sizeof(buf)) {
00282                         ret = ENAMETOOLONG;
00283                         return (ret);
00284                 }
00285                 (void)strcpy(buf, dbenv->db_home);
00286                 (void)strcat(buf, CONFIG_NAME);
00287                 if ((fp = fopen(buf, "r")) != NULL) {
00288                         while (fgets(buf, sizeof(buf), fp) != NULL) {
00289                                 if ((lp = strchr(buf, '\n')) == NULL) {
00290                                         CDB___db_err(dbenv,
00291                                             "%s: line too long", CONFIG_NAME);
00292                                         (void)fclose(fp);
00293                                         ret = EINVAL;
00294                                         return (ret);
00295                                 }
00296                                 *lp = '\0';
00297                                 if (buf[0] == '\0' ||
00298                                     buf[0] == '#' || isspace((int)buf[0]))
00299                                         continue;
00300 
00301                                 if ((ret = __db_parse(dbenv, buf)) != 0) {
00302                                         (void)fclose(fp);
00303                                         return (ret);
00304                                 }
00305                         }
00306                         (void)fclose(fp);
00307                 }
00308         }
00309 
00310         /* Set up the tmp directory path. */
00311         if (dbenv->db_tmp_dir == NULL && (ret = CDB___os_tmpdir(dbenv, flags)) != 0)
00312                 return (ret);
00313 
00314         /*
00315          * The locking file descriptor is rarely on.  Set the fd to -1, not
00316          * because it's ever tested, but to make sure we catch mistakes.
00317          */
00318         if ((ret =
00319             CDB___os_calloc(dbenv,
00320                 1, sizeof(*dbenv->lockfhp), &dbenv->lockfhp)) != 0)
00321                 return (ret);
00322         dbenv->lockfhp->fd = -1;
00323 
00324         /*
00325          * Flag that the DB_ENV structure has been initialized.  Note, this
00326          * must be set before calling into the subsystems as it's used during
00327          * file naming.
00328          */
00329         F_SET(dbenv, DB_ENV_OPEN_CALLED);
00330 
00331         return (0);
00332 }
00333 
00334 /*
00335  * CDB___dbenv_close --
00336  *      DB_ENV destructor.
00337  *
00338  * PUBLIC: int CDB___dbenv_close __P((DB_ENV *, u_int32_t));
00339  */
00340 int
00341 CDB___dbenv_close(dbenv, flags)
00342         DB_ENV *dbenv;
00343         u_int32_t flags;
00344 {
00345         int ret;
00346 
00347         COMPQUIET(flags, 0);
00348 
00349         PANIC_CHECK(dbenv);
00350 
00351         ret = __dbenv_refresh(dbenv);
00352 
00353         /* Discard the structure if we allocated it. */
00354         if (!F_ISSET(dbenv, DB_ENV_USER_ALLOC)) {
00355                 memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV));
00356                 CDB___os_free(dbenv, sizeof(DB_ENV));
00357         }
00358 
00359         return (ret);
00360 }
00361 
00362 /*
00363  * __dbenv_refresh --
00364  *      Refresh the DB_ENV structure, releasing any allocated resources.
00365  */
00366 static int
00367 __dbenv_refresh(dbenv)
00368         DB_ENV *dbenv;
00369 {
00370         int ret, t_ret;
00371         char **p;
00372 
00373         ret = 0;
00374 
00375         /*
00376          * Close subsystems, in the reverse order they were opened (txn
00377          * must be first, it may want to discard locks and flush the log).
00378          */
00379         if (TXN_ON(dbenv)) {
00380                 if ((t_ret = CDB___txn_close(dbenv)) != 0 && ret == 0)
00381                         ret = t_ret;
00382         }
00383 
00384         if (LOCKING_ON(dbenv)) {
00385                 if ((t_ret = CDB___lock_close(dbenv)) != 0 && ret == 0)
00386                         ret = t_ret;
00387         }
00388         CDB___lock_dbenv_close(dbenv);
00389 
00390         if (LOGGING_ON(dbenv)) {
00391                 if ((t_ret = CDB___log_close(dbenv)) != 0 && ret == 0)
00392                         ret = t_ret;
00393         }
00394 
00395         if (MPOOL_ON(dbenv)) {
00396                 if ((t_ret = CDB___memp_close(dbenv)) != 0 && ret == 0)
00397                         ret = t_ret;
00398         }
00399 
00400         /* Detach from the region. */
00401         if (dbenv->reginfo != NULL) {
00402                 if ((t_ret = CDB___db_e_detach(dbenv, 0)) != 0 && ret == 0)
00403                         ret = t_ret;
00404                 /*
00405                  * !!!
00406                  * Don't free dbenv->reginfo or set the reference to NULL,
00407                  * that was done by CDB___db_e_detach().
00408                  */
00409         }
00410 
00411         /* Clean up the structure. */
00412         dbenv->db_panic = 0;
00413 
00414         if (dbenv->db_home != NULL) {
00415                 CDB___os_freestr(dbenv->db_home);
00416                 dbenv->db_home = NULL;
00417         }
00418         if (dbenv->db_log_dir != NULL) {
00419                 CDB___os_freestr(dbenv->db_log_dir);
00420                 dbenv->db_log_dir = NULL;
00421         }
00422         if (dbenv->db_tmp_dir != NULL) {
00423                 CDB___os_freestr(dbenv->db_tmp_dir);
00424                 dbenv->db_tmp_dir = NULL;
00425         }
00426         if (dbenv->db_data_dir != NULL) {
00427                 for (p = dbenv->db_data_dir; *p != NULL; ++p)
00428                         CDB___os_freestr(*p);
00429                 CDB___os_free(dbenv->db_data_dir,
00430                     dbenv->data_cnt * sizeof(char **));
00431                 dbenv->db_data_dir = NULL;
00432         }
00433         dbenv->data_cnt = dbenv->data_next = 0;
00434 
00435         dbenv->db_mode = 0;
00436 
00437         if (dbenv->lockfhp != NULL) {
00438                 CDB___os_free(dbenv->lockfhp, sizeof(*dbenv->lockfhp));
00439                 dbenv->lockfhp = NULL;
00440         }
00441 
00442         if (dbenv->dtab != NULL) {
00443                 CDB___os_free(dbenv->dtab,
00444                     dbenv->dtab_size * sizeof(dbenv->dtab[0]));
00445                 dbenv->dtab = NULL;
00446                 dbenv->dtab_size = 0;
00447         }
00448 
00449         dbenv->mp_mmapsize = 0;
00450         dbenv->links.tqe_next = NULL;
00451         dbenv->links.tqe_prev = NULL;
00452         dbenv->xa_rmid = 0;
00453         dbenv->xa_txn = 0;
00454 
00455         F_CLR(dbenv, ~(DB_ENV_STANDALONE | DB_ENV_USER_ALLOC));
00456 
00457         return (ret);
00458 }
00459 
00460 #define DB_ADDSTR(add) {                                                \
00461         if ((add) != NULL) {                                            \
00462                 /* If leading slash, start over. */                     \
00463                 if (CDB___os_abspath(add)) {                            \
00464                         p = str;                                        \
00465                         slash = 0;                                      \
00466                 }                                                       \
00467                 /* Append to the current string. */                     \
00468                 len = strlen(add);                                      \
00469                 if (slash)                                              \
00470                         *p++ = PATH_SEPARATOR[0];                       \
00471                 memcpy(p, add, len);                                    \
00472                 p += len;                                               \
00473                 slash = strchr(PATH_SEPARATOR, p[-1]) == NULL;          \
00474         }                                                               \
00475 }
00476 
00477 /*
00478  * CDB___db_appname --
00479  *      Given an optional DB environment, directory and file name and type
00480  *      of call, build a path based on the DBENV->open rules, and return
00481  *      it in allocated space.
00482  *
00483  * PUBLIC: int CDB___db_appname __P((DB_ENV *, APPNAME,
00484  * PUBLIC:    const char *, const char *, u_int32_t, DB_FH *, char **));
00485  */
00486 int
00487 CDB___db_appname(dbenv, appname, dir, file, tmp_oflags, fhp, namep)
00488         DB_ENV *dbenv;
00489         APPNAME appname;
00490         const char *dir, *file;
00491         u_int32_t tmp_oflags;
00492         DB_FH *fhp;
00493         char **namep;
00494 {
00495         DB_ENV etmp;
00496         size_t len, str_len;
00497         int data_entry, ret, slash, tmp_create, tmp_free;
00498         const char *a, *b, *c;
00499         char *p, *str;
00500 
00501         a = b = c = NULL;
00502         data_entry = -1;
00503         tmp_create = tmp_free = 0;
00504 
00505         /*
00506          * We don't return a name when creating temporary files, just a
00507          * file handle.  Default to an error now.
00508          */
00509         if (fhp != NULL)
00510                 F_CLR(fhp, DB_FH_VALID);
00511         if (namep != NULL)
00512                 *namep = NULL;
00513 
00514         /*
00515          * Absolute path names are never modified.  If the file is an absolute
00516          * path, we're done.  If the directory is, simply append the file and
00517          * return.
00518          */
00519         if (file != NULL && CDB___os_abspath(file))
00520                 return (CDB___os_strdup(dbenv, file, namep));
00521         if (dir != NULL && CDB___os_abspath(dir)) {
00522                 a = dir;
00523                 goto done;
00524         }
00525 
00526         /*
00527          * DB_ENV  DIR     APPNAME         RESULT
00528          * -------------------------------------------
00529          * null    null    none            <tmp>/file
00530          * null    set     none            DIR/file
00531          * set     null    none            DB_HOME/file
00532          * set     set     none            DB_HOME/DIR/file
00533          *
00534          * DB_ENV  FILE    APPNAME         RESULT
00535          * -------------------------------------------
00536          * null    null    DB_APP_DATA     <tmp>/<create>
00537          * null    set     DB_APP_DATA     ./file
00538          * set     null    DB_APP_DATA     <tmp>/<create>
00539          * set     set     DB_APP_DATA     DB_HOME/DB_DATA_DIR/file
00540          *
00541          * DB_ENV  DIR     APPNAME         RESULT
00542          * -------------------------------------------
00543          * null    null    DB_APP_LOG      <tmp>/file
00544          * null    set     DB_APP_LOG      DIR/file
00545          * set     null    DB_APP_LOG      DB_HOME/DB_LOG_DIR/file
00546          * set     set     DB_APP_LOG      DB_HOME/DB_LOG_DIR/DIR/file
00547          *
00548          * DB_ENV          APPNAME         RESULT
00549          * -------------------------------------------
00550          * null            DB_APP_TMP*     <tmp>/<create>
00551          * set             DB_APP_TMP*     DB_HOME/DB_TMP_DIR/<create>
00552          */
00553 retry:  switch (appname) {
00554         case DB_APP_NONE:
00555                 if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
00556                         if (dir == NULL)
00557                                 goto tmp;
00558                         a = dir;
00559                 } else {
00560                         a = dbenv->db_home;
00561                         b = dir;
00562                 }
00563                 break;
00564         case DB_APP_DATA:
00565                 if (dir != NULL) {
00566                         CDB___db_err(dbenv,
00567                             "DB_APP_DATA: illegal directory specification");
00568                         return (EINVAL);
00569                 }
00570 
00571                 if (file == NULL) {
00572                         tmp_create = 1;
00573                         goto tmp;
00574                 }
00575                 if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED))
00576                         a = PATH_DOT;
00577                 else {
00578                         a = dbenv->db_home;
00579                         if (dbenv->db_data_dir != NULL &&
00580                             (b = dbenv->db_data_dir[++data_entry]) == NULL) {
00581                                 data_entry = -1;
00582                                 b = dbenv->db_data_dir[0];
00583                         }
00584                 }
00585                 break;
00586         case DB_APP_LOG:
00587                 if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
00588                         if (dir == NULL)
00589                                 goto tmp;
00590                         a = dir;
00591                 } else {
00592                         a = dbenv->db_home;
00593                         b = dbenv->db_log_dir;
00594                         c = dir;
00595                 }
00596                 break;
00597         case DB_APP_TMP:
00598                 if (dir != NULL || file != NULL) {
00599                         CDB___db_err(dbenv,
00600                     "DB_APP_TMP: illegal directory or file specification");
00601                         return (EINVAL);
00602                 }
00603 
00604                 tmp_create = 1;
00605                 if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED))
00606                         goto tmp;
00607                 else {
00608                         a = dbenv->db_home;
00609                         b = dbenv->db_tmp_dir;
00610                 }
00611                 break;
00612         }
00613 
00614         /* Reference a file from the appropriate temporary directory. */
00615         if (0) {
00616 tmp:            if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
00617                         memset(&etmp, 0, sizeof(etmp));
00618                         if ((ret = CDB___os_tmpdir(&etmp, DB_USE_ENVIRON)) != 0)
00619                                 return (ret);
00620                         tmp_free = 1;
00621                         a = etmp.db_tmp_dir;
00622                 } else
00623                         a = dbenv->db_tmp_dir;
00624         }
00625 
00626 done:   len =
00627             (a == NULL ? 0 : strlen(a) + 1) +
00628             (b == NULL ? 0 : strlen(b) + 1) +
00629             (c == NULL ? 0 : strlen(c) + 1) +
00630             (file == NULL ? 0 : strlen(file) + 1);
00631 
00632         /*
00633          * Allocate space to hold the current path information, as well as any
00634          * temporary space that we're going to need to create a temporary file
00635          * name.
00636          */
00637 #define DB_TRAIL        "BDBXXXXXX"
00638         str_len = len + sizeof(DB_TRAIL) + 10;
00639         if ((ret = CDB___os_malloc(dbenv, str_len, NULL, &str)) != 0) {
00640                 if (tmp_free)
00641                         CDB___os_freestr(etmp.db_tmp_dir);
00642                 return (ret);
00643         }
00644 
00645         slash = 0;
00646         p = str;
00647         DB_ADDSTR(a);
00648         DB_ADDSTR(b);
00649         DB_ADDSTR(file);
00650         *p = '\0';
00651 
00652         /* Discard any space allocated to find the temp directory. */
00653         if (tmp_free) {
00654                 CDB___os_freestr(etmp.db_tmp_dir);
00655                 tmp_free = 0;
00656         }
00657 
00658         /*
00659          * If we're opening a data file, see if it exists.  If it does,
00660          * return it, otherwise, try and find another one to open.
00661          */
00662         if (data_entry != -1 && CDB___os_exists(str, NULL) != 0) {
00663                 CDB___os_free(str, str_len);
00664                 a = b = c = NULL;
00665                 goto retry;
00666         }
00667 
00668         /* Create the file if so requested. */
00669         if (tmp_create &&
00670             (ret = __db_tmp_open(dbenv, tmp_oflags, str, fhp)) != 0) {
00671                 CDB___os_free(str, str_len);
00672                 return (ret);
00673         }
00674 
00675         if (namep == NULL)
00676                 CDB___os_free(str, str_len);
00677         else
00678                 *namep = str;
00679         return (0);
00680 }
00681 
00682 /*
00683  * __db_home --
00684  *      Find the database home.
00685  */
00686 static int
00687 __db_home(dbenv, db_home, flags)
00688         DB_ENV *dbenv;
00689         const char *db_home;
00690         u_int32_t flags;
00691 {
00692         const char *p;
00693 
00694         /*
00695          * Use db_home by default, this allows utilities to reasonably
00696          * override the environment either explicitly or by using a -h
00697          * option.  Otherwise, use the environment if it's permitted
00698          * and initialized.
00699          */
00700         if ((p = db_home) == NULL &&
00701             (LF_ISSET(DB_USE_ENVIRON) ||
00702             (LF_ISSET(DB_USE_ENVIRON_ROOT) && CDB___os_isroot() == 0)) &&
00703             (p = getenv("DB_HOME")) != NULL && p[0] == '\0') {
00704                 CDB___db_err(dbenv, "illegal DB_HOME environment variable");
00705                 return (EINVAL);
00706         }
00707 
00708         return (p == NULL ? 0 : CDB___os_strdup(dbenv, p, &dbenv->db_home));
00709 }
00710 
00711 /*
00712  * __db_parse --
00713  *      Parse a single NAME VALUE pair.
00714  */
00715 static int
00716 __db_parse(dbenv, s)
00717         DB_ENV *dbenv;
00718         char *s;
00719 {
00720         u_long v1, v2, v3;
00721         u_int32_t flags;
00722         char *name, *p, *value, v4;
00723 
00724         /*
00725          * !!!
00726          * The value of 40 is hard-coded into format arguments to sscanf
00727          * below, it can't be changed here without changing it there, too.
00728          */
00729         char arg[40];
00730 
00731         /*
00732          * Name/value pairs are parsed as two white-space separated strings.
00733          * Leading and trailing white-space is trimmed from the value, but
00734          * it may contain embedded white-space.  Note: we use the isspace(3)
00735          * macro because it's more portable, but that means that you can use
00736          * characters like form-feed to separate the strings.
00737          */
00738         name = s;
00739         for (p = name; *p != '\0' && !isspace((int)*p); ++p)
00740                 ;
00741         if (*p == '\0' || p == name)
00742                 goto illegal;
00743         *p = '\0';
00744         for (++p; isspace((int)*p); ++p)
00745                 ;
00746         if (*p == '\0')
00747                 goto illegal;
00748         value = p;
00749         for (++p; *p != '\0'; ++p)
00750                 ;
00751         for (--p; isspace((int)*p); --p)
00752                 ;
00753         ++p;
00754         if (p == value) {
00755 illegal:        CDB___db_err(dbenv, "mis-formatted name-value pair: %s", s);
00756                 return (EINVAL);
00757         }
00758         *p = '\0';
00759 
00760         if (!strcasecmp(name, "set_cachesize")) {
00761                 if (sscanf(value, "%lu %lu %lu %c", &v1, &v2, &v3, &v4) != 3)
00762                         goto badarg;
00763                 return (dbenv->set_cachesize(dbenv, v1, v2, v3));
00764         }
00765 
00766         if (!strcasecmp(name, "set_data_dir") ||
00767             !strcasecmp(name, "db_data_dir"))           /* Compatibility. */
00768                 return (dbenv->set_data_dir(dbenv, value));
00769 
00770         if (!strcasecmp(name, "set_lg_bsize")) {
00771                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
00772                         goto badarg;
00773                 return (dbenv->set_lg_bsize(dbenv, v1));
00774         }
00775 
00776         if (!strcasecmp(name, "set_lg_max")) {
00777                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
00778                         goto badarg;
00779                 return (dbenv->set_lg_max(dbenv, v1));
00780         }
00781 
00782         if (!strcasecmp(name, "set_lg_dir") ||
00783             !strcasecmp(name, "db_log_dir"))            /* Compatibility. */
00784                 return (dbenv->set_lg_dir(dbenv, value));
00785 
00786         if (!strcasecmp(name, "set_lk_detect")) {
00787                 if (sscanf(value, "%40s %c", arg, &v4) != 1)
00788                         goto badarg;
00789                 if (!strcasecmp(value, "db_lock_default"))
00790                         flags = DB_LOCK_DEFAULT;
00791                 else if (!strcasecmp(value, "db_lock_oldest"))
00792                         flags = DB_LOCK_OLDEST;
00793                 else if (!strcasecmp(value, "db_lock_random"))
00794                         flags = DB_LOCK_RANDOM;
00795                 else if (!strcasecmp(value, "db_lock_youngest"))
00796                         flags = DB_LOCK_YOUNGEST;
00797                 else
00798                         goto badarg;
00799                 return (dbenv->set_lk_detect(dbenv, flags));
00800         }
00801 
00802         if (!strcasecmp(name, "set_lk_max")) {
00803                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
00804                         goto badarg;
00805                 return (dbenv->set_lk_max(dbenv, v1));
00806         }
00807 
00808         if (!strcasecmp(name, "set_mp_mmapsize")) {
00809                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
00810                         goto badarg;
00811                 return (dbenv->set_mp_mmapsize(dbenv, v1));
00812         }
00813 
00814         if (!strcasecmp(name, "set_region_init")) {
00815                 if (sscanf(value, "%lu %c", &v1, &v4) != 1 || v1 != 1)
00816                         goto badarg;
00817                 return (CDB_db_env_set_region_init(v1));
00818         }
00819 
00820         if (!strcasecmp(name, "set_shm_key")) {
00821                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
00822                         goto badarg;
00823                 return (dbenv->set_shm_key(dbenv, (long)v1));
00824         }
00825 
00826         if (!strcasecmp(name, "set_tas_spins")) {
00827                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
00828                         goto badarg;
00829                 return (CDB_db_env_set_tas_spins(v1));
00830         }
00831 
00832         if (!strcasecmp(name, "set_tmp_dir") ||
00833             !strcasecmp(name, "db_tmp_dir"))            /* Compatibility.*/
00834                 return (dbenv->set_tmp_dir(dbenv, value));
00835 
00836         if (!strcasecmp(name, "set_tx_max")) {
00837                 if (sscanf(value, "%lu %c", &v1, &v4) != 1)
00838                         goto badarg;
00839                 return (dbenv->set_tx_max(dbenv, v1));
00840         }
00841 
00842         if (!strcasecmp(name, "set_verbose")) {
00843                 if (sscanf(value, "%40s %c", arg, &v4) != 1)
00844                         goto badarg;
00845 
00846                 if (!strcasecmp(value, "db_verb_chkpoint"))
00847                         flags = DB_VERB_CHKPOINT;
00848                 else if (!strcasecmp(value, "db_verb_deadlock"))
00849                         flags = DB_VERB_DEADLOCK;
00850                 else if (!strcasecmp(value, "db_verb_recovery"))
00851                         flags = DB_VERB_RECOVERY;
00852                 else if (!strcasecmp(value, "db_verb_waitsfor"))
00853                         flags = DB_VERB_WAITSFOR;
00854                 else
00855                         goto badarg;
00856                 return (dbenv->set_verbose(dbenv, flags, 1));
00857         }
00858 
00859         CDB___db_err(dbenv, "unrecognized name-value pair: %s", s);
00860         return (EINVAL);
00861 
00862 badarg: CDB___db_err(dbenv, "incorrect arguments for name-value pair: %s", s);
00863         return (EINVAL);
00864 }
00865 
00866 /*
00867  * __db_tmp_open --
00868  *      Create a temporary file.
00869  */
00870 static int
00871 __db_tmp_open(dbenv, tmp_oflags, path, fhp)
00872         DB_ENV *dbenv;
00873         u_int32_t tmp_oflags;
00874         char *path;
00875         DB_FH *fhp;
00876 {
00877         u_long pid;
00878         int mode, isdir, ret;
00879         const char *p;
00880         char *trv;
00881 
00882         /*
00883          * Check the target directory; if you have six X's and it doesn't
00884          * exist, this runs for a *very* long time.
00885          */
00886         if ((ret = CDB___os_exists(path, &isdir)) != 0) {
00887                 CDB___db_err(dbenv, "%s: %s", path, CDB_db_strerror(ret));
00888                 return (ret);
00889         }
00890         if (!isdir) {
00891                 CDB___db_err(dbenv, "%s: %s", path, CDB_db_strerror(EINVAL));
00892                 return (EINVAL);
00893         }
00894 
00895         /* Build the path. */
00896         for (trv = path; *trv != '\0'; ++trv)
00897                 ;
00898         *trv = PATH_SEPARATOR[0];
00899         for (p = DB_TRAIL; (*++trv = *p) != '\0'; ++p)
00900                 ;
00901 
00902         /*
00903          * Replace the X's with the process ID.  Pid should be a pid_t,
00904          * but we use unsigned long for portability.
00905          */
00906         for (pid = getpid(); *--trv == 'X'; pid /= 10)
00907                 switch (pid % 10) {
00908                 case 0: *trv = '0'; break;
00909                 case 1: *trv = '1'; break;
00910                 case 2: *trv = '2'; break;
00911                 case 3: *trv = '3'; break;
00912                 case 4: *trv = '4'; break;
00913                 case 5: *trv = '5'; break;
00914                 case 6: *trv = '6'; break;
00915                 case 7: *trv = '7'; break;
00916                 case 8: *trv = '8'; break;
00917                 case 9: *trv = '9'; break;
00918                 }
00919         ++trv;
00920 
00921         /* Set up open flags and mode. */
00922         mode = CDB___db_omode("rw----");
00923 
00924         /* Loop, trying to open a file. */
00925         for (;;) {
00926                 if ((ret = CDB___os_open(dbenv, path,
00927                     tmp_oflags | DB_OSO_CREATE | DB_OSO_EXCL, mode, fhp)) == 0)
00928                         return (0);
00929 
00930                 /*
00931                  * !!!:
00932                  * If we don't get an EEXIST error, then there's something
00933                  * seriously wrong.  Unfortunately, if the implementation
00934                  * doesn't return EEXIST for O_CREAT and O_EXCL regardless
00935                  * of other possible errors, we've lost.
00936                  */
00937                 if (ret != EEXIST) {
00938                         CDB___db_err(dbenv,
00939                             "tmp_open: %s: %s", path, CDB_db_strerror(ret));
00940                         return (ret);
00941                 }
00942 
00943                 /*
00944                  * Tricky little algorithm for backward compatibility.
00945                  * Assumes sequential ordering of lower-case characters.
00946                  */
00947                 for (;;) {
00948                         if (*trv == '\0')
00949                                 return (EINVAL);
00950                         if (*trv == 'z')
00951                                 *trv++ = 'a';
00952                         else {
00953                                 if (isdigit((int)*trv))
00954                                         *trv = 'a';
00955                                 else
00956                                         ++*trv;
00957                                 break;
00958                         }
00959                 }
00960         }
00961         /* NOTREACHED */
00962 }

Generated on Sun Jun 8 10:56:37 2008 for GNUmifluz by  doxygen 1.5.5