1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999,2008 Oracle.  All rights reserved.
5 *
6 * $Id: env_method.c,v 12.87 2008/02/18 20:06:07 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/crypto.h"
13#include "dbinc/hmac.h"
14#include "dbinc/db_page.h"
15#include "dbinc/db_am.h"
16#include "dbinc/lock.h"
17#include "dbinc/log.h"
18#include "dbinc/mp.h"
19#include "dbinc/txn.h"
20
21#ifdef HAVE_RPC
22#ifdef HAVE_SYSTEM_INCLUDE_FILES
23#include <rpc/rpc.h>
24#endif
25#include "db_server.h"
26#include "dbinc_auto/rpc_client_ext.h"
27#endif
28
29static int  __db_env_init __P((DB_ENV *));
30static void __env_err __P((const DB_ENV *, int, const char *, ...));
31static void __env_errx __P((const DB_ENV *, const char *, ...));
32static int  __env_get_data_dirs __P((DB_ENV *, const char ***));
33static int  __env_get_flags __P((DB_ENV *, u_int32_t *));
34static int  __env_get_home __P((DB_ENV *, const char **));
35static int  __env_get_intermediate_dir_mode __P((DB_ENV *, const char **));
36static int  __env_get_shm_key __P((DB_ENV *, long *));
37static int  __env_get_thread_count __P((DB_ENV *, u_int32_t *));
38static int  __env_get_tmp_dir __P((DB_ENV *, const char **));
39static int  __env_get_verbose __P((DB_ENV *, u_int32_t, int *));
40static int  __env_set_app_dispatch
41		__P((DB_ENV *, int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops)));
42static int __env_set_event_notify
43		__P((DB_ENV *, void (*)(DB_ENV *, u_int32_t, void *)));
44static int  __env_set_feedback __P((DB_ENV *, void (*)(DB_ENV *, int, int)));
45static int  __env_set_isalive __P((DB_ENV *,
46		int (*)(DB_ENV *, pid_t, db_threadid_t, u_int32_t)));
47static int  __env_set_thread_id __P((DB_ENV *, void (*)(DB_ENV *,
48		pid_t *, db_threadid_t *)));
49static int  __env_set_thread_id_string __P((DB_ENV *,
50		char * (*)(DB_ENV *, pid_t, db_threadid_t, char *)));
51static int  __env_set_thread_count __P((DB_ENV *, u_int32_t));
52static int  __env_set_rpc_server
53		__P((DB_ENV *, void *, const char *, long, long, u_int32_t));
54
55/*
56 * db_env_create --
57 *	DB_ENV constructor.
58 *
59 * EXTERN: int db_env_create __P((DB_ENV **, u_int32_t));
60 */
61int
62db_env_create(dbenvpp, flags)
63	DB_ENV **dbenvpp;
64	u_int32_t flags;
65{
66	DB_ENV *dbenv;
67	ENV *env;
68	int ret;
69
70	/*
71	 * !!!
72	 * Our caller has not yet had the opportunity to reset the panic
73	 * state or turn off mutex locking, and so we can neither check
74	 * the panic state or acquire a mutex in the DB_ENV create path.
75	 *
76	 * !!!
77	 * We can't call the flags-checking routines, we don't have an
78	 * environment yet.
79	 */
80	if (flags != 0 && !LF_ISSET(DB_RPCCLIENT))
81		return (EINVAL);
82
83	/* Allocate the DB_ENV and ENV structures -- we always have both. */
84	if ((ret = __os_calloc(NULL, 1, sizeof(DB_ENV), &dbenv)) != 0)
85		return (ret);
86	if ((ret = __os_calloc(NULL, 1, sizeof(ENV), &env)) != 0)
87		goto err;
88	dbenv->env = env;
89	env->dbenv = dbenv;
90
91#ifdef HAVE_RPC
92	if (LF_ISSET(DB_RPCCLIENT))
93		F_SET(dbenv, DB_ENV_RPCCLIENT);
94#endif
95	if ((ret = __db_env_init(dbenv)) != 0 ||
96	    (ret = __lock_env_create(dbenv)) != 0 ||
97	    (ret = __log_env_create(dbenv)) != 0 ||
98	    (ret = __memp_env_create(dbenv)) != 0 ||
99#ifdef HAVE_REPLICATION
100	    (ret = __rep_env_create(dbenv)) != 0 ||
101#endif
102	    (ret = __txn_env_create(dbenv)))
103		goto err;
104
105#ifdef HAVE_RPC
106	/*
107	 * RPC specific: must be last, as we replace methods set by the
108	 * access methods.
109	 */
110	if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) {
111		__dbcl_dbenv_init(dbenv);
112		/*
113		 * !!!
114		 * We wrap the DB_ENV->open and close methods for RPC, and
115		 * the rpc.src file can't handle that.
116		 */
117		dbenv->open = __dbcl_env_open_wrap;
118		dbenv->close = __dbcl_env_close_wrap;
119	}
120#endif
121
122	*dbenvpp = dbenv;
123	return (0);
124
125err:	__db_env_destroy(dbenv);
126	return (ret);
127}
128
129/*
130 * __db_env_destroy --
131 *	DB_ENV destructor.
132 *
133 * PUBLIC: void __db_env_destroy __P((DB_ENV *));
134 */
135void
136__db_env_destroy(dbenv)
137	DB_ENV *dbenv;
138{
139	__lock_env_destroy(dbenv);
140	__log_env_destroy(dbenv);
141	__memp_env_destroy(dbenv);
142#ifdef HAVE_REPLICATION
143	__rep_env_destroy(dbenv);
144#endif
145	__txn_env_destroy(dbenv);
146
147	/*
148	 * Discard the underlying ENV structure.
149	 *
150	 * XXX
151	 * This is wrong, but can't be fixed until we finish the work of
152	 * splitting up the DB_ENV and ENV structures so that we don't
153	 * touch anything in the ENV as part of the above calls to subsystem
154	 * DB_ENV cleanup routines.
155	 */
156	memset(dbenv->env, CLEAR_BYTE, sizeof(ENV));
157	__os_free(NULL, dbenv->env);
158
159	memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV));
160	__os_free(NULL, dbenv);
161}
162
163/*
164 * __db_env_init --
165 *	Initialize a DB_ENV structure.
166 */
167static int
168__db_env_init(dbenv)
169	DB_ENV *dbenv;
170{
171	ENV *env;
172	/*
173	 * !!!
174	 * Our caller has not yet had the opportunity to reset the panic
175	 * state or turn off mutex locking, and so we can neither check
176	 * the panic state or acquire a mutex in the DB_ENV create path.
177	 *
178	 * Initialize the method handles.
179	 */
180	/* DB_ENV PUBLIC HANDLE LIST BEGIN */
181	dbenv->cdsgroup_begin = __cdsgroup_begin;
182	dbenv->close = __env_close_pp;
183	dbenv->dbremove = __env_dbremove_pp;
184	dbenv->dbrename = __env_dbrename_pp;
185	dbenv->err = __env_err;
186	dbenv->errx = __env_errx;
187	dbenv->failchk = __env_failchk_pp;
188	dbenv->fileid_reset = __env_fileid_reset_pp;
189	dbenv->get_cache_max = __memp_get_cache_max;
190	dbenv->get_cachesize = __memp_get_cachesize;
191	dbenv->get_data_dirs = __env_get_data_dirs;
192	dbenv->get_encrypt_flags = __env_get_encrypt_flags;
193	dbenv->get_errcall = __env_get_errcall;
194	dbenv->get_errfile = __env_get_errfile;
195	dbenv->get_errpfx = __env_get_errpfx;
196	dbenv->get_flags = __env_get_flags;
197	dbenv->get_home = __env_get_home;
198	dbenv->get_intermediate_dir_mode = __env_get_intermediate_dir_mode;
199	dbenv->get_lg_bsize = __log_get_lg_bsize;
200	dbenv->get_lg_dir = __log_get_lg_dir;
201	dbenv->get_lg_filemode = __log_get_lg_filemode;
202	dbenv->get_lg_max = __log_get_lg_max;
203	dbenv->get_lg_regionmax = __log_get_lg_regionmax;
204	dbenv->get_lk_conflicts = __lock_get_lk_conflicts;
205	dbenv->get_lk_detect = __lock_get_lk_detect;
206	dbenv->get_lk_max_lockers = __lock_get_lk_max_lockers;
207	dbenv->get_lk_max_locks = __lock_get_lk_max_locks;
208	dbenv->get_lk_max_objects = __lock_get_lk_max_objects;
209	dbenv->get_lk_partitions = __lock_get_lk_partitions;
210	dbenv->get_mp_max_openfd = __memp_get_mp_max_openfd;
211	dbenv->get_mp_max_write = __memp_get_mp_max_write;
212	dbenv->get_mp_mmapsize = __memp_get_mp_mmapsize;
213	dbenv->get_msgfile = __env_get_msgfile;
214	dbenv->get_open_flags = __env_get_open_flags;
215	dbenv->get_shm_key = __env_get_shm_key;
216	dbenv->get_thread_count = __env_get_thread_count;
217	dbenv->get_timeout = __lock_get_env_timeout;
218	dbenv->get_tmp_dir = __env_get_tmp_dir;
219	dbenv->get_tx_max = __txn_get_tx_max;
220	dbenv->get_tx_timestamp = __txn_get_tx_timestamp;
221	dbenv->get_verbose = __env_get_verbose;
222	dbenv->is_bigendian = __db_isbigendian;
223	dbenv->lock_detect = __lock_detect_pp;
224	dbenv->lock_get = __lock_get_pp;
225	dbenv->lock_id = __lock_id_pp;
226	dbenv->lock_id_free = __lock_id_free_pp;
227	dbenv->lock_put = __lock_put_pp;
228	dbenv->lock_stat = __lock_stat_pp;
229	dbenv->lock_stat_print = __lock_stat_print_pp;
230	dbenv->lock_vec = __lock_vec_pp;
231	dbenv->log_archive = __log_archive_pp;
232	dbenv->log_cursor = __log_cursor_pp;
233	dbenv->log_file = __log_file_pp;
234	dbenv->log_flush = __log_flush_pp;
235	dbenv->log_get_config = __log_get_config;
236	dbenv->log_printf = __log_printf_capi;
237	dbenv->log_put = __log_put_pp;
238	dbenv->log_set_config = __log_set_config;
239	dbenv->log_stat = __log_stat_pp;
240	dbenv->log_stat_print = __log_stat_print_pp;
241	dbenv->lsn_reset = __env_lsn_reset_pp;
242	dbenv->memp_fcreate = __memp_fcreate_pp;
243	dbenv->memp_register = __memp_register_pp;
244	dbenv->memp_stat = __memp_stat_pp;
245	dbenv->memp_stat_print = __memp_stat_print_pp;
246	dbenv->memp_sync = __memp_sync_pp;
247	dbenv->memp_trickle = __memp_trickle_pp;
248	dbenv->mutex_alloc = __mutex_alloc_pp;
249	dbenv->mutex_free = __mutex_free_pp;
250	dbenv->mutex_get_align = __mutex_get_align;
251	dbenv->mutex_get_increment = __mutex_get_increment;
252	dbenv->mutex_get_max = __mutex_get_max;
253	dbenv->mutex_get_tas_spins = __mutex_get_tas_spins;
254	dbenv->mutex_lock = __mutex_lock_pp;
255	dbenv->mutex_set_align = __mutex_set_align;
256	dbenv->mutex_set_increment = __mutex_set_increment;
257	dbenv->mutex_set_max = __mutex_set_max;
258	dbenv->mutex_set_tas_spins = __mutex_set_tas_spins;
259	dbenv->mutex_stat = __mutex_stat_pp;
260	dbenv->mutex_stat_print = __mutex_stat_print_pp;
261	dbenv->mutex_unlock = __mutex_unlock_pp;
262	dbenv->open = __env_open_pp;
263	dbenv->remove = __env_remove;
264	dbenv->rep_elect = __rep_elect;
265	dbenv->rep_flush = __rep_flush;
266	dbenv->rep_get_clockskew = __rep_get_clockskew;
267	dbenv->rep_get_config = __rep_get_config;
268	dbenv->rep_get_limit = __rep_get_limit;
269	dbenv->rep_get_nsites = __rep_get_nsites;
270	dbenv->rep_get_priority = __rep_get_priority;
271	dbenv->rep_get_request = __rep_get_request;
272	dbenv->rep_get_timeout = __rep_get_timeout;
273	dbenv->rep_process_message = __rep_process_message;
274	dbenv->rep_set_clockskew = __rep_set_clockskew;
275	dbenv->rep_set_config = __rep_set_config;
276	dbenv->rep_set_limit = __rep_set_limit;
277	dbenv->rep_set_nsites = __rep_set_nsites;
278	dbenv->rep_set_priority = __rep_set_priority;
279	dbenv->rep_set_request = __rep_set_request;
280	dbenv->rep_set_timeout = __rep_set_timeout;
281	dbenv->rep_set_transport = __rep_set_transport;
282	dbenv->rep_start = __rep_start;
283	dbenv->rep_stat = __rep_stat_pp;
284	dbenv->rep_stat_print = __rep_stat_print_pp;
285	dbenv->rep_sync = __rep_sync;
286	dbenv->repmgr_add_remote_site = __repmgr_add_remote_site;
287	dbenv->repmgr_get_ack_policy = __repmgr_get_ack_policy;
288	dbenv->repmgr_set_ack_policy = __repmgr_set_ack_policy;
289	dbenv->repmgr_set_local_site = __repmgr_set_local_site;
290	dbenv->repmgr_site_list = __repmgr_site_list;
291	dbenv->repmgr_start = __repmgr_start;
292	dbenv->repmgr_stat = __repmgr_stat_pp;
293	dbenv->repmgr_stat_print = __repmgr_stat_print_pp;
294	dbenv->set_alloc = __env_set_alloc;
295	dbenv->set_app_dispatch = __env_set_app_dispatch;
296	dbenv->set_cache_max = __memp_set_cache_max;
297	dbenv->set_cachesize = __memp_set_cachesize;
298	dbenv->set_data_dir = __env_set_data_dir;
299	dbenv->set_encrypt = __env_set_encrypt;
300	dbenv->set_errcall = __env_set_errcall;
301	dbenv->set_errfile = __env_set_errfile;
302	dbenv->set_errpfx = __env_set_errpfx;
303	dbenv->set_event_notify = __env_set_event_notify;
304	dbenv->set_feedback = __env_set_feedback;
305	dbenv->set_flags = __env_set_flags;
306	dbenv->set_intermediate_dir_mode = __env_set_intermediate_dir_mode;
307	dbenv->set_isalive = __env_set_isalive;
308	dbenv->set_lg_bsize = __log_set_lg_bsize;
309	dbenv->set_lg_dir = __log_set_lg_dir;
310	dbenv->set_lg_filemode = __log_set_lg_filemode;
311	dbenv->set_lg_max = __log_set_lg_max;
312	dbenv->set_lg_regionmax = __log_set_lg_regionmax;
313	dbenv->set_lk_conflicts = __lock_set_lk_conflicts;
314	dbenv->set_lk_detect = __lock_set_lk_detect;
315	dbenv->set_lk_max_lockers = __lock_set_lk_max_lockers;
316	dbenv->set_lk_max_locks = __lock_set_lk_max_locks;
317	dbenv->set_lk_max_objects = __lock_set_lk_max_objects;
318	dbenv->set_lk_partitions = __lock_set_lk_partitions;
319	dbenv->set_mp_max_openfd = __memp_set_mp_max_openfd;
320	dbenv->set_mp_max_write = __memp_set_mp_max_write;
321	dbenv->set_mp_mmapsize = __memp_set_mp_mmapsize;
322	dbenv->set_msgcall = __env_set_msgcall;
323	dbenv->set_msgfile = __env_set_msgfile;
324	dbenv->set_paniccall = __env_set_paniccall;
325	dbenv->set_rpc_server = __env_set_rpc_server;
326	dbenv->set_shm_key = __env_set_shm_key;
327	dbenv->set_thread_count = __env_set_thread_count;
328	dbenv->set_thread_id = __env_set_thread_id;
329	dbenv->set_thread_id_string = __env_set_thread_id_string;
330	dbenv->set_timeout = __lock_set_env_timeout;
331	dbenv->set_tmp_dir = __env_set_tmp_dir;
332	dbenv->set_tx_max = __txn_set_tx_max;
333	dbenv->set_tx_timestamp = __txn_set_tx_timestamp;
334	dbenv->set_verbose = __env_set_verbose;
335	dbenv->stat_print = __env_stat_print_pp;
336	dbenv->txn_begin = __txn_begin_pp;
337	dbenv->txn_checkpoint = __txn_checkpoint_pp;
338	dbenv->txn_recover = __txn_recover_pp;
339	dbenv->txn_stat = __txn_stat_pp;
340	dbenv->txn_stat_print = __txn_stat_print_pp;
341	/* DB_ENV PUBLIC HANDLE LIST END */
342
343	/* DB_ENV PRIVATE HANDLE LIST BEGIN */
344	dbenv->prdbt = __db_prdbt;
345	/* DB_ENV PRIVATE HANDLE LIST END */
346
347	dbenv->shm_key = INVALID_REGION_SEGID;
348	dbenv->thread_id = __os_id;
349	dbenv->thread_id_string = __env_thread_id_string;
350
351	env = dbenv->env;
352	__os_id(NULL, &env->pid_cache, NULL);
353
354	env->db_ref = 0;
355	TAILQ_INIT(&env->fdlist);
356
357	if (!__db_isbigendian())
358		F_SET(env, ENV_LITTLEENDIAN);
359	F_SET(env, ENV_NO_OUTPUT_SET);
360
361	return (0);
362}
363
364/*
365 * __env_err --
366 *	DbEnv.err method.
367 */
368static void
369#ifdef STDC_HEADERS
370__env_err(const DB_ENV *dbenv, int error, const char *fmt, ...)
371#else
372__env_err(dbenv, error, fmt, va_alist)
373	const DB_ENV *dbenv;
374	int error;
375	const char *fmt;
376	va_dcl
377#endif
378{
379	/* Message with error string, to stderr by default. */
380	DB_REAL_ERR(dbenv, error, DB_ERROR_SET, 1, fmt);
381}
382
383/*
384 * __env_errx --
385 *	DbEnv.errx method.
386 */
387static void
388#ifdef STDC_HEADERS
389__env_errx(const DB_ENV *dbenv, const char *fmt, ...)
390#else
391__env_errx(dbenv, fmt, va_alist)
392	const DB_ENV *dbenv;
393	const char *fmt;
394	va_dcl
395#endif
396{
397	/* Message without error string, to stderr by default. */
398	DB_REAL_ERR(dbenv, 0, DB_ERROR_NOT_SET, 1, fmt);
399}
400
401static int
402__env_get_home(dbenv, homep)
403	DB_ENV *dbenv;
404	const char **homep;
405{
406	ENV *env;
407
408	env = dbenv->env;
409
410	ENV_ILLEGAL_BEFORE_OPEN(env, "DB_ENV->get_home");
411	*homep = env->db_home;
412
413	return (0);
414}
415
416/*
417 * __env_set_alloc --
418 *	{DB_ENV,DB}->set_alloc.
419 *
420 * PUBLIC: int  __env_set_alloc __P((DB_ENV *, void *(*)(size_t),
421 * PUBLIC:          void *(*)(void *, size_t), void (*)(void *)));
422 */
423int
424__env_set_alloc(dbenv, mal_func, real_func, free_func)
425	DB_ENV *dbenv;
426	void *(*mal_func) __P((size_t));
427	void *(*real_func) __P((void *, size_t));
428	void (*free_func) __P((void *));
429{
430	ENV *env;
431
432	env = dbenv->env;
433
434	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_alloc");
435
436	dbenv->db_malloc = mal_func;
437	dbenv->db_realloc = real_func;
438	dbenv->db_free = free_func;
439	return (0);
440}
441
442/*
443 * __env_set_app_dispatch --
444 *	Set the transaction abort recover function.
445 */
446static int
447__env_set_app_dispatch(dbenv, app_dispatch)
448	DB_ENV *dbenv;
449	int (*app_dispatch) __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
450{
451	ENV *env;
452
453	env = dbenv->env;
454
455	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_app_dispatch");
456
457	dbenv->app_dispatch = app_dispatch;
458	return (0);
459}
460
461/*
462 * __env_get_encrypt_flags --
463 *	{DB_ENV,DB}->get_encrypt_flags.
464 *
465 * PUBLIC: int __env_get_encrypt_flags __P((DB_ENV *, u_int32_t *));
466 */
467int
468__env_get_encrypt_flags(dbenv, flagsp)
469	DB_ENV *dbenv;
470	u_int32_t *flagsp;
471{
472#ifdef HAVE_CRYPTO
473	DB_CIPHER *db_cipher;
474#endif
475	ENV *env;
476
477	env = dbenv->env;
478
479#ifdef HAVE_CRYPTO
480	db_cipher = env->crypto_handle;
481	if (db_cipher != NULL && db_cipher->alg == CIPHER_AES)
482		*flagsp = DB_ENCRYPT_AES;
483	else
484		*flagsp = 0;
485	return (0);
486#else
487	COMPQUIET(flagsp, 0);
488	__db_errx(env,
489	    "library build did not include support for cryptography");
490	return (DB_OPNOTSUP);
491#endif
492}
493
494/*
495 * __env_set_encrypt --
496 *	DB_ENV->set_encrypt.
497 *
498 * PUBLIC: int __env_set_encrypt __P((DB_ENV *, const char *, u_int32_t));
499 */
500int
501__env_set_encrypt(dbenv, passwd, flags)
502	DB_ENV *dbenv;
503	const char *passwd;
504	u_int32_t flags;
505{
506#ifdef HAVE_CRYPTO
507	DB_CIPHER *db_cipher;
508	ENV *env;
509	int ret;
510
511	env = dbenv->env;
512
513	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_encrypt");
514#define	OK_CRYPTO_FLAGS	(DB_ENCRYPT_AES)
515
516	if (flags != 0 && LF_ISSET(~OK_CRYPTO_FLAGS))
517		return (__db_ferr(env, "DB_ENV->set_encrypt", 0));
518
519	if (passwd == NULL || strlen(passwd) == 0) {
520		__db_errx(env, "Empty password specified to set_encrypt");
521		return (EINVAL);
522	}
523	if (!CRYPTO_ON(env)) {
524		if ((ret = __os_calloc(env, 1, sizeof(DB_CIPHER), &db_cipher))
525		    != 0)
526			goto err;
527		env->crypto_handle = db_cipher;
528	} else
529		db_cipher = env->crypto_handle;
530
531	if (dbenv->passwd != NULL)
532		__os_free(env, dbenv->passwd);
533	if ((ret = __os_strdup(env, passwd, &dbenv->passwd)) != 0) {
534		__os_free(env, db_cipher);
535		goto err;
536	}
537	/*
538	 * We're going to need this often enough to keep around
539	 */
540	dbenv->passwd_len = strlen(dbenv->passwd) + 1;
541	/*
542	 * The MAC key is for checksumming, and is separate from
543	 * the algorithm.  So initialize it here, even if they
544	 * are using CIPHER_ANY.
545	 */
546	__db_derive_mac(
547	    (u_int8_t *)dbenv->passwd, dbenv->passwd_len, db_cipher->mac_key);
548	switch (flags) {
549	case 0:
550		F_SET(db_cipher, CIPHER_ANY);
551		break;
552	case DB_ENCRYPT_AES:
553		if ((ret =
554		    __crypto_algsetup(env, db_cipher, CIPHER_AES, 0)) != 0)
555			goto err1;
556		break;
557	default:				/* Impossible. */
558		break;
559	}
560	return (0);
561
562err1:
563	__os_free(env, dbenv->passwd);
564	__os_free(env, db_cipher);
565	env->crypto_handle = NULL;
566err:
567	return (ret);
568#else
569	COMPQUIET(passwd, NULL);
570	COMPQUIET(flags, 0);
571
572	__db_errx(dbenv->env,
573	    "library build did not include support for cryptography");
574	return (DB_OPNOTSUP);
575#endif
576}
577#ifndef HAVE_BREW
578static
579#endif
580const FLAG_MAP EnvMap[] = {
581	{ DB_AUTO_COMMIT,	DB_ENV_AUTO_COMMIT },
582	{ DB_CDB_ALLDB,		DB_ENV_CDB_ALLDB },
583	{ DB_DIRECT_DB,		DB_ENV_DIRECT_DB },
584	{ DB_DSYNC_DB,		DB_ENV_DSYNC_DB },
585	{ DB_MULTIVERSION,	DB_ENV_MULTIVERSION },
586	{ DB_NOLOCKING,		DB_ENV_NOLOCKING },
587	{ DB_NOMMAP,		DB_ENV_NOMMAP },
588	{ DB_NOPANIC,		DB_ENV_NOPANIC },
589	{ DB_OVERWRITE,		DB_ENV_OVERWRITE },
590	{ DB_REGION_INIT,	DB_ENV_REGION_INIT },
591	{ DB_TIME_NOTGRANTED,	DB_ENV_TIME_NOTGRANTED },
592	{ DB_TXN_NOSYNC,	DB_ENV_TXN_NOSYNC },
593	{ DB_TXN_NOWAIT,	DB_ENV_TXN_NOWAIT },
594	{ DB_TXN_SNAPSHOT,	DB_ENV_TXN_SNAPSHOT },
595	{ DB_TXN_WRITE_NOSYNC,	DB_ENV_TXN_WRITE_NOSYNC },
596	{ DB_YIELDCPU,		DB_ENV_YIELDCPU }
597};
598
599/*
600 * __env_map_flags -- map from external to internal flags.
601 * PUBLIC: void __env_map_flags __P((const FLAG_MAP *,
602 * PUBLIC:       u_int, u_int32_t *, u_int32_t *));
603 */
604void
605__env_map_flags(flagmap, mapsize, inflagsp, outflagsp)
606	const FLAG_MAP *flagmap;
607	u_int mapsize;
608	u_int32_t *inflagsp, *outflagsp;
609{
610
611	const FLAG_MAP *fmp;
612	u_int i;
613
614	for (i = 0, fmp = flagmap;
615	    i < mapsize / sizeof(flagmap[0]); ++i, ++fmp)
616		if (FLD_ISSET(*inflagsp, fmp->inflag)) {
617			FLD_SET(*outflagsp, fmp->outflag);
618			FLD_CLR(*inflagsp, fmp->inflag);
619			if (*inflagsp == 0)
620				break;
621		}
622}
623
624/*
625 * __env_fetch_flags -- map from internal to external flags.
626 * PUBLIC: void __env_fetch_flags __P((const FLAG_MAP *,
627 * PUBLIC:       u_int, u_int32_t *, u_int32_t *));
628 */
629void
630__env_fetch_flags(flagmap, mapsize, inflagsp, outflagsp)
631	const FLAG_MAP *flagmap;
632	u_int mapsize;
633	u_int32_t *inflagsp, *outflagsp;
634{
635	const FLAG_MAP *fmp;
636	u_int32_t i;
637
638	*outflagsp = 0;
639	for (i = 0, fmp = flagmap;
640	    i < mapsize / sizeof(flagmap[0]); ++i, ++fmp)
641		if (FLD_ISSET(*inflagsp, fmp->outflag))
642			FLD_SET(*outflagsp, fmp->inflag);
643}
644
645static int
646__env_get_flags(dbenv, flagsp)
647	DB_ENV *dbenv;
648	u_int32_t *flagsp;
649{
650	ENV *env;
651
652	__env_fetch_flags(EnvMap, sizeof(EnvMap), &dbenv->flags, flagsp);
653
654	env = dbenv->env;
655	/* Some flags are persisted in the regions. */
656	if (env->reginfo != NULL &&
657	    ((REGENV *)env->reginfo->primary)->panic != 0)
658		FLD_SET(*flagsp, DB_PANIC_ENVIRONMENT);
659
660	return (0);
661}
662
663/*
664 * __env_set_flags --
665 *	DB_ENV->set_flags.
666 *
667 * PUBLIC: int  __env_set_flags __P((DB_ENV *, u_int32_t, int));
668 */
669int
670__env_set_flags(dbenv, flags, on)
671	DB_ENV *dbenv;
672	u_int32_t flags;
673	int on;
674{
675	ENV *env;
676	u_int32_t mapped_flags;
677	int ret;
678
679	env = dbenv->env;
680
681#define	OK_FLAGS							\
682	(DB_AUTO_COMMIT | DB_CDB_ALLDB | DB_DIRECT_DB |			\
683	    DB_DSYNC_DB |  DB_MULTIVERSION | DB_NOLOCKING |		\
684	    DB_NOMMAP | DB_NOPANIC | DB_OVERWRITE |			\
685	    DB_PANIC_ENVIRONMENT | DB_REGION_INIT |			\
686	    DB_TIME_NOTGRANTED | DB_TXN_NOSYNC | DB_TXN_NOWAIT |	\
687	    DB_TXN_SNAPSHOT |	DB_TXN_WRITE_NOSYNC | DB_YIELDCPU)
688
689	if (LF_ISSET(~OK_FLAGS))
690		return (__db_ferr(env, "DB_ENV->set_flags", 0));
691	if (on) {
692		if ((ret = __db_fcchk(env, "DB_ENV->set_flags",
693		    flags, DB_TXN_NOSYNC, DB_TXN_WRITE_NOSYNC)) != 0)
694			return (ret);
695		if (LF_ISSET(DB_DIRECT_DB) && __os_support_direct_io() == 0) {
696			__db_errx(env,
697	"DB_ENV->set_flags: direct I/O either not configured or not supported");
698			return (EINVAL);
699		}
700	}
701
702	if (LF_ISSET(DB_CDB_ALLDB))
703		ENV_ILLEGAL_AFTER_OPEN(env,
704		    "DB_ENV->set_flags: DB_CDB_ALLDB");
705	if (LF_ISSET(DB_PANIC_ENVIRONMENT)) {
706		ENV_ILLEGAL_BEFORE_OPEN(env,
707		    "DB_ENV->set_flags: DB_PANIC_ENVIRONMENT");
708		if (on) {
709			__db_errx(env, "Environment panic set");
710			(void)__env_panic(env, DB_RUNRECOVERY);
711		} else
712			__env_panic_set(env, 0);
713	}
714	if (LF_ISSET(DB_REGION_INIT))
715		ENV_ILLEGAL_AFTER_OPEN(env,
716		    "DB_ENV->set_flags: DB_REGION_INIT");
717
718	/*
719	 * DB_LOG_IN_MEMORY, DB_TXN_NOSYNC and DB_TXN_WRITE_NOSYNC are
720	 * mutually incompatible.  If we're setting one of them, clear all
721	 * current settings.
722	 */
723	if (LF_ISSET(DB_TXN_NOSYNC | DB_TXN_WRITE_NOSYNC)) {
724		F_CLR(dbenv, DB_ENV_TXN_NOSYNC | DB_ENV_TXN_WRITE_NOSYNC);
725		if ((LOGGING_ON(env) || !F_ISSET(env, ENV_OPEN_CALLED)) &&
726		    (ret = __log_set_config(dbenv, DB_LOG_IN_MEMORY, 0)) != 0)
727			return (ret);
728	}
729
730	mapped_flags = 0;
731	__env_map_flags(EnvMap, sizeof(EnvMap), &flags, &mapped_flags);
732	if (on)
733		F_SET(dbenv, mapped_flags);
734	else
735		F_CLR(dbenv, mapped_flags);
736
737	return (0);
738}
739
740static int
741__env_get_data_dirs(dbenv, dirpp)
742	DB_ENV *dbenv;
743	const char ***dirpp;
744{
745	*dirpp = (const char **)dbenv->db_data_dir;
746	return (0);
747}
748
749/*
750 * __env_set_data_dir --
751 *	DB_ENV->set_data_dir.
752 *
753 * PUBLIC: int  __env_set_data_dir __P((DB_ENV *, const char *));
754 */
755int
756__env_set_data_dir(dbenv, dir)
757	DB_ENV *dbenv;
758	const char *dir;
759{
760	ENV *env;
761	int ret;
762
763	env = dbenv->env;
764
765	/*
766	 * The array is NULL-terminated so it can be returned by get_data_dirs
767	 * without a length.
768	 */
769
770#define	DATA_INIT_CNT	20			/* Start with 20 data slots. */
771	if (dbenv->db_data_dir == NULL) {
772		if ((ret = __os_calloc(env, DATA_INIT_CNT,
773		    sizeof(char **), &dbenv->db_data_dir)) != 0)
774			return (ret);
775		dbenv->data_cnt = DATA_INIT_CNT;
776	} else if (dbenv->data_next == dbenv->data_cnt - 2) {
777		dbenv->data_cnt *= 2;
778		if ((ret = __os_realloc(env,
779		    (u_int)dbenv->data_cnt * sizeof(char **),
780		    &dbenv->db_data_dir)) != 0)
781			return (ret);
782	}
783
784	ret = __os_strdup(env,
785	    dir, &dbenv->db_data_dir[dbenv->data_next++]);
786	dbenv->db_data_dir[dbenv->data_next] = NULL;
787	return (ret);
788}
789
790static int
791__env_get_intermediate_dir_mode(dbenv, modep)
792	DB_ENV *dbenv;
793	const char **modep;
794{
795	*modep = dbenv->intermediate_dir_mode;
796	return (0);
797}
798
799/*
800 * __env_set_intermediate_dir_mode --
801 *	DB_ENV->set_intermediate_dir_mode.
802 *
803 * PUBLIC: int  __env_set_intermediate_dir_mode __P((DB_ENV *, const char *));
804 */
805int
806__env_set_intermediate_dir_mode(dbenv, mode)
807	DB_ENV *dbenv;
808	const char *mode;
809{
810	ENV *env;
811	u_int t;
812	int ret;
813
814	env = dbenv->env;
815
816	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_intermediate_dir_mode");
817
818#define	__SETMODE(offset, valid_ch, mask) {				\
819	if (mode[offset] == (valid_ch))					\
820		t |= (mask);						\
821	else if (mode[offset] != '-')					\
822		goto format_err;					\
823}
824	t = 0;
825	__SETMODE(0, 'r', S_IRUSR);
826	__SETMODE(1, 'w', S_IWUSR);
827	__SETMODE(2, 'x', S_IXUSR);
828	__SETMODE(3, 'r', S_IRGRP);
829	__SETMODE(4, 'w', S_IWGRP);
830	__SETMODE(5, 'x', S_IXGRP);
831	__SETMODE(6, 'r', S_IROTH);
832	__SETMODE(7, 'w', S_IWOTH);
833	__SETMODE(8, 'x', S_IXOTH);
834	if (mode[9] != '\0' || t == 0) {
835		/*
836		 * We disallow modes of 0 -- we use 0 to decide the application
837		 * never configured intermediate directory permissions, and we
838		 * shouldn't create intermediate directories.  Besides, setting
839		 * the permissions to 0 makes no sense.
840		 */
841format_err:	__db_errx(env,
842	    "DB_ENV->set_intermediate_dir_mode: illegal mode \"%s\"", mode);
843		return (EINVAL);
844	}
845
846	if (dbenv->intermediate_dir_mode != NULL)
847		__os_free(env, dbenv->intermediate_dir_mode);
848	if ((ret = __os_strdup(env, mode, &dbenv->intermediate_dir_mode)) != 0)
849		return (ret);
850
851	env->dir_mode = (int)t;
852	return (0);
853}
854
855/*
856 * __env_get_errcall --
857 *	{DB_ENV,DB}->get_errcall.
858 *
859 * PUBLIC: void __env_get_errcall __P((DB_ENV *,
860 * PUBLIC:		void (**)(const DB_ENV *, const char *, const char *)));
861 */
862void
863__env_get_errcall(dbenv, errcallp)
864	DB_ENV *dbenv;
865	void (**errcallp) __P((const DB_ENV *, const char *, const char *));
866{
867	*errcallp = dbenv->db_errcall;
868}
869
870/*
871 * __env_set_errcall --
872 *	{DB_ENV,DB}->set_errcall.
873 *
874 * PUBLIC: void __env_set_errcall __P((DB_ENV *,
875 * PUBLIC:		void (*)(const DB_ENV *, const char *, const char *)));
876 */
877void
878__env_set_errcall(dbenv, errcall)
879	DB_ENV *dbenv;
880	void (*errcall) __P((const DB_ENV *, const char *, const char *));
881{
882	ENV *env;
883
884	env = dbenv->env;
885
886	F_CLR(env, ENV_NO_OUTPUT_SET);
887	dbenv->db_errcall = errcall;
888}
889
890/*
891 * __env_get_errfile --
892 *	{DB_ENV,DB}->get_errfile.
893 *
894 * PUBLIC: void __env_get_errfile __P((DB_ENV *, FILE **));
895 */
896void
897__env_get_errfile(dbenv, errfilep)
898	DB_ENV *dbenv;
899	FILE **errfilep;
900{
901	*errfilep = dbenv->db_errfile;
902}
903
904/*
905 * __env_set_errfile --
906 *	{DB_ENV,DB}->set_errfile.
907 *
908 * PUBLIC: void __env_set_errfile __P((DB_ENV *, FILE *));
909 */
910void
911__env_set_errfile(dbenv, errfile)
912	DB_ENV *dbenv;
913	FILE *errfile;
914{
915	ENV *env;
916
917	env = dbenv->env;
918
919	F_CLR(env, ENV_NO_OUTPUT_SET);
920	dbenv->db_errfile = errfile;
921}
922
923/*
924 * __env_get_errpfx --
925 *	{DB_ENV,DB}->get_errpfx.
926 *
927 * PUBLIC: void __env_get_errpfx __P((DB_ENV *, const char **));
928 */
929void
930__env_get_errpfx(dbenv, errpfxp)
931	DB_ENV *dbenv;
932	const char **errpfxp;
933{
934	*errpfxp = dbenv->db_errpfx;
935}
936
937/*
938 * __env_set_errpfx --
939 *	{DB_ENV,DB}->set_errpfx.
940 *
941 * PUBLIC: void __env_set_errpfx __P((DB_ENV *, const char *));
942 */
943void
944__env_set_errpfx(dbenv, errpfx)
945	DB_ENV *dbenv;
946	const char *errpfx;
947{
948	dbenv->db_errpfx = errpfx;
949}
950
951static int
952__env_set_feedback(dbenv, feedback)
953	DB_ENV *dbenv;
954	void (*feedback) __P((DB_ENV *, int, int));
955{
956	dbenv->db_feedback = feedback;
957	return (0);
958}
959
960/*
961 * __env_set_thread_id --
962 *	DB_ENV->set_thread_id
963 */
964static int
965__env_set_thread_id(dbenv, id)
966	DB_ENV *dbenv;
967	void (*id) __P((DB_ENV *, pid_t *, db_threadid_t *));
968{
969	dbenv->thread_id = id;
970	return (0);
971}
972
973/*
974 * __env_set_threadid_string --
975 *	DB_ENV->set_threadid_string
976 */
977static int
978__env_set_thread_id_string(dbenv, thread_id_string)
979	DB_ENV *dbenv;
980	char *(*thread_id_string) __P((DB_ENV *, pid_t, db_threadid_t, char *));
981{
982	dbenv->thread_id_string = thread_id_string;
983	return (0);
984}
985
986/*
987 * __env_set_isalive --
988 *	DB_ENV->set_isalive
989 */
990static int
991__env_set_isalive(dbenv, is_alive)
992	DB_ENV *dbenv;
993	int (*is_alive) __P((DB_ENV *, pid_t, db_threadid_t, u_int32_t));
994{
995	ENV *env;
996
997	env = dbenv->env;
998
999	if (F_ISSET(env, ENV_OPEN_CALLED) && env->thr_nbucket == 0) {
1000		__db_errx(env,
1001		    "is_alive method specified but no thread region allocated");
1002		return (EINVAL);
1003	}
1004	dbenv->is_alive = is_alive;
1005	return (0);
1006}
1007
1008/*
1009 * __env_get_thread_count --
1010 *	DB_ENV->get_thread_count
1011 */
1012static int
1013__env_get_thread_count(dbenv, countp)
1014	DB_ENV *dbenv;
1015	u_int32_t *countp;
1016{
1017	*countp = dbenv->thr_max;
1018	return (0);
1019}
1020
1021/*
1022 * __env_set_thread_count --
1023 *	DB_ENV->set_thread_count
1024 */
1025static int
1026__env_set_thread_count(dbenv, count)
1027	DB_ENV *dbenv;
1028	u_int32_t count;
1029{
1030	ENV *env;
1031
1032	env = dbenv->env;
1033
1034	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_thread_count");
1035	dbenv->thr_max = count;
1036
1037	return (0);
1038}
1039
1040/*
1041 * __env_set_msgcall --
1042 *	{DB_ENV,DB}->set_msgcall.
1043 *
1044 * PUBLIC: void __env_set_msgcall
1045 * PUBLIC:     __P((DB_ENV *, void (*)(const DB_ENV *, const char *)));
1046 */
1047void
1048__env_set_msgcall(dbenv, msgcall)
1049	DB_ENV *dbenv;
1050	void (*msgcall) __P((const DB_ENV *, const char *));
1051{
1052	dbenv->db_msgcall = msgcall;
1053}
1054
1055/*
1056 * __env_get_msgfile --
1057 *	{DB_ENV,DB}->get_msgfile.
1058 *
1059 * PUBLIC: void __env_get_msgfile __P((DB_ENV *, FILE **));
1060 */
1061void
1062__env_get_msgfile(dbenv, msgfilep)
1063	DB_ENV *dbenv;
1064	FILE **msgfilep;
1065{
1066	*msgfilep = dbenv->db_msgfile;
1067}
1068
1069/*
1070 * __env_set_msgfile --
1071 *	{DB_ENV,DB}->set_msgfile.
1072 *
1073 * PUBLIC: void __env_set_msgfile __P((DB_ENV *, FILE *));
1074 */
1075void
1076__env_set_msgfile(dbenv, msgfile)
1077	DB_ENV *dbenv;
1078	FILE *msgfile;
1079{
1080	dbenv->db_msgfile = msgfile;
1081}
1082
1083/*
1084 * __env_set_paniccall --
1085 *	{DB_ENV,DB}->set_paniccall.
1086 *
1087 * PUBLIC: int  __env_set_paniccall __P((DB_ENV *, void (*)(DB_ENV *, int)));
1088 */
1089int
1090__env_set_paniccall(dbenv, paniccall)
1091	DB_ENV *dbenv;
1092	void (*paniccall) __P((DB_ENV *, int));
1093{
1094	dbenv->db_paniccall = paniccall;
1095	return (0);
1096}
1097
1098/*
1099 * __env_set_event_notify --
1100 *	DB_ENV->set_event_notify.
1101 */
1102static int
1103__env_set_event_notify(dbenv, event_func)
1104	DB_ENV *dbenv;
1105	void (*event_func) __P((DB_ENV *, u_int32_t, void *));
1106{
1107	dbenv->db_event_func = event_func;
1108	return (0);
1109}
1110
1111static int
1112__env_get_shm_key(dbenv, shm_keyp)
1113	DB_ENV *dbenv;
1114	long *shm_keyp;			/* !!!: really a key_t *. */
1115{
1116	*shm_keyp = dbenv->shm_key;
1117	return (0);
1118}
1119
1120/*
1121 * __env_set_shm_key --
1122 *	DB_ENV->set_shm_key.
1123 *
1124 * PUBLIC: int  __env_set_shm_key __P((DB_ENV *, long));
1125 */
1126int
1127__env_set_shm_key(dbenv, shm_key)
1128	DB_ENV *dbenv;
1129	long shm_key;			/* !!!: really a key_t. */
1130{
1131	ENV *env;
1132
1133	env = dbenv->env;
1134
1135	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_shm_key");
1136
1137	dbenv->shm_key = shm_key;
1138	return (0);
1139}
1140
1141static int
1142__env_get_tmp_dir(dbenv, dirp)
1143	DB_ENV *dbenv;
1144	const char **dirp;
1145{
1146	*dirp = dbenv->db_tmp_dir;
1147	return (0);
1148}
1149
1150/*
1151 * __env_set_tmp_dir --
1152 *	DB_ENV->set_tmp_dir.
1153 *
1154 * PUBLIC: int  __env_set_tmp_dir __P((DB_ENV *, const char *));
1155 */
1156int
1157__env_set_tmp_dir(dbenv, dir)
1158	DB_ENV *dbenv;
1159	const char *dir;
1160{
1161	ENV *env;
1162
1163	env = dbenv->env;
1164
1165	if (dbenv->db_tmp_dir != NULL)
1166		__os_free(env, dbenv->db_tmp_dir);
1167	return (__os_strdup(env, dir, &dbenv->db_tmp_dir));
1168}
1169
1170static int
1171__env_get_verbose(dbenv, which, onoffp)
1172	DB_ENV *dbenv;
1173	u_int32_t which;
1174	int *onoffp;
1175{
1176	switch (which) {
1177	case DB_VERB_DEADLOCK:
1178	case DB_VERB_FILEOPS:
1179	case DB_VERB_FILEOPS_ALL:
1180	case DB_VERB_RECOVERY:
1181	case DB_VERB_REGISTER:
1182	case DB_VERB_REPLICATION:
1183	case DB_VERB_REP_ELECT:
1184	case DB_VERB_REP_LEASE:
1185	case DB_VERB_REP_MISC:
1186	case DB_VERB_REP_MSGS:
1187	case DB_VERB_REP_SYNC:
1188	case DB_VERB_REPMGR_CONNFAIL:
1189	case DB_VERB_REPMGR_MISC:
1190	case DB_VERB_WAITSFOR:
1191		*onoffp = FLD_ISSET(dbenv->verbose, which) ? 1 : 0;
1192		break;
1193	default:
1194		return (EINVAL);
1195	}
1196	return (0);
1197}
1198
1199/*
1200 * __env_set_verbose --
1201 *	DB_ENV->set_verbose.
1202 *
1203 * PUBLIC: int  __env_set_verbose __P((DB_ENV *, u_int32_t, int));
1204 */
1205int
1206__env_set_verbose(dbenv, which, on)
1207	DB_ENV *dbenv;
1208	u_int32_t which;
1209	int on;
1210{
1211	switch (which) {
1212	case DB_VERB_DEADLOCK:
1213	case DB_VERB_FILEOPS:
1214	case DB_VERB_FILEOPS_ALL:
1215	case DB_VERB_RECOVERY:
1216	case DB_VERB_REGISTER:
1217	case DB_VERB_REPLICATION:
1218	case DB_VERB_REP_ELECT:
1219	case DB_VERB_REP_LEASE:
1220	case DB_VERB_REP_MISC:
1221	case DB_VERB_REP_MSGS:
1222	case DB_VERB_REP_SYNC:
1223	case DB_VERB_REPMGR_CONNFAIL:
1224	case DB_VERB_REPMGR_MISC:
1225	case DB_VERB_WAITSFOR:
1226		if (on)
1227			FLD_SET(dbenv->verbose, which);
1228		else
1229			FLD_CLR(dbenv->verbose, which);
1230		break;
1231	default:
1232		return (EINVAL);
1233	}
1234	return (0);
1235}
1236
1237/*
1238 * __db_mi_env --
1239 *	Method illegally called with public environment.
1240 *
1241 * PUBLIC: int __db_mi_env __P((ENV *, const char *));
1242 */
1243int
1244__db_mi_env(env, name)
1245	ENV *env;
1246	const char *name;
1247{
1248	__db_errx(env,
1249	    "%s: method not permitted when environment specified", name);
1250	return (EINVAL);
1251}
1252
1253/*
1254 * __db_mi_open --
1255 *	Method illegally called after open.
1256 *
1257 * PUBLIC: int __db_mi_open __P((ENV *, const char *, int));
1258 */
1259int
1260__db_mi_open(env, name, after)
1261	ENV *env;
1262	const char *name;
1263	int after;
1264{
1265	__db_errx(env, "%s: method not permitted %s handle's open method",
1266	    name, after ? "after" : "before");
1267	return (EINVAL);
1268}
1269
1270/*
1271 * __env_not_config --
1272 *	Method or function called without required configuration.
1273 *
1274 * PUBLIC: int __env_not_config __P((ENV *, char *, u_int32_t));
1275 */
1276int
1277__env_not_config(env, i, flags)
1278	ENV *env;
1279	char *i;
1280	u_int32_t flags;
1281{
1282	char *sub;
1283
1284	switch (flags) {
1285	case DB_INIT_LOCK:
1286		sub = "locking";
1287		break;
1288	case DB_INIT_LOG:
1289		sub = "logging";
1290		break;
1291	case DB_INIT_MPOOL:
1292		sub = "memory pool";
1293		break;
1294	case DB_INIT_REP:
1295		sub = "replication";
1296		break;
1297	case DB_INIT_TXN:
1298		sub = "transaction";
1299		break;
1300	default:
1301		sub = "<unspecified>";
1302		break;
1303	}
1304	__db_errx(env,
1305    "%s interface requires an environment configured for the %s subsystem",
1306	    i, sub);
1307	return (EINVAL);
1308}
1309
1310static int
1311__env_set_rpc_server(dbenv, cl, host, tsec, ssec, flags)
1312	DB_ENV *dbenv;
1313	void *cl;
1314	const char *host;
1315	long tsec, ssec;
1316	u_int32_t flags;
1317{
1318	ENV *env;
1319
1320	env = dbenv->env;
1321
1322	COMPQUIET(host, NULL);
1323	COMPQUIET(cl, NULL);
1324	COMPQUIET(tsec, 0);
1325	COMPQUIET(ssec, 0);
1326	COMPQUIET(flags, 0);
1327
1328	__db_errx(env, "Berkeley DB was not configured for RPC support");
1329	return (DB_OPNOTSUP);
1330}
1331