1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: env_config.c,v 12.84 2008/02/12 15:34:06 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/lock.h"
13#include "dbinc/log.h"
14#include "dbinc/mp.h"
15#include "dbinc/txn.h"
16
17static int __config_parse __P((ENV *, char *, int));
18
19/*
20 * __env_read_db_config --
21 *	Read the DB_CONFIG file.
22 *
23 * PUBLIC: int __env_read_db_config __P((ENV *));
24 */
25int
26__env_read_db_config(env)
27	ENV *env;
28{
29	FILE *fp;
30	int lc, ret;
31	char *p, buf[256];
32
33	/* Parse the config file. */
34	p = NULL;
35	if ((ret =
36	    __db_appname(env, DB_APP_NONE, "DB_CONFIG", 0, NULL, &p)) != 0)
37		return (ret);
38	if (p == NULL)
39		fp = NULL;
40	else {
41		fp = fopen(p, "r");
42		__os_free(env, p);
43	}
44
45	if (fp == NULL)
46		return (0);
47
48	for (lc = 1; fgets(buf, sizeof(buf), fp) != NULL; ++lc) {
49		if ((p = strchr(buf, '\n')) == NULL) {
50			__db_errx(env, "DB_CONFIG: line %d: illegal input", lc);
51			ret = EINVAL;
52			break;
53		}
54		if (p > buf && p[-1] == '\r')
55			--p;
56		*p = '\0';
57		for (p = buf; *p != '\0' && isspace((int)*p); ++p)
58			;
59		if (*p == '\0' || *p == '#')
60			continue;
61
62		if ((ret = __config_parse(env, buf, lc)) != 0)
63			break;
64	}
65	(void)fclose(fp);
66
67	return (ret);
68}
69
70#undef	CONFIG_GET_INT
71#define	CONFIG_GET_INT(s, vp) do {					\
72	int __ret;							\
73	if ((__ret =							\
74	    __db_getlong(env->dbenv, NULL, s, 0, INT_MAX, vp)) != 0)	\
75		return (__ret);						\
76} while (0)
77#undef	CONFIG_GET_LONG
78#define	CONFIG_GET_LONG(s, vp) do {					\
79	int __ret;							\
80	if ((__ret =							\
81	    __db_getlong(env->dbenv, NULL, s, 0, LONG_MAX, vp)) != 0)	\
82		return (__ret);						\
83} while (0)
84#undef	CONFIG_INT
85#define	CONFIG_INT(s, f) do {						\
86	if (strcasecmp(s, argv[0]) == 0) {				\
87		long __v;						\
88		if (nf != 2)						\
89			goto format;					\
90		CONFIG_GET_INT(argv[1], &__v);				\
91		return (f(env->dbenv, (int)__v));			\
92	}								\
93} while (0)
94#undef	CONFIG_GET_UINT32
95#define	CONFIG_GET_UINT32(s, vp) do {					\
96	if (__db_getulong(env->dbenv, NULL, s, 0, UINT32_MAX, vp) != 0)	\
97		return (EINVAL);					\
98} while (0)
99#undef	CONFIG_UINT32
100#define	CONFIG_UINT32(s, f) do {					\
101	if (strcasecmp(s, argv[0]) == 0) {				\
102		u_long __v;						\
103		if (nf != 2)						\
104			goto format;					\
105		CONFIG_GET_UINT32(argv[1], &__v);			\
106		return (f(env->dbenv, (u_int32_t)__v));			\
107	}								\
108} while (0)
109
110#undef	CONFIG_SLOTS
111#define	CONFIG_SLOTS	10
112
113/*
114 * __config_parse --
115 *	Parse a single NAME VALUE pair.
116 */
117static int
118__config_parse(env, s, lc)
119	ENV *env;
120	char *s;
121	int lc;
122{
123	DB_ENV *dbenv;
124	u_long uv1, uv2;
125	u_int32_t flags;
126	long lv1, lv2;
127	int nf;
128	char *argv[CONFIG_SLOTS];
129
130	dbenv = env->dbenv;
131					/* Split the line by white-space. */
132	if ((nf = __config_split(s, argv)) < 2) {
133format:		__db_errx(env,
134		    "line %d: %s: incorrect name-value pair", lc, argv[0]);
135		return (EINVAL);
136	}
137
138	CONFIG_UINT32("mutex_set_align", __mutex_set_align);
139	CONFIG_UINT32("mutex_set_increment", __mutex_set_increment);
140	CONFIG_UINT32("mutex_set_max", __mutex_set_max);
141	CONFIG_UINT32("mutex_set_tas_spins", __mutex_set_tas_spins);
142
143	if (strcasecmp(argv[0], "rep_set_clockskew") == 0) {
144		if (nf != 3)
145			goto format;
146		CONFIG_GET_UINT32(argv[1], &uv1);
147		CONFIG_GET_UINT32(argv[2], &uv2);
148		return (__rep_set_clockskew(
149		    dbenv, (u_int32_t)uv1, (u_int32_t)uv2));
150	}
151
152	if (strcasecmp(argv[0], "rep_set_config") == 0) {
153		if (nf != 2)
154			goto format;
155		if (strcasecmp(argv[1], "db_rep_conf_bulk") == 0)
156			return (__rep_set_config(dbenv,
157			    DB_REP_CONF_BULK, 1));
158		if (strcasecmp(argv[1], "db_rep_conf_delayclient") == 0)
159			return (__rep_set_config(dbenv,
160			    DB_REP_CONF_DELAYCLIENT, 1));
161		if (strcasecmp(argv[1], "db_rep_conf_lease") == 0)
162			return (__rep_set_config(dbenv,
163			    DB_REP_CONF_LEASE, 1));
164		if (strcasecmp(argv[1], "db_rep_conf_noautoinit") == 0)
165			return (__rep_set_config(dbenv,
166			    DB_REP_CONF_NOAUTOINIT, 1));
167		if (strcasecmp(argv[1], "db_rep_conf_nowait") == 0)
168			return (__rep_set_config(dbenv, DB_REP_CONF_NOWAIT, 1));
169		if (strcasecmp(argv[1], "db_repmgr_conf_2site_strict") == 0)
170			return (__rep_set_config(dbenv,
171			    DB_REPMGR_CONF_2SITE_STRICT, 1));
172		goto format;
173	}
174
175	if (strcasecmp(argv[0], "rep_set_limit") == 0) {
176		if (nf != 3)
177			goto format;
178		CONFIG_GET_UINT32(argv[1], &uv1);
179		CONFIG_GET_UINT32(argv[2], &uv2);
180		return (__rep_set_limit(
181		    dbenv, (u_int32_t)uv1, (u_int32_t)uv2));
182	}
183
184	if (strcasecmp(argv[0], "rep_set_nsites") == 0) {
185		if (nf != 2)
186			goto format;
187		CONFIG_GET_UINT32(argv[1], &uv1);
188		return (__rep_set_nsites(
189		    dbenv, (u_int32_t)uv1));
190	}
191
192	if (strcasecmp(argv[0], "rep_set_priority") == 0) {
193		if (nf != 2)
194			goto format;
195		CONFIG_GET_UINT32(argv[1], &uv1);
196		return (__rep_set_priority(
197		    dbenv, (u_int32_t)uv1));
198	}
199
200	if (strcasecmp(argv[0], "rep_set_request") == 0) {
201		if (nf != 3)
202			goto format;
203		CONFIG_GET_UINT32(argv[1], &uv1);
204		CONFIG_GET_UINT32(argv[2], &uv2);
205		return (__rep_set_request(
206		    dbenv, (u_int32_t)uv1, (u_int32_t)uv2));
207	}
208
209	if (strcasecmp(argv[0], "rep_set_timeout") == 0) {
210		if (nf != 3)
211			goto format;
212		CONFIG_GET_UINT32(argv[2], &uv2);
213		if (strcasecmp(argv[1], "db_rep_ack_timeout") == 0)
214			return (__rep_set_timeout(
215			    dbenv, DB_REP_ACK_TIMEOUT, (u_int32_t)uv2));
216		if (strcasecmp(argv[1], "db_rep_checkpoint_delay") == 0)
217			return (__rep_set_timeout(
218			    dbenv, DB_REP_CHECKPOINT_DELAY, (u_int32_t)uv2));
219		if (strcasecmp(argv[1], "db_rep_connection_retry") == 0)
220			return (__rep_set_timeout(
221			    dbenv, DB_REP_CONNECTION_RETRY, (u_int32_t)uv2));
222		if (strcasecmp(argv[1], "db_rep_election_timeout") == 0)
223			return (__rep_set_timeout(
224			    dbenv, DB_REP_ELECTION_TIMEOUT, (u_int32_t)uv2));
225		if (strcasecmp(argv[1], "db_rep_election_retry") == 0)
226			return (__rep_set_timeout(
227			    dbenv, DB_REP_ELECTION_RETRY, (u_int32_t)uv2));
228		if (strcasecmp(argv[1], "db_rep_full_election_timeout") == 0)
229			return (__rep_set_timeout(dbenv,
230			    DB_REP_FULL_ELECTION_TIMEOUT, (u_int32_t)uv2));
231		if (strcasecmp(argv[1], "db_rep_heartbeat_monitor") == 0)
232			return (__rep_set_timeout(
233			    dbenv, DB_REP_HEARTBEAT_MONITOR, (u_int32_t)uv2));
234		if (strcasecmp(argv[1], "db_rep_heartbeat_send") == 0)
235			return (__rep_set_timeout(
236			    dbenv, DB_REP_HEARTBEAT_SEND, (u_int32_t)uv2));
237		if (strcasecmp(argv[1], "db_rep_lease_timeout") == 0)
238			return (__rep_set_timeout(
239			    dbenv, DB_REP_LEASE_TIMEOUT, (u_int32_t)uv2));
240		goto format;
241	}
242
243	if (strcasecmp(argv[0], "repmgr_set_ack_policy") == 0) {
244		if (nf != 2)
245			goto format;
246		if (strcasecmp(argv[1], "db_repmgr_acks_all") == 0)
247			return (__repmgr_set_ack_policy(
248			    dbenv, DB_REPMGR_ACKS_ALL));
249		if (strcasecmp(argv[1], "db_repmgr_acks_all_peers") == 0)
250			return (__repmgr_set_ack_policy(
251			    dbenv, DB_REPMGR_ACKS_ALL_PEERS));
252		if (strcasecmp(argv[1], "db_repmgr_acks_none") == 0)
253			return (__repmgr_set_ack_policy(
254			    dbenv, DB_REPMGR_ACKS_NONE));
255		if (strcasecmp(argv[1], "db_repmgr_acks_one") == 0)
256			return (__repmgr_set_ack_policy(
257			    dbenv, DB_REPMGR_ACKS_ONE));
258		if (strcasecmp(argv[1], "db_repmgr_acks_one_peer") == 0)
259			return (__repmgr_set_ack_policy(
260			    dbenv, DB_REPMGR_ACKS_ONE_PEER));
261		if (strcasecmp(argv[1], "db_repmgr_acks_quorum") == 0)
262			return (__repmgr_set_ack_policy(
263			    dbenv, DB_REPMGR_ACKS_QUORUM));
264		goto format;
265	}
266
267	if (strcasecmp(argv[0], "set_cachesize") == 0) {
268		if (nf != 4)
269			goto format;
270		CONFIG_GET_UINT32(argv[1], &uv1);
271		CONFIG_GET_UINT32(argv[2], &uv2);
272		CONFIG_GET_INT(argv[3], &lv1);
273		return (__memp_set_cachesize(
274		    dbenv, (u_int32_t)uv1, (u_int32_t)uv2, (int)lv1));
275	}
276
277	if (strcasecmp(argv[0], "set_data_dir") == 0 ||
278	    strcasecmp(argv[0], "db_data_dir") == 0) {	/* Compatibility. */
279		if (nf != 2)
280			goto format;
281		return (__env_set_data_dir(dbenv, argv[1]));
282	}
283
284							/* Compatibility */
285	if (strcasecmp(argv[0], "set_intermediate_dir") == 0) {
286		if (nf != 2)
287			goto format;
288		CONFIG_GET_INT(argv[1], &lv1);
289		if (lv1 <= 0)
290			goto format;
291		env->dir_mode = (int)lv1;
292		return (0);
293	}
294	if (strcasecmp(argv[0], "set_intermediate_dir_mode") == 0) {
295		if (nf != 2)
296			goto format;
297		return (__env_set_intermediate_dir_mode(dbenv, argv[1]));
298	}
299
300	if (strcasecmp(argv[0], "set_flags") == 0) {
301		if (nf != 2)
302			goto format;
303		if (strcasecmp(argv[1], "db_auto_commit") == 0)
304			return (__env_set_flags(dbenv, DB_AUTO_COMMIT, 1));
305		if (strcasecmp(argv[1], "db_cdb_alldb") == 0)
306			return (__env_set_flags(dbenv, DB_CDB_ALLDB, 1));
307		if (strcasecmp(argv[1], "db_direct_db") == 0)
308			return (__env_set_flags(dbenv, DB_DIRECT_DB, 1));
309		if (strcasecmp(argv[1], "db_dsync_db") == 0)
310			return (__env_set_flags(dbenv, DB_DSYNC_DB, 1));
311		if (strcasecmp(argv[1], "db_multiversion") == 0)
312			return (__env_set_flags(dbenv, DB_MULTIVERSION, 1));
313		if (strcasecmp(argv[1], "db_nolocking") == 0)
314			return (__env_set_flags(dbenv, DB_NOLOCKING, 1));
315		if (strcasecmp(argv[1], "db_nommap") == 0)
316			return (__env_set_flags(dbenv, DB_NOMMAP, 1));
317		if (strcasecmp(argv[1], "db_nopanic") == 0)
318			return (__env_set_flags(dbenv, DB_NOPANIC, 1));
319		if (strcasecmp(argv[1], "db_overwrite") == 0)
320			return (__env_set_flags(dbenv, DB_OVERWRITE, 1));
321		if (strcasecmp(argv[1], "db_region_init") == 0)
322			return (__env_set_flags(dbenv, DB_REGION_INIT, 1));
323		if (strcasecmp(argv[1], "db_txn_nosync") == 0)
324			return (__env_set_flags(dbenv, DB_TXN_NOSYNC, 1));
325		if (strcasecmp(argv[1], "db_txn_nowait") == 0)
326			return (__env_set_flags(dbenv, DB_TXN_NOWAIT, 1));
327		if (strcasecmp(argv[1], "db_txn_snapshot") == 0)
328			return (__env_set_flags(dbenv, DB_TXN_SNAPSHOT, 1));
329		if (strcasecmp(argv[1], "db_txn_write_nosync") == 0)
330			return (
331			    __env_set_flags(dbenv, DB_TXN_WRITE_NOSYNC, 1));
332		if (strcasecmp(argv[1], "db_yieldcpu") == 0)
333			return (__env_set_flags(dbenv, DB_YIELDCPU, 1));
334		if (strcasecmp(argv[1], "db_log_inmemory") == 0)
335			return (__log_set_config(dbenv, DB_LOG_IN_MEMORY, 1));
336		if (strcasecmp(argv[1], "db_direct_log") == 0)
337			return (__log_set_config(dbenv, DB_LOG_DIRECT, 1));
338		if (strcasecmp(argv[1], "db_dsync_log") == 0)
339			return (__log_set_config(dbenv, DB_LOG_DSYNC, 1));
340		if (strcasecmp(argv[1], "db_log_autoremove") == 0)
341			return (__log_set_config(dbenv, DB_LOG_AUTO_REMOVE, 1));
342		goto format;
343	}
344	if (strcasecmp(argv[0], "set_log_config") == 0) {
345		if (nf != 2)
346			goto format;
347		if (strcasecmp(argv[1], "db_log_auto_remove") == 0)
348			return (__log_set_config(dbenv, DB_LOG_AUTO_REMOVE, 1));
349		if (strcasecmp(argv[1], "db_log_direct") == 0)
350			return (__log_set_config(dbenv, DB_LOG_DIRECT, 1));
351		if (strcasecmp(argv[1], "db_log_dsync") == 0)
352			return (__log_set_config(dbenv, DB_LOG_DSYNC, 1));
353		if (strcasecmp(argv[1], "db_log_in_memory") == 0)
354			return (__log_set_config(dbenv, DB_LOG_IN_MEMORY, 1));
355		if (strcasecmp(argv[1], "db_log_zero") == 0)
356			return (__log_set_config(dbenv, DB_LOG_ZERO, 1));
357		goto format;
358	}
359
360	CONFIG_UINT32("set_lg_bsize", __log_set_lg_bsize);
361	CONFIG_INT("set_lg_filemode", __log_set_lg_filemode);
362	CONFIG_UINT32("set_lg_max", __log_set_lg_max);
363	CONFIG_UINT32("set_lg_regionmax", __log_set_lg_regionmax);
364
365	if (strcasecmp(argv[0], "set_lg_dir") == 0 ||
366	    strcasecmp(argv[0], "db_log_dir") == 0) {	/* Compatibility. */
367		if (nf != 2)
368			goto format;
369		return (__log_set_lg_dir(dbenv, argv[1]));
370	}
371
372	if (strcasecmp(argv[0], "set_lk_detect") == 0) {
373		if (nf != 2)
374			goto format;
375		if (strcasecmp(argv[1], "db_lock_default") == 0)
376			flags = DB_LOCK_DEFAULT;
377		else if (strcasecmp(argv[1], "db_lock_expire") == 0)
378			flags = DB_LOCK_EXPIRE;
379		else if (strcasecmp(argv[1], "db_lock_maxlocks") == 0)
380			flags = DB_LOCK_MAXLOCKS;
381		else if (strcasecmp(argv[1], "db_lock_maxwrite") == 0)
382			flags = DB_LOCK_MAXWRITE;
383		else if (strcasecmp(argv[1], "db_lock_minlocks") == 0)
384			flags = DB_LOCK_MINLOCKS;
385		else if (strcasecmp(argv[1], "db_lock_minwrite") == 0)
386			flags = DB_LOCK_MINWRITE;
387		else if (strcasecmp(argv[1], "db_lock_oldest") == 0)
388			flags = DB_LOCK_OLDEST;
389		else if (strcasecmp(argv[1], "db_lock_random") == 0)
390			flags = DB_LOCK_RANDOM;
391		else if (strcasecmp(argv[1], "db_lock_youngest") == 0)
392			flags = DB_LOCK_YOUNGEST;
393		else
394			goto format;
395		return (__lock_set_lk_detect(dbenv, flags));
396	}
397
398	CONFIG_UINT32("set_lk_max_locks", __lock_set_lk_max_locks);
399	CONFIG_UINT32("set_lk_max_lockers", __lock_set_lk_max_lockers);
400	CONFIG_UINT32("set_lk_max_objects", __lock_set_lk_max_objects);
401	CONFIG_UINT32("set_lk_partitions", __lock_set_lk_partitions);
402
403	if (strcasecmp(argv[0], "set_lock_timeout") == 0) {
404		if (nf != 2)
405			goto format;
406		CONFIG_GET_UINT32(argv[1], &uv1);
407		return (__lock_set_env_timeout(
408		    dbenv, (u_int32_t)uv1, DB_SET_LOCK_TIMEOUT));
409	}
410
411	CONFIG_INT("set_mp_max_openfd", __memp_set_mp_max_openfd);
412
413	if (strcasecmp(argv[0], "set_mp_max_write") == 0) {
414		if (nf != 3)
415			goto format;
416		CONFIG_GET_INT(argv[1], &lv1);
417		CONFIG_GET_INT(argv[2], &lv2);
418		return (__memp_set_mp_max_write(
419		    dbenv, (int)lv1, (db_timeout_t)lv2));
420	}
421
422	CONFIG_UINT32("set_mp_mmapsize", __memp_set_mp_mmapsize);
423
424	if (strcasecmp(argv[0], "set_region_init") == 0) {
425		if (nf != 2)
426			goto format;
427		CONFIG_GET_INT(argv[1], &lv1);
428		if (lv1 != 0 && lv1 != 1)
429			goto format;
430		return (__env_set_flags(
431		    dbenv, DB_REGION_INIT, lv1 == 0 ? 0 : 1));
432	}
433
434	if (strcasecmp(argv[0], "set_shm_key") == 0) {
435		if (nf != 2)
436			goto format;
437		CONFIG_GET_LONG(argv[1], &lv1);
438		return (__env_set_shm_key(dbenv, lv1));
439	}
440
441	/*
442	 * The set_tas_spins method has been replaced by mutex_set_tas_spins.
443	 * The set_tas_spins argv[0] remains for DB_CONFIG compatibility.
444	 */
445	CONFIG_UINT32("set_tas_spins", __mutex_set_tas_spins);
446
447	if (strcasecmp(argv[0], "set_tmp_dir") == 0 ||
448	    strcasecmp(argv[0], "db_tmp_dir") == 0) {	/* Compatibility.*/
449		if (nf != 2)
450			goto format;
451		return (__env_set_tmp_dir(dbenv, argv[1]));
452	}
453
454	CONFIG_UINT32("set_tx_max", __txn_set_tx_max);
455
456	if (strcasecmp(argv[0], "set_txn_timeout") == 0) {
457		if (nf != 2)
458			goto format;
459		CONFIG_GET_UINT32(argv[1], &uv1);
460		return (__lock_set_env_timeout(
461		    dbenv, (u_int32_t)uv1, DB_SET_TXN_TIMEOUT));
462	}
463
464	if (strcasecmp(argv[0], "set_verbose") == 0) {
465		if (nf != 2)
466			goto format;
467		if (strcasecmp(argv[1], "db_verb_deadlock") == 0)
468			flags = DB_VERB_DEADLOCK;
469		else if (strcasecmp(argv[1], "db_verb_fileops") == 0)
470			flags = DB_VERB_FILEOPS;
471		else if (strcasecmp(argv[1], "db_verb_fileops_all") == 0)
472			flags = DB_VERB_FILEOPS_ALL;
473		else if (strcasecmp(argv[1], "db_verb_recovery") == 0)
474			flags = DB_VERB_RECOVERY;
475		else if (strcasecmp(argv[1], "db_verb_register") == 0)
476			flags = DB_VERB_REGISTER;
477		else if (strcasecmp(argv[1], "db_verb_replication") == 0)
478			flags = DB_VERB_REPLICATION;
479		else if (strcasecmp(argv[1], "db_verb_rep_elect") == 0)
480			flags = DB_VERB_REP_ELECT;
481		else if (strcasecmp(argv[1], "db_verb_rep_lease") == 0)
482			flags = DB_VERB_REP_LEASE;
483		else if (strcasecmp(argv[1], "db_verb_rep_misc") == 0)
484			flags = DB_VERB_REP_MISC;
485		else if (strcasecmp(argv[1], "db_verb_rep_msgs") == 0)
486			flags = DB_VERB_REP_MSGS;
487		else if (strcasecmp(argv[1], "db_verb_rep_sync") == 0)
488			flags = DB_VERB_REP_SYNC;
489		else if (strcasecmp(argv[1], "db_verb_repmgr_connfail") == 0)
490			flags = DB_VERB_REPMGR_CONNFAIL;
491		else if (strcasecmp(argv[1], "db_verb_repmgr_misc") == 0)
492			flags = DB_VERB_REPMGR_MISC;
493		else if (strcasecmp(argv[1], "db_verb_waitsfor") == 0)
494			flags = DB_VERB_WAITSFOR;
495		else
496			goto format;
497		return (__env_set_verbose(dbenv, flags, 1));
498	}
499
500	__db_errx(env, "unrecognized name-value pair: %s", s);
501	return (EINVAL);
502}
503
504/*
505 * __config_split --
506 *	Split lines into white-space separated fields, returning the count of
507 *	fields.
508 *
509 * PUBLIC: int __config_split __P((char *, char *[]));
510 */
511int
512__config_split(input, argv)
513	char *input, *argv[CONFIG_SLOTS];
514{
515	int count;
516	char **ap;
517
518	for (count = 0, ap = argv; (*ap = strsep(&input, " \t\n")) != NULL;)
519		if (**ap != '\0') {
520			++count;
521			if (++ap == &argv[CONFIG_SLOTS - 1]) {
522				*ap = NULL;
523				break;
524			}
525		}
526	return (count);
527}
528