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 }