db_appinit.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996, 1997, 1998
* Sleepycat Software. All rights reserved.
*/
#include "config.h"
#ifndef lint
static const char sccsid[] = "@(#)db_appinit.c 10.66 (Sleepycat) 12/7/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#endif
#include "db_int.h"
#include "shqueue.h"
#include "db_page.h"
#include "btree.h"
#include "hash.h"
#include "log.h"
#include "txn.h"
#include "clib_ext.h"
#include "common_ext.h"
/*
* This conflict array is used for concurrent db access (cdb). It
* uses the same locks as the db_rw_conflict array, but adds an IW
* mode to be used for write cursors.
*/
static u_int8_t const db_cdb_conflicts[] = {
/* N R W IW */
/* N */ 0, 0, 0, 0,
/* R */ 0, 0, 1, 0,
/* W */ 0, 1, 1, 1,
/* IW */ 0, 0, 1, 1
};
/*
* db_version --
* Return version information.
*/
char *
{
return ((char *)DB_VERSION_STRING);
}
/*
* db_appinit --
* Initialize the application environment.
*/
int
const char *db_home;
char * const *db_config;
{
char * const *p;
/* Validate arguments. */
return (EINVAL);
#ifdef HAVE_SPINLOCKS
#define OKFLAGS \
#else
#define OKFLAGS \
#endif
return (ret);
/* Transactions imply logging. */
if (LF_ISSET(DB_INIT_TXN))
/* Convert the db_appinit(3) flags. */
/* Set the database home. */
goto err;
/* Parse the config array. */
goto err;
/*
* Parse the config file.
*
* XXX
* Don't use sprintf(3)/snprintf(3) -- the former is dangerous, and
* the latter isn't standard, and we're manipulating strings handed
* us by the application.
*/
#define CONFIG_NAME "/DB_CONFIG"
ret = ENAMETOOLONG;
goto err;
}
"%s: line too long", CONFIG_NAME);
goto err;
}
*lp = '\0';
if (buf[0] == '\0' ||
continue;
goto err;
}
}
}
/* Set up the tmp directory path. */
goto err;
/*
* Flag that the structure has been initialized by the application.
* Note, this must be set before calling into the subsystems as it
* is used when we're doing file naming.
*/
/*
* If we are doing recovery, remove all the old shared memory
* regions.
*/
goto err;
goto err;
goto err;
goto err;
}
/*
* Create the new shared regions.
*
* Default permissions are read-write for both owner and group.
*/
if (LF_ISSET(DB_INIT_CDB)) {
goto err;
}
goto err;
}
goto err;
goto err;
goto err;
goto err;
/*
* If the application is running with transactions, initialize the
* function tables. Once that's done, do recovery for any previous
* run.
*/
if (LF_ISSET(DB_INIT_TXN)) {
goto err;
goto err;
goto err;
goto err;
goto err;
goto err;
}
return (ret);
(void)db_appexit(dbenv);
return (ret);
}
/*
* db_appexit --
* Close down the default application environment.
*/
int
{
char **p;
ret = 0;
/* Close subsystems. */
if (ret == 0)
if (ret == 0)
if (ret == 0)
if (ret == 0)
/* Clear initialized flag (after subsystems, it affects naming). */
/* Free allocated memory. */
for (; *p != NULL; ++p)
__os_freestr(*p);
}
return (ret);
}
/* If leading slash, start over. */ \
if (__os_abspath(str)) { \
p = start; \
slash = 0; \
} \
/* Append to the current string. */ \
if (slash) \
*p++ = PATH_SEPARATOR[0]; \
p += len; \
} \
}
/*
* __db_appname --
* Given an optional DB environment, directory and file name and type
* of call, build a path based on the db_appinit(3) rules, and return
* it in allocated space.
*
* PUBLIC: int __db_appname __P((DB_ENV *,
* PUBLIC: APPNAME, const char *, const char *, u_int32_t, int *, char **));
*/
int
int *fdp;
char **namep;
{
const char *a, *b, *c;
char *p, *start;
a = b = c = NULL;
data_entry = -1;
tmp_create = tmp_free = 0;
/*
* We don't return a name when creating temporary files, just an fd.
* Default to error now.
*/
*fdp = -1;
/*
* Absolute path names are never modified. If the file is an absolute
* path, we're done. If the directory is, simply append the file and
* return.
*/
a = dir;
goto done;
}
/*
* DB_ENV DIR APPNAME RESULT
* -------------------------------------------
* null null none <tmp>/file
*
* DB_ENV FILE APPNAME RESULT
* -------------------------------------------
* null null DB_APP_DATA <tmp>/<create>
* null set DB_APP_DATA ./file
* set null DB_APP_DATA <tmp>/<create>
* set set DB_APP_DATA DB_HOME/DB_DATA_DIR/file
*
* DB_ENV DIR APPNAME RESULT
* -------------------------------------------
* null null DB_APP_LOG <tmp>/file
* set null DB_APP_LOG DB_HOME/DB_LOG_DIR/file
* set set DB_APP_LOG DB_HOME/DB_LOG_DIR/DIR/file
*
* DB_ENV APPNAME RESULT
* -------------------------------------------
* null DB_APP_TMP* <tmp>/<create>
* set DB_APP_TMP* DB_HOME/DB_TMP_DIR/<create>
*/
case DB_APP_NONE:
goto tmp;
a = dir;
} else {
b = dir;
}
break;
case DB_APP_DATA:
"DB_APP_DATA: illegal directory specification");
return (EINVAL);
}
tmp_create = 1;
goto tmp;
}
a = PATH_DOT;
else {
data_entry = -1;
b = dbenv->db_data_dir[0];
}
}
break;
case DB_APP_LOG:
goto tmp;
a = dir;
} else {
b = dbenv->db_log_dir;
c = dir;
}
break;
case DB_APP_TMP:
"DB_APP_TMP: illegal directory or file specification");
return (EINVAL);
}
tmp_create = 1;
goto tmp;
else {
b = dbenv->db_tmp_dir;
}
break;
}
/* Reference a file from the appropriate temporary directory. */
if (0) {
return (ret);
tmp_free = 1;
a = etmp.db_tmp_dir;
} else
a = dbenv->db_tmp_dir;
}
/*
* Allocate space to hold the current path information, as well as any
* temporary space that we're going to need to create a temporary file
* name.
*/
#define DB_TRAIL "XXXXXX"
if ((ret =
if (tmp_free)
return (ret);
}
slash = 0;
p = start;
DB_ADDSTR(a);
DB_ADDSTR(b);
*p = '\0';
/* Discard any space allocated to find the temp directory. */
if (tmp_free) {
tmp_free = 0;
}
/*
* If we're opening a data file, see if it exists. If it does,
* return it, otherwise, try and find another one to open.
*/
a = b = c = NULL;
goto retry;
}
/* Create the file if so requested. */
if (tmp_create &&
return (ret);
}
else
return (0);
}
/*
* __db_home --
* Find the database home.
*/
static int
const char *db_home;
{
const char *p;
p = db_home;
/* Use the environment if it's permitted and initialized. */
#ifdef HAVE_GETUID
if (LF_ISSET(DB_USE_ENVIRON) ||
#else
if (LF_ISSET(DB_USE_ENVIRON)) {
#endif
p = db_home;
else if (p[0] == '\0') {
"illegal DB_HOME environment variable");
return (EINVAL);
}
}
if (p == NULL)
return (0);
}
/*
* __db_parse --
* Parse a single NAME VALUE pair.
*/
static int
__db_parse(dbenv, s)
char *s;
{
int ret;
/*
* We need to strdup the argument in case the caller passed us
* static data.
*/
return (ret);
/*
* Leading and trailing white-space is trimmed from the value, but
* it may contain embedded white-space. Note: we use the isspace(3)
* macro because it's more portable, but that means that you can use
* characters like form-feed to separate the strings.
*/
;
goto illegal;
*tp = '\0';
;
if (*tp == '\0')
goto illegal;
;
;
goto err;
}
*++tp = '\0';
sizeof(char **), &dbenv->db_data_dir)) != 0)
goto err;
goto err;
}
p = &dbenv->db_log_dir;
p = &dbenv->db_tmp_dir;
} else
goto err;
return (ret);
}
/*
* __db_tmp_open --
* Create a temporary file.
*/
static int
char *path;
int *fdp;
{
const char *p;
char *trv;
/*
* Check the target directory; if you have six X's and it doesn't
* exist, this runs for a *very* long time.
*/
return (ret);
}
if (!isdir) {
return (EINVAL);
}
/* Build the path. */
;
*trv = PATH_SEPARATOR[0];
;
/*
* Replace the X's with the process ID. Pid should be a pid_t,
* but we use unsigned long for portability.
*/
switch (pid % 10) {
case 0: *trv = '0'; break;
}
++trv;
/* Set up open flags and mode. */
/* Loop, trying to open a file. */
for (;;) {
return (0);
/*
* XXX:
* If we don't get an EEXIST error, then there's something
* seriously wrong. Unfortunately, if the implementation
* doesn't return EEXIST for O_CREAT and O_EXCL regardless
* of other possible errors, we've lost.
*/
return (ret);
}
/*
* Tricky little algorithm for backward compatibility.
* Assumes the ASCII ordering of lower-case characters.
*/
for (;;) {
if (*trv == '\0')
return (EINVAL);
if (*trv == 'z')
*trv++ = 'a';
else {
*trv = 'a';
else
++*trv;
break;
}
}
}
/* NOTREACHED */
}