/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ #include "db_config.h" #include "db_int.h" #include "dbinc/lock.h" #include "dbinc/log.h" #include "dbinc/mp.h" #include "dbinc/txn.h" #include "dbinc/db_page.h" #include "dbinc_auto/db_ext.h" /* * DB_CONFIG lines are processed primarily by interpreting the command * description tables initialized below. * * Most DB_CONFIG commands consist of a single token name followed by one or two * integer or string arguments. These commands are described by entries in the * config_descs[] array. * * The remaining, usually more complex, DB_CONFIG commands are handled by small * code blocks in __config_parse(). Many of those commands need to translate * option names to the integer values needed by the API configuration functions. * Below the __config_descs[] initialization there are many FN array * initializations which provide the mapping between user-specifiable strings * and internally-used integer values. Typically there is one of these mappings * defined for each complex DB_CONFIG command. Use __db_name_to_val() * to translate a string to its integer value. */ typedef enum { CFG_INT, /* The argument is 1 signed integer. */ CFG_LONG, /* The argument is 1 signed long int. */ CFG_UINT, /* The argument is 1 unsigned integer. */ CFG_2INT, /* The arguments are 2 signed integers. */ CFG_2UINT, /* The arguments are 2 unsigned integers. */ CFG_STRING /* The rest of the line is a string. */ } __db_config_type; typedef struct __db_config_desc { char *name; /* The name of a simple DB_CONFIG command. */ __db_config_type type; /* The enum describing its argument type(s). */ int (*func)(); /* The function to call with the argument(s). */ } CFG_DESC; /* These typedefs help eliminate lint warnings where "func" above is used. */ typedef int (*CFG_FUNC_STRING) __P((DB_ENV *, const char *)); typedef int (*CFG_FUNC_INT) __P((DB_ENV *, int)); typedef int (*CFG_FUNC_LONG) __P((DB_ENV *, long)); typedef int (*CFG_FUNC_UINT) __P((DB_ENV *, u_int32_t)); typedef int (*CFG_FUNC_2INT) __P((DB_ENV *, int, int)); typedef int (*CFG_FUNC_2UINT) __P((DB_ENV *, u_int32_t, u_int32_t)); /* * This table lists the simple DB_CONFIG configuration commands. It is sorted by * the command name, so that __config_scan() can bsearch() it. After making an * addition to this table, please be sure that it remains sorted. With vi or * vim, the following command line will do it: * :/^static const CFG_DESC config_descs/+1, /^}/-1 ! sort * * This table can contain aliases. Aliases have different names with identical * types and functions. At this time there are four aliases: * Outdated Name Current Name * db_data_dir set_data_dir * db_log_dir set_lg_dir * db_tmp_dir set_tmp_dir * set_tas_spins mutex_set_tas_spins */ static const CFG_DESC config_descs[] = { { "add_data_dir", CFG_STRING, __env_add_data_dir }, { "db_data_dir", CFG_STRING, __env_set_data_dir }, { "db_log_dir", CFG_STRING, __log_set_lg_dir }, { "db_tmp_dir", CFG_STRING, __env_set_tmp_dir }, { "mutex_set_align", CFG_UINT, __mutex_set_align }, { "mutex_set_increment", CFG_UINT, __mutex_set_increment }, { "mutex_set_init", CFG_UINT, __mutex_set_init }, { "mutex_set_max", CFG_UINT, __mutex_set_max }, { "mutex_set_tas_spins", CFG_UINT, __mutex_set_tas_spins }, { "rep_set_clockskew", CFG_2UINT, __rep_set_clockskew }, { "rep_set_limit", CFG_2UINT, __rep_set_limit }, { "rep_set_nsites", CFG_UINT, __rep_set_nsites_pp }, { "rep_set_priority", CFG_UINT, __rep_set_priority_pp }, { "rep_set_request", CFG_2UINT, __rep_set_request }, { "set_blob_dir", CFG_STRING, __env_set_blob_dir }, { "set_blob_threshold", CFG_2UINT, __env_set_blob_threshold }, { "set_cache_max", CFG_2UINT, __memp_set_cache_max }, { "set_create_dir", CFG_STRING, __env_set_create_dir }, { "set_data_dir", CFG_STRING, __env_set_data_dir }, { "set_data_len", CFG_UINT, __env_set_data_len }, { "set_intermediate_dir_mode",CFG_STRING, __env_set_intermediate_dir_mode }, { "set_lg_bsize", CFG_UINT, __log_set_lg_bsize }, { "set_lg_dir", CFG_STRING, __log_set_lg_dir }, { "set_lg_filemode", CFG_INT, __log_set_lg_filemode }, { "set_lg_max", CFG_UINT, __log_set_lg_max }, { "set_lg_regionmax", CFG_UINT, __log_set_lg_regionmax }, { "set_lk_max_lockers", CFG_UINT, __lock_set_lk_max_lockers }, { "set_lk_max_locks", CFG_UINT, __lock_set_lk_max_locks }, { "set_lk_max_objects", CFG_UINT, __lock_set_lk_max_objects }, { "set_lk_partitions", CFG_UINT, __lock_set_lk_partitions }, { "set_lk_tablesize", CFG_UINT, __lock_set_lk_tablesize }, { "set_memory_max", CFG_2UINT, __env_set_memory_max }, { "set_metadata_dir", CFG_STRING, __env_set_metadata_dir }, { "set_mp_max_openfd", CFG_INT, __memp_set_mp_max_openfd }, { "set_mp_max_write", CFG_2INT, __memp_set_mp_max_write }, { "set_mp_mmapsize", CFG_UINT, __memp_set_mp_mmapsize }, { "set_mp_mtxcount", CFG_UINT, __memp_set_mp_mtxcount }, { "set_mp_pagesize", CFG_UINT, __memp_set_mp_pagesize }, { "set_shm_key", CFG_LONG, __env_set_shm_key }, { "set_tas_spins", CFG_UINT, __mutex_set_tas_spins }, { "set_thread_count", CFG_UINT, __env_set_thread_count }, { "set_tmp_dir", CFG_STRING, __env_set_tmp_dir }, { "set_tx_max", CFG_UINT, __txn_set_tx_max } }; /* * Here are the option-name to option-value mappings used by complex commands. */ static const FN config_mem_init[] = { { (u_int32_t) DB_MEM_LOCK, "DB_MEM_LOCK" }, { (u_int32_t) DB_MEM_LOCKER, "DB_MEM_LOCKER" }, { (u_int32_t) DB_MEM_LOCKOBJECT, "DB_MEM_LOCKOBJECT" }, { (u_int32_t) DB_MEM_TRANSACTION, "DB_MEM_TRANSACTION" }, { (u_int32_t) DB_MEM_THREAD, "DB_MEM_THREAD" }, { (u_int32_t) DB_MEM_LOGID, "DB_MEM_LOGID" }, { 0, NULL } }; static const FN config_rep_config[] = { { DB_REP_CONF_AUTOINIT, "db_rep_conf_autoinit" }, { DB_REP_CONF_AUTOROLLBACK, "db_rep_conf_autorollback" }, { DB_REP_CONF_BULK, "db_rep_conf_bulk" }, { DB_REP_CONF_DELAYCLIENT, "db_rep_conf_delayclient" }, { DB_REP_CONF_ELECT_LOGLENGTH, "db_rep_conf_elect_loglength" }, { DB_REP_CONF_INMEM, "db_rep_conf_inmem" }, { DB_REP_CONF_LEASE, "db_rep_conf_lease" }, { DB_REP_CONF_NOWAIT, "db_rep_conf_nowait" }, { DB_REPMGR_CONF_2SITE_STRICT, "db_repmgr_conf_2site_strict" }, { DB_REPMGR_CONF_ELECTIONS, "db_repmgr_conf_elections" }, { DB_REPMGR_CONF_PREFMAS_CLIENT, "db_repmgr_conf_prefmas_client" }, { DB_REPMGR_CONF_PREFMAS_MASTER, "db_repmgr_conf_prefmas_master" }, { 0, NULL } }; static const FN config_rep_timeout[] = { { DB_REP_ACK_TIMEOUT, "db_rep_ack_timeout" }, { DB_REP_CHECKPOINT_DELAY, "db_rep_checkpoint_delay" }, { DB_REP_CONNECTION_RETRY, "db_rep_connection_retry" }, { DB_REP_ELECTION_TIMEOUT, "db_rep_election_timeout" }, { DB_REP_ELECTION_RETRY, "db_rep_election_retry" }, { DB_REP_FULL_ELECTION_TIMEOUT, "db_rep_full_election_timeout" }, { DB_REP_HEARTBEAT_MONITOR, "db_rep_heartbeat_monitor" }, { DB_REP_HEARTBEAT_SEND, "db_rep_heartbeat_send" }, { DB_REP_LEASE_TIMEOUT, "db_rep_lease_timeout" }, { 0, NULL } }; static const FN config_repmgr_ack_policy[] = { { DB_REPMGR_ACKS_ALL, "db_repmgr_acks_all" }, { DB_REPMGR_ACKS_ALL_AVAILABLE, "db_repmgr_acks_all_available" }, { DB_REPMGR_ACKS_ALL_PEERS, "db_repmgr_acks_all_peers" }, { DB_REPMGR_ACKS_NONE, "db_repmgr_acks_none" }, { DB_REPMGR_ACKS_ONE, "db_repmgr_acks_one" }, { DB_REPMGR_ACKS_ONE_PEER, "db_repmgr_acks_one_peer" }, { DB_REPMGR_ACKS_QUORUM, "db_repmgr_acks_quorum" }, { 0, NULL } }; static const FN config_repmgr_site[] = { { DB_BOOTSTRAP_HELPER, "db_bootstrap_helper" }, { DB_GROUP_CREATOR, "db_group_creator" }, { DB_LEGACY, "db_legacy" }, { DB_LOCAL_SITE, "db_local_site" }, { DB_REPMGR_PEER, "db_repmgr_peer" }, { 0, NULL } }; static const FN config_set_flags[] = { { DB_AUTO_COMMIT, "db_auto_commit" }, { DB_CDB_ALLDB, "db_cdb_alldb" }, { DB_DIRECT_DB, "db_direct_db" }, { DB_DSYNC_DB, "db_dsync_db" }, { DB_MULTIVERSION, "db_multiversion" }, { DB_NOLOCKING, "db_nolocking" }, { DB_NOMMAP, "db_nommap" }, { DB_NOPANIC, "db_nopanic" }, { DB_OVERWRITE, "db_overwrite" }, { DB_REGION_INIT, "db_region_init" }, { DB_TIME_NOTGRANTED, "db_time_notgranted" }, { DB_TXN_NOSYNC, "db_txn_nosync" }, { DB_TXN_NOWAIT, "db_txn_nowait" }, { DB_TXN_SNAPSHOT, "db_txn_snapshot" }, { DB_TXN_WRITE_NOSYNC, "db_txn_write_nosync" }, { DB_YIELDCPU, "db_yieldcpu" }, { 0, NULL } }; static const FN config_set_flags_forlog[] = { { DB_LOG_DIRECT, "db_direct_log" }, { DB_LOG_DSYNC, "db_dsync_log" }, { DB_LOG_AUTO_REMOVE, "db_log_autoremove" }, { DB_LOG_BLOB, "db_log_blob" }, { DB_LOG_IN_MEMORY, "db_log_inmemory" }, { DB_LOG_NOSYNC, "db_log_nosync" }, { 0, NULL } }; static const FN config_log_set_config[] = { { DB_LOG_DIRECT, "db_log_direct" }, { DB_LOG_DSYNC, "db_log_dsync" }, { DB_LOG_AUTO_REMOVE, "db_log_auto_remove" }, { DB_LOG_BLOB, "db_log_blob" }, { DB_LOG_IN_MEMORY, "db_log_in_memory" }, { DB_LOG_NOSYNC, "db_log_nosync" }, { DB_LOG_ZERO, "db_log_zero" }, { 0, NULL } }; static const FN config_set_lk_detect[] = { { DB_LOCK_DEFAULT, "db_lock_default" }, { DB_LOCK_EXPIRE, "db_lock_expire" }, { DB_LOCK_MAXLOCKS, "db_lock_maxlocks" }, { DB_LOCK_MAXWRITE, "db_lock_maxwrite" }, { DB_LOCK_MINLOCKS, "db_lock_minlocks" }, { DB_LOCK_MINWRITE, "db_lock_minwrite" }, { DB_LOCK_OLDEST, "db_lock_oldest" }, { DB_LOCK_RANDOM, "db_lock_random" }, { DB_LOCK_YOUNGEST, "db_lock_youngest" }, { 0, NULL } }; static const FN config_set_open_flags[] = { { DB_INIT_REP, "db_init_rep" }, { DB_PRIVATE, "db_private" }, { DB_REGISTER, "db_register" }, { DB_THREAD, "db_thread" }, { 0, NULL } }; static const FN config_set_verbose[] = { { DB_VERB_BACKUP, "db_verb_backup" }, { DB_VERB_DEADLOCK, "db_verb_deadlock" }, { DB_VERB_FILEOPS, "db_verb_fileops" }, { DB_VERB_FILEOPS_ALL, "db_verb_fileops_all" }, { DB_VERB_MVCC, "db_verb_mvcc" }, { DB_VERB_RECOVERY, "db_verb_recovery" }, { DB_VERB_REGISTER, "db_verb_register" }, { DB_VERB_REPLICATION, "db_verb_replication" }, { DB_VERB_REP_ELECT, "db_verb_rep_elect" }, { DB_VERB_REP_LEASE, "db_verb_rep_lease" }, { DB_VERB_REP_MISC, "db_verb_rep_misc" }, { DB_VERB_REP_MSGS, "db_verb_rep_msgs" }, { DB_VERB_REP_SYNC, "db_verb_rep_sync" }, { DB_VERB_REP_SYSTEM, "db_verb_rep_system" }, { DB_VERB_REP_TEST, "db_verb_rep_test" }, { DB_VERB_REPMGR_CONNFAIL, "db_verb_repmgr_connfail" }, { DB_VERB_REPMGR_MISC, "db_verb_repmgr_misc" }, { DB_VERB_WAITSFOR, "db_verb_waitsfor" }, { 0, NULL} }; static int __config_parse __P((ENV *, char *, int)); static int __config_scan __P((char *, char **, const CFG_DESC **)); static int cmp_cfg_name __P((const void *, const void *element)); /* * __env_read_db_config -- * Read the DB_CONFIG file. * * PUBLIC: int __env_read_db_config __P((ENV *)); */ int __env_read_db_config(env) ENV *env; { FILE *fp; int lc, ret; char *p, buf[256]; /* Parse the config file. */ p = NULL; if ((ret = __db_appname(env, DB_APP_NONE, "DB_CONFIG", NULL, &p)) != 0) return (ret); if (p == NULL) fp = NULL; else { fp = fopen(p, "r"); __os_free(env, p); } if (fp == NULL) return (0); for (lc = 1; fgets(buf, sizeof(buf), fp) != NULL; ++lc) { if ((p = strchr(buf, '\n')) == NULL) p = buf + strlen(buf); if (p > buf && p[-1] == '\r') --p; *p = '\0'; for (p = buf; *p != '\0' && isspace((int)*p); ++p) ; if (*p == '\0' || *p == '#') continue; if ((ret = __config_parse(env, p, lc)) != 0) break; } (void)fclose(fp); return (ret); } #undef CFG_GET_INT #define CFG_GET_INT(s, vp) do { \ int __ret; \ if ((__ret = \ __db_getlong(env->dbenv, NULL, s, 0, INT_MAX, vp)) != 0) \ return (__ret); \ } while (0) #undef CFG_GET_LONG #define CFG_GET_LONG(s, vp) do { \ int __ret; \ if ((__ret = \ __db_getlong(env->dbenv, NULL, s, 0, LONG_MAX, vp)) != 0) \ return (__ret); \ } while (0) #undef CFG_GET_UINT #define CFG_GET_UINT(s, vp) do { \ int __ret; \ if ((__ret = \ __db_getulong(env->dbenv, NULL, s, 0, UINT_MAX, vp)) != 0) \ return (__ret); \ } while (0) #undef CFG_GET_UINT32 #define CFG_GET_UINT32(s, vp) do { \ if (__db_getulong(env->dbenv, NULL, s, 0, UINT32_MAX, vp) != 0) \ return (EINVAL); \ } while (0) /* This is the maximum number of tokens in a DB_CONFIG line. */ #undef CFG_SLOTS #define CFG_SLOTS 10 /* * __config_parse -- * Parse a single NAME VALUE pair. */ static int __config_parse(env, s, lc) ENV *env; char *s; int lc; { DB_ENV *dbenv; DB_SITE *site; u_long uv1, uv2; long lv1, lv2; u_int port; int i, nf, onoff, bad, ret, t_ret; char *argv[CFG_SLOTS]; const CFG_DESC *desc; bad = 0; dbenv = env->dbenv; /* * Split the input line in 's' into its argv-like components, returning * the number of fields. If the command is one of the "simple" ones in * config_descs, also return its command descriptor. */ if ((nf = __config_scan(s, argv, &desc)) < 2) { format: __db_errx(env, DB_STR_A("1584", "line %d: %s: incorrect name-value pair", "%d %s"), lc, argv[0]); return (EINVAL); } /* Handle simple configuration lines here. */ if (desc != NULL) { ret = 0; switch (desc->type) { case CFG_INT: /* */ if (nf != 2) goto format; CFG_GET_INT(argv[1], &lv1); ret = ((CFG_FUNC_INT)desc->func)(dbenv, (int) lv1); break; case CFG_LONG: /* */ if (nf != 2) goto format; CFG_GET_LONG(argv[1], &lv1); ret = ((CFG_FUNC_LONG)desc->func)(dbenv, lv1); break; case CFG_UINT: /* */ if (nf != 2) goto format; CFG_GET_UINT(argv[1], &uv1); ret = ((CFG_FUNC_UINT)desc->func) (dbenv, (u_int32_t) uv1); break; case CFG_2INT: /* */ if (nf != 3) goto format; CFG_GET_INT(argv[1], &lv1); CFG_GET_INT(argv[2], &lv2); ret = ((CFG_FUNC_2INT)desc->func) (dbenv, (int) lv1, (int) lv2); break; case CFG_2UINT: /* */ if (nf != 3) goto format; CFG_GET_UINT(argv[1], &uv1); CFG_GET_UINT(argv[2], &uv2); ret = ((CFG_FUNC_2UINT)desc->func) (dbenv, (u_int32_t) uv1, (u_int32_t) uv2); break; case CFG_STRING: /* */ ret = ((CFG_FUNC_STRING) desc->func)(dbenv, argv[1]); break; } return (ret); } /* * The commands not covered in config_descs are handled below, each * with their own command-specific block of code. Most of them are * fairly similar to each other, but not quite enough to warrant * that they all be table-driven too. */ /* set_memory_init db_mem_XXX */ if (strcasecmp(argv[0], "set_memory_init") == 0) { if (nf != 3) goto format; if ((lv1 = __db_name_to_val(config_mem_init, argv[1])) == -1) goto format; CFG_GET_UINT32(argv[2], &uv2); return (__env_set_memory_init(dbenv, (DB_MEM_CONFIG) lv1, (u_int32_t)uv2)); } /* rep_set_config { db_rep_conf_XXX | db_repmgr_conf_XXX } [on|off] */ if (strcasecmp(argv[0], "rep_set_config") == 0) { if (nf != 2 && nf != 3) goto format; onoff = 1; if (nf == 3) { if (strcasecmp(argv[2], "off") == 0) onoff = 0; else if (strcasecmp(argv[2], "on") != 0) goto format; } if ((lv1 = __db_name_to_val(config_rep_config, argv[1])) == -1) goto format; return (__rep_set_config(dbenv, (u_int32_t)lv1, onoff)); } /* rep_set_timeout db_rep_XXX */ if (strcasecmp(argv[0], "rep_set_timeout") == 0) { if (nf != 3) goto format; if ((lv1 = __db_name_to_val(config_rep_timeout, argv[1])) == -1) goto format; CFG_GET_UINT32(argv[2], &uv2); return (__rep_set_timeout_pp(dbenv, lv1, (db_timeout_t)uv2)); } /* repmgr_set_ack_policy db_repmgr_acks_XXX */ if (strcasecmp(argv[0], "repmgr_set_ack_policy") == 0) { if (nf != 2) goto format; if ((lv1 = __db_name_to_val(config_repmgr_ack_policy, argv[1])) == -1) goto format; return (__repmgr_set_ack_policy(dbenv, lv1)); } if (strcasecmp(argv[0], "repmgr_set_incoming_queue_max") == 0) { if (nf != 3) goto format; CFG_GET_UINT32(argv[1], &uv1); CFG_GET_UINT32(argv[2], &uv2); return (__repmgr_set_incoming_queue_max( dbenv, (u_int32_t)uv1, (u_int32_t)uv2)); } /* * Configure name/value pairs of config information for a site (local or * remote). * * repmgr_site host port [which value(on | off | unsigned)}] ... */ if (strcasecmp(argv[0], "repmgr_site") == 0) { if (nf < 3 || (nf % 2) == 0) goto format; CFG_GET_UINT(argv[2], &uv2); port = (u_int)uv2; if ((ret = __repmgr_site(dbenv, argv[1], port, &site, 0)) != 0) return (ret); #ifdef HAVE_REPLICATION_THREADS for (i = 3; i < nf; i += 2) { if ((lv1 = __db_name_to_val( config_repmgr_site, argv[i])) == -1) { bad = 1; break; } if (strcasecmp(argv[i + 1], "on") == 0) uv2 = 1; else if (strcasecmp(argv[i + 1], "off") == 0) uv2 = 0; else CFG_GET_UINT32(argv[i + 1], &uv2); if ((ret = __repmgr_site_config_int(site, (u_int32_t)lv1, (u_int32_t)uv2)) != 0) break; } if ((t_ret = __repmgr_site_close(site)) != 0 && ret == 0) ret = t_ret; if (bad) goto format; #else /* If repmgr not built, __repmgr_site() returns DB_OPNOTSUP. */ COMPQUIET(i, 0); COMPQUIET(t_ret, 0); DB_ASSERT(env, 0); #endif return (ret); } /* set_cachesize */ if (strcasecmp(argv[0], "set_cachesize") == 0) { if (nf != 4) goto format; CFG_GET_UINT32(argv[1], &uv1); CFG_GET_UINT32(argv[2], &uv2); CFG_GET_INT(argv[3], &lv1); return (__memp_set_cachesize( dbenv, (u_int32_t)uv1, (u_int32_t)uv2, (int)lv1)); } /* set_intermediate_dir */ if (strcasecmp(argv[0], "set_intermediate_dir") == 0) { if (nf != 2) goto format; CFG_GET_INT(argv[1], &lv1); if (lv1 <= 0) goto format; env->dir_mode = (int)lv1; return (0); } /* set_flags [on | off] */ if (strcasecmp(argv[0], "set_flags") == 0) { if (nf != 2 && nf != 3) goto format; onoff = 1; if (nf == 3) { if (strcasecmp(argv[2], "off") == 0) onoff = 0; else if (strcasecmp(argv[2], "on") != 0) goto format; } /* First see whether it is an env flag, then a log flag. */ if ((lv1 = __db_name_to_val(config_set_flags, argv[1])) != -1) return (__env_set_flags(dbenv, (u_int32_t)lv1, onoff)); else if ((lv1 = __db_name_to_val(config_set_flags_forlog, argv[1])) != -1) return (__log_set_config(dbenv, (u_int32_t)lv1, onoff)); goto format; } /* log_set_config [on | off] */ if (strcasecmp(argv[0], "log_set_config") == 0) { if (nf != 2 && nf != 3) goto format; onoff = 1; if (nf == 3) { if (strcasecmp(argv[2], "off") == 0) onoff = 0; else if (strcasecmp(argv[2], "on") != 0) goto format; } if ((lv1 = __db_name_to_val(config_log_set_config, argv[1])) == -1) goto format; return (__log_set_config(dbenv, (u_int32_t)lv1, onoff)); } /* set_lk_detect db_lock_xxx */ if (strcasecmp(argv[0], "set_lk_detect") == 0) { if (nf != 2) goto format; if ((lv1 = __db_name_to_val(config_set_lk_detect, argv[1])) == -1) goto format; return (__lock_set_lk_detect(dbenv, (u_int32_t)lv1)); } /* set_lock_timeout */ if (strcasecmp(argv[0], "set_lock_timeout") == 0) { if (nf != 2) goto format; CFG_GET_UINT32(argv[1], &uv1); return (__lock_set_env_timeout( dbenv, (u_int32_t)uv1, DB_SET_LOCK_TIMEOUT)); } /* set_open_flags [on | off] */ if (strcasecmp(argv[0], "set_open_flags") == 0) { if (nf != 2 && nf != 3) goto format; onoff = 1; if (nf == 3) { if (strcasecmp(argv[2], "off") == 0) onoff = 0; else if (strcasecmp(argv[2], "on") != 0) goto format; } if ((lv1 = __db_name_to_val(config_set_open_flags, argv[1])) == -1) goto format; if (onoff == 1) FLD_SET(env->open_flags, (u_int32_t)lv1); else FLD_CLR(env->open_flags, (u_int32_t)lv1); return (0); } /* set_region_init <0 or 1> */ if (strcasecmp(argv[0], "set_region_init") == 0) { if (nf != 2) goto format; CFG_GET_INT(argv[1], &lv1); if (lv1 != 0 && lv1 != 1) goto format; return (__env_set_flags( dbenv, DB_REGION_INIT, lv1 == 0 ? 0 : 1)); } /* set_mutex_failchk_timeout */ if (strcasecmp(argv[0], "set_mutex_failchk_timeout") == 0) { if (nf != 2) goto format; CFG_GET_UINT32(argv[1], &uv1); return (__env_set_timeout( dbenv, (u_int32_t)uv1, DB_SET_MUTEX_FAILCHK_TIMEOUT)); } /* set_reg_timeout */ if (strcasecmp(argv[0], "set_reg_timeout") == 0) { if (nf != 2) goto format; CFG_GET_UINT32(argv[1], &uv1); return (__env_set_timeout( dbenv, (u_int32_t)uv1, DB_SET_REG_TIMEOUT)); } /* set_txn_timeout */ if (strcasecmp(argv[0], "set_txn_timeout") == 0) { if (nf != 2) goto format; CFG_GET_UINT32(argv[1], &uv1); return (__lock_set_env_timeout( dbenv, (u_int32_t)uv1, DB_SET_TXN_TIMEOUT)); } /* set_verbose db_verb_XXX [on | off] */ if (strcasecmp(argv[0], "set_verbose") == 0) { if (nf != 2 && nf != 3) goto format; onoff = 1; if (nf == 3) { if (strcasecmp(argv[2], "off") == 0) onoff = 0; else if (strcasecmp(argv[2], "on") != 0) goto format; } if ((lv1 = __db_name_to_val(config_set_verbose, argv[1])) == -1) goto format; return (__env_set_verbose(dbenv, (u_int32_t)lv1, onoff)); } __db_errx(env, DB_STR_A("1585", "unrecognized name-value pair: %s", "%s"), s); return (EINVAL); } /* cmp_cfg_name -- * Bsearch comparison function for CFG_DESC.name, for looking up * the names of simple commmands. */ static int cmp_cfg_name(sought, element) const void *sought; const void *element; { return (strcmp((const char *) sought, ((const CFG_DESC *) element)->name)); } /* * __config_scan -- * Split DB_CONFIG lines into fields. Usually each whitespace separated * field is scanned as a distinct argument. However, if the command is * recognized as one needing a single string value, then the rest of the * line is returned as the one argument. That supports strings which * contain whitespaces, such as some directory paths. * * This returns the number of fields. It sets *descptr to the command * descriptor (if it is recognized), or NULL. */ static int __config_scan(input, argv, descptr) char *input, *argv[CFG_SLOTS]; const CFG_DESC **descptr; { size_t tablecount; int count; char **ap; tablecount = sizeof(config_descs) / sizeof(config_descs[0]); *descptr = NULL; for (count = 0, ap = argv; (*ap = strsep(&input, " \t\n")) != NULL;) { /* Empty tokens are adjacent whitespaces; skip them. */ if (**ap == '\0') continue; /* Accept a non-empty token as the next field. */ count++; ap++; /* * If that was the first token, look it up in the simple command * table. If it is there and takes a single string value, then * return the remainder of the line (after skipping over any * leading whitespaces) without splitting it further. */ if (count == 1) { *descptr = bsearch(argv[0], config_descs, tablecount, sizeof(config_descs[0]), cmp_cfg_name); if (*descptr != NULL && (*descptr)->type == CFG_STRING) { count++; while (isspace(*input)) input++; *ap++ = input; break; } } /* Stop scanning if the line has too many tokens. */ if (count >= CFG_SLOTS) break; } return (count); }