1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/db_page.h"
13#include "dbinc/db_am.h"
14
15#ifndef lint
16static const char copyright[] =
17    "Copyright (c) 1996-2009 Oracle.  All rights reserved.\n";
18#endif
19
20typedef struct {			/* XXX: Globals. */
21	const char *progname;		/* Program name. */
22	char	*hdrbuf;		/* Input file header. */
23	u_long	lineno;			/* Input file line number. */
24	u_long	origline;		/* Original file line number. */
25	int	endodata;		/* Reached the end of a database. */
26	int	endofile;		/* Reached the end of the input. */
27	int	version;		/* Input version. */
28	char	*home;			/* Env home. */
29	char	*passwd;		/* Env passwd. */
30	int	private;		/* Private env. */
31	u_int32_t cache;		/* Env cache size. */
32} LDG;
33
34int	badend __P((DB_ENV *));
35void	badnum __P((DB_ENV *));
36int	configure __P((DB_ENV *, DB *, char **, char **, int *));
37int	convprintable __P((DB_ENV *, char *, char **));
38int	db_init __P((DB_ENV *, char *, u_int32_t, int *));
39int	dbt_rdump __P((DB_ENV *, DBT *));
40int	dbt_rprint __P((DB_ENV *, DBT *));
41int	dbt_rrecno __P((DB_ENV *, DBT *, int));
42int	dbt_to_recno __P((DB_ENV *, DBT *, db_recno_t *));
43int	env_create __P((DB_ENV **, LDG *));
44int	load __P((DB_ENV *, char *, DBTYPE, char **, u_int, LDG *, int *));
45int	main __P((int, char *[]));
46int	rheader __P((DB_ENV *, DB *, DBTYPE *, char **, int *, int *));
47int	usage __P((void));
48int	version_check __P((void));
49
50const char *progname;
51
52#define	G(f)	((LDG *)dbenv->app_private)->f
53
54					/* Flags to the load function. */
55#define	LDF_NOHEADER	0x01		/* No dump header. */
56#define	LDF_NOOVERWRITE	0x02		/* Don't overwrite existing rows. */
57#define	LDF_PASSWORD	0x04		/* Encrypt created databases. */
58
59int
60main(argc, argv)
61	int argc;
62	char *argv[];
63{
64	enum { NOTSET, FILEID_RESET, LSN_RESET, STANDARD_LOAD } mode;
65	extern char *optarg;
66	extern int optind;
67	DBTYPE dbtype;
68	DB_ENV	*dbenv;
69	LDG ldg;
70	u_int ldf;
71	int ch, existed, exitval, ret;
72	char **clist, **clp;
73
74	if ((progname = __db_rpath(argv[0])) == NULL)
75		progname = argv[0];
76	else
77		++progname;
78
79	if ((exitval = version_check()) != 0)
80		goto done;
81
82	ldg.progname = progname;
83	ldg.lineno = 0;
84	ldg.endodata = ldg.endofile = 0;
85	ldg.version = 1;
86	ldg.cache = MEGABYTE;
87	ldg.hdrbuf = NULL;
88	ldg.home = NULL;
89	ldg.passwd = NULL;
90
91	mode = NOTSET;
92	ldf = 0;
93	exitval = existed = 0;
94	dbtype = DB_UNKNOWN;
95
96	/* Allocate enough room for configuration arguments. */
97	if ((clp = clist =
98	    (char **)calloc((size_t)argc + 1, sizeof(char *))) == NULL) {
99		fprintf(stderr, "%s: %s\n", ldg.progname, strerror(ENOMEM));
100		exitval = 1;
101		goto done;
102	}
103
104	/*
105	 * There are two modes for db_load: -r and everything else.  The -r
106	 * option zeroes out the database LSN's or resets the file ID, it
107	 * doesn't really "load" a new database.  The functionality is in
108	 * db_load because we don't have a better place to put it, and we
109	 * don't want to create a new utility for just that functionality.
110	 */
111	while ((ch = getopt(argc, argv, "c:f:h:nP:r:Tt:V")) != EOF)
112		switch (ch) {
113		case 'c':
114			if (mode != NOTSET && mode != STANDARD_LOAD) {
115				exitval = usage();
116				goto done;
117			}
118			mode = STANDARD_LOAD;
119
120			*clp++ = optarg;
121			break;
122		case 'f':
123			if (mode != NOTSET && mode != STANDARD_LOAD) {
124				exitval = usage();
125				goto done;
126			}
127			mode = STANDARD_LOAD;
128
129			if (freopen(optarg, "r", stdin) == NULL) {
130				fprintf(stderr, "%s: %s: reopen: %s\n",
131				    ldg.progname, optarg, strerror(errno));
132				exitval = usage();
133				goto done;
134			}
135			break;
136		case 'h':
137			ldg.home = optarg;
138			break;
139		case 'n':
140			if (mode != NOTSET && mode != STANDARD_LOAD) {
141				exitval = usage();
142				goto done;
143			}
144			mode = STANDARD_LOAD;
145
146			ldf |= LDF_NOOVERWRITE;
147			break;
148		case 'P':
149			ldg.passwd = strdup(optarg);
150			memset(optarg, 0, strlen(optarg));
151			if (ldg.passwd == NULL) {
152				fprintf(stderr, "%s: strdup: %s\n",
153				    ldg.progname, strerror(errno));
154				exitval = usage();
155				goto done;
156			}
157			ldf |= LDF_PASSWORD;
158			break;
159		case 'r':
160			if (mode == STANDARD_LOAD) {
161				exitval = usage();
162				goto done;
163			}
164			if (strcmp(optarg, "lsn") == 0)
165				mode = LSN_RESET;
166			else if (strcmp(optarg, "fileid") == 0)
167				mode = FILEID_RESET;
168			else {
169				exitval = usage();
170				goto done;
171			}
172			break;
173		case 'T':
174			if (mode != NOTSET && mode != STANDARD_LOAD) {
175				exitval = usage();
176				goto done;
177			}
178			mode = STANDARD_LOAD;
179
180			ldf |= LDF_NOHEADER;
181			break;
182		case 't':
183			if (mode != NOTSET && mode != STANDARD_LOAD) {
184				exitval = usage();
185				goto done;
186			}
187			mode = STANDARD_LOAD;
188
189			if (strcmp(optarg, "btree") == 0) {
190				dbtype = DB_BTREE;
191				break;
192			}
193			if (strcmp(optarg, "hash") == 0) {
194				dbtype = DB_HASH;
195				break;
196			}
197			if (strcmp(optarg, "recno") == 0) {
198				dbtype = DB_RECNO;
199				break;
200			}
201			if (strcmp(optarg, "queue") == 0) {
202				dbtype = DB_QUEUE;
203				break;
204			}
205			exitval = usage();
206			goto done;
207		case 'V':
208			printf("%s\n", db_version(NULL, NULL, NULL));
209			return (EXIT_SUCCESS);
210		case '?':
211		default:
212			exitval = usage();
213			goto done;
214		}
215	argc -= optind;
216	argv += optind;
217
218	if (argc != 1) {
219		exitval = usage();
220		goto done;
221	}
222
223	/* Handle possible interruptions. */
224	__db_util_siginit();
225
226	/*
227	 * Create an environment object initialized for error reporting, and
228	 * then open it.
229	 */
230	if (env_create(&dbenv, &ldg) != 0)
231		goto shutdown;
232
233	/* If we're resetting the LSNs, that's an entirely separate path. */
234	switch (mode) {
235	case FILEID_RESET:
236		exitval = dbenv->fileid_reset(
237		    dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0);
238		break;
239	case LSN_RESET:
240		exitval = dbenv->lsn_reset(
241		    dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0);
242		break;
243	case NOTSET:
244	case STANDARD_LOAD:
245		while (!ldg.endofile)
246			if (load(dbenv, argv[0], dbtype, clist, ldf,
247			    &ldg, &existed) != 0)
248				goto shutdown;
249		break;
250	}
251
252	if (0) {
253shutdown:	exitval = 1;
254	}
255	if ((ret = dbenv->close(dbenv, 0)) != 0) {
256		exitval = 1;
257		fprintf(stderr,
258		    "%s: dbenv->close: %s\n", ldg.progname, db_strerror(ret));
259	}
260
261	/* Resend any caught signal. */
262	__db_util_sigresend();
263	free(clist);
264	if (ldg.passwd != NULL)
265		free(ldg.passwd);
266
267	/*
268	 * Return 0 on success, 1 if keys existed already, and 2 on failure.
269	 *
270	 * Technically, this is wrong, because exit of anything other than
271	 * 0 is implementation-defined by the ANSI C standard.  I don't see
272	 * any good solutions that don't involve API changes.
273	 */
274done:
275	return (exitval == 0 ? (existed == 0 ? 0 : 1) : 2);
276}
277
278/*
279 * load --
280 *	Load a database.
281 */
282int
283load(dbenv, name, argtype, clist, flags, ldg, existedp)
284	DB_ENV *dbenv;
285	char *name, **clist;
286	DBTYPE argtype;
287	u_int flags;
288	LDG *ldg;
289	int *existedp;
290{
291	DB *dbp;
292	DBC *dbc;
293	DBT key, rkey, data, *readp, *writep;
294	DBTYPE dbtype;
295	DB_TXN *ctxn, *txn;
296	db_recno_t recno, datarecno;
297	u_int32_t put_flags;
298	int ascii_recno, checkprint, hexkeys, keyflag, keys, resize, ret, rval;
299	char *subdb;
300
301	put_flags = LF_ISSET(LDF_NOOVERWRITE) ? DB_NOOVERWRITE : 0;
302	G(endodata) = 0;
303
304	dbc = NULL;
305	subdb = NULL;
306	ctxn = txn = NULL;
307	memset(&key, 0, sizeof(DBT));
308	memset(&data, 0, sizeof(DBT));
309	memset(&rkey, 0, sizeof(DBT));
310
311retry_db:
312	dbtype = DB_UNKNOWN;
313	keys = -1;
314	hexkeys = -1;
315	keyflag = -1;
316
317	/* Create the DB object. */
318	if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
319		dbenv->err(dbenv, ret, "db_create");
320		goto err;
321	}
322
323	/* Read the header -- if there's no header, we expect flat text. */
324	if (LF_ISSET(LDF_NOHEADER)) {
325		checkprint = 1;
326		dbtype = argtype;
327	} else {
328		if (rheader(dbenv,
329		    dbp, &dbtype, &subdb, &checkprint, &keys) != 0)
330			goto err;
331		if (G(endofile))
332			goto done;
333	}
334
335	/*
336	 * Apply command-line configuration changes.  (We apply command-line
337	 * configuration changes to all databases that are loaded, e.g., all
338	 * subdatabases.)
339	 */
340	if (configure(dbenv, dbp, clist, &subdb, &keyflag))
341		goto err;
342
343	if (keys != 1) {
344		if (keyflag == 1) {
345			dbp->err(dbp, EINVAL, "No keys specified in file");
346			goto err;
347		}
348	}
349	else if (keyflag == 0) {
350		dbp->err(dbp, EINVAL, "Keys specified in file");
351		goto err;
352	}
353	else
354		keyflag = 1;
355
356	if (dbtype == DB_BTREE || dbtype == DB_HASH) {
357		if (keyflag == 0)
358			dbp->err(dbp,
359			    EINVAL, "Btree and Hash must specify keys");
360		else
361			keyflag = 1;
362	}
363
364	if (argtype != DB_UNKNOWN) {
365
366		if (dbtype == DB_RECNO || dbtype == DB_QUEUE)
367			if (keyflag != 1 && argtype != DB_RECNO &&
368			    argtype != DB_QUEUE) {
369				dbenv->errx(dbenv,
370			   "improper database type conversion specified");
371				goto err;
372			}
373		dbtype = argtype;
374	}
375
376	if (dbtype == DB_UNKNOWN) {
377		dbenv->errx(dbenv, "no database type specified");
378		goto err;
379	}
380
381	if (keyflag == -1)
382		keyflag = 0;
383
384	/*
385	 * Recno keys have only been printed in hexadecimal starting
386	 * with db_dump format version 3 (DB 3.2).
387	 *
388	 * !!!
389	 * Note that version is set in rheader(), which must be called before
390	 * this assignment.
391	 */
392	hexkeys = (G(version) >= 3 && keyflag == 1 && checkprint == 0);
393
394	if (keyflag == 1 && (dbtype == DB_RECNO || dbtype == DB_QUEUE))
395		ascii_recno = 1;
396	else
397		ascii_recno = 0;
398
399	/* If configured with a password, encrypt databases we create. */
400	if (LF_ISSET(LDF_PASSWORD) &&
401	    (ret = dbp->set_flags(dbp, DB_ENCRYPT)) != 0) {
402		dbp->err(dbp, ret, "DB->set_flags: DB_ENCRYPT");
403		goto err;
404	}
405
406#if 0
407	Set application-specific btree comparison, compression, or hash
408	functions here. For example:
409
410	if ((ret = dbp->set_bt_compare(dbp, local_comparison_func)) != 0) {
411		dbp->err(dbp, ret, "DB->set_bt_compare");
412		goto err;
413	}
414	if ((ret = dbp->set_bt_compress(dbp, local_compress_func,
415	    local_decompress_func)) != 0) {
416		dbp->err(dbp, ret, "DB->set_bt_compress");
417		goto err;
418	}
419	if ((ret = dbp->set_h_hash(dbp, local_hash_func)) != 0) {
420		dbp->err(dbp, ret, "DB->set_h_hash");
421		goto err;
422	}
423#endif
424
425	/* Open the DB file. */
426	if ((ret = dbp->open(dbp, NULL, name, subdb, dbtype,
427	    DB_CREATE | (TXN_ON(dbenv->env) ? DB_AUTO_COMMIT : 0),
428	    DB_MODE_666)) != 0) {
429		dbp->err(dbp, ret, "DB->open: %s", name);
430		goto err;
431	}
432	if (ldg->private != 0) {
433		if ((ret = __db_util_cache(dbp, &ldg->cache, &resize)) != 0)
434			goto err;
435		if (resize) {
436			if ((ret = dbp->close(dbp, 0)) != 0)
437				goto err;
438			dbp = NULL;
439			if ((ret = dbenv->close(dbenv, 0)) != 0)
440				goto err;
441			if ((ret = env_create(&dbenv, ldg)) != 0)
442				goto err;
443			goto retry_db;
444		}
445	}
446
447	/* Initialize the key/data pair. */
448	readp = writep = &key;
449	if (dbtype == DB_RECNO || dbtype == DB_QUEUE) {
450		key.size = sizeof(recno);
451		if (keyflag) {
452			key.data = &datarecno;
453			if (checkprint) {
454				readp = &rkey;
455				goto key_data;
456			}
457		} else
458			key.data = &recno;
459	} else
460key_data:	if ((readp->data = malloc(readp->ulen = 1024)) == NULL) {
461			dbenv->err(dbenv, ENOMEM, NULL);
462			goto err;
463		}
464	if ((data.data = malloc(data.ulen = 1024)) == NULL) {
465		dbenv->err(dbenv, ENOMEM, NULL);
466		goto err;
467	}
468
469	if (TXN_ON(dbenv->env) &&
470	    (ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0)
471		goto err;
472
473	if (put_flags == 0 && (ret = dbp->cursor(dbp,
474	    txn, &dbc, DB_CURSOR_BULK)) != 0)
475		goto err;
476
477	/* Get each key/data pair and add them to the database. */
478	for (recno = 1; !__db_util_interrupted(); ++recno) {
479		if (!keyflag) {
480			if (checkprint) {
481				if (dbt_rprint(dbenv, &data))
482					goto err;
483			} else {
484				if (dbt_rdump(dbenv, &data))
485					goto err;
486			}
487		} else {
488			if (checkprint) {
489				if (dbt_rprint(dbenv, readp))
490					goto err;
491				if (ascii_recno &&
492				    dbt_to_recno(dbenv, readp, &datarecno) != 0)
493					goto err;
494
495				if (!G(endodata) && dbt_rprint(dbenv, &data))
496					goto odd_count;
497			} else {
498				if (ascii_recno) {
499					if (dbt_rrecno(dbenv, readp, hexkeys))
500						goto err;
501				} else
502					if (dbt_rdump(dbenv, readp))
503						goto err;
504
505				if (!G(endodata) && dbt_rdump(dbenv, &data)) {
506odd_count:				dbenv->errx(dbenv,
507					    "odd number of key/data pairs");
508					goto err;
509				}
510			}
511		}
512		if (G(endodata))
513			break;
514retry:
515		if (put_flags != 0 && txn != NULL)
516			if ((ret = dbenv->txn_begin(dbenv, txn, &ctxn, 0)) != 0)
517				goto err;
518		switch (ret = ((put_flags == 0) ?
519		    dbc->put(dbc, writep, &data, DB_KEYLAST) :
520		    dbp->put(dbp, ctxn, writep, &data, put_flags))) {
521		case 0:
522			if (ctxn != NULL) {
523				if ((ret =
524				    ctxn->commit(ctxn, DB_TXN_NOSYNC)) != 0)
525					goto err;
526				ctxn = NULL;
527			}
528			break;
529		case DB_KEYEXIST:
530			*existedp = 1;
531			dbenv->errx(dbenv,
532			    "%s: line %d: key already exists, not loaded:",
533			    name,
534			    !keyflag ? recno : recno * 2 - 1);
535
536			(void)dbenv->prdbt(&key,
537			    checkprint, 0, stderr, __db_pr_callback, 0);
538			break;
539		case DB_LOCK_DEADLOCK:
540			/* If we have a child txn, retry--else it's fatal. */
541			if (ctxn != NULL) {
542				if ((ret = ctxn->abort(ctxn)) != 0)
543					goto err;
544				ctxn = NULL;
545				goto retry;
546			}
547			/* FALLTHROUGH */
548		default:
549			dbenv->err(dbenv, ret, NULL);
550			if (ctxn != NULL) {
551				(void)ctxn->abort(ctxn);
552				ctxn = NULL;
553			}
554			goto err;
555		}
556		if (ctxn != NULL) {
557			if ((ret = ctxn->abort(ctxn)) != 0)
558				goto err;
559			ctxn = NULL;
560		}
561	}
562done:	rval = 0;
563	if (dbc != NULL && (ret = dbc->close(dbc)) != 0) {
564		dbc = NULL;
565		goto err;
566	}
567	if (txn != NULL && (ret = txn->commit(txn, 0)) != 0) {
568		txn = NULL;
569		goto err;
570	}
571
572	if (0) {
573err:		rval = 1;
574		if (dbc != NULL)
575			(void)dbc->close(dbc);
576		if (txn != NULL)
577			(void)txn->abort(txn);
578	}
579
580	/* Close the database. */
581	if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0) {
582		dbenv->err(dbenv, ret, "DB->close");
583		rval = 1;
584	}
585
586	if (G(hdrbuf) != NULL)
587		free(G(hdrbuf));
588	G(hdrbuf) = NULL;
589	/* Free allocated memory. */
590	if (subdb != NULL)
591		free(subdb);
592	if (dbtype != DB_RECNO && dbtype != DB_QUEUE && key.data != NULL)
593		free(key.data);
594	if (rkey.data != NULL)
595		free(rkey.data);
596	free(data.data);
597
598	return (rval);
599}
600
601/*
602 * env_create --
603 *	Create the environment and initialize it for error reporting.
604 */
605int
606env_create(dbenvp, ldg)
607	DB_ENV **dbenvp;
608	LDG *ldg;
609{
610	DB_ENV *dbenv;
611	int ret;
612
613	if ((ret = db_env_create(dbenvp, 0)) != 0) {
614		fprintf(stderr,
615		    "%s: db_env_create: %s\n", ldg->progname, db_strerror(ret));
616		return (ret);
617	}
618	dbenv = *dbenvp;
619	dbenv->set_errfile(dbenv, stderr);
620	dbenv->set_errpfx(dbenv, ldg->progname);
621	if (ldg->passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
622	    ldg->passwd, DB_ENCRYPT_AES)) != 0) {
623		dbenv->err(dbenv, ret, "set_passwd");
624		return (ret);
625	}
626	if ((ret = db_init(dbenv, ldg->home, ldg->cache, &ldg->private)) != 0)
627		return (ret);
628	dbenv->app_private = ldg;
629
630	return (0);
631}
632
633/*
634 * db_init --
635 *	Initialize the environment.
636 */
637int
638db_init(dbenv, home, cache, is_private)
639	DB_ENV *dbenv;
640	char *home;
641	u_int32_t cache;
642	int *is_private;
643{
644	u_int32_t flags;
645	int ret;
646
647	*is_private = 0;
648	/* We may be loading into a live environment.  Try and join. */
649	flags = DB_USE_ENVIRON |
650	    DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN;
651	if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0)
652		return (0);
653	if (ret == DB_VERSION_MISMATCH)
654		goto err;
655
656	/*
657	 * We're trying to load a database.
658	 *
659	 * An environment is required because we may be trying to look at
660	 * databases in directories other than the current one.  We could
661	 * avoid using an environment iff the -h option wasn't specified,
662	 * but that seems like more work than it's worth.
663	 *
664	 * No environment exists (or, at least no environment that includes
665	 * an mpool region exists).  Create one, but make it private so that
666	 * no files are actually created.
667	 */
668	LF_CLR(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN);
669	LF_SET(DB_CREATE | DB_PRIVATE);
670	*is_private = 1;
671	if ((ret = dbenv->set_cachesize(dbenv, 0, cache, 1)) != 0) {
672		dbenv->err(dbenv, ret, "set_cachesize");
673		return (1);
674	}
675	if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0)
676		return (0);
677
678	/* An environment is required. */
679err:	dbenv->err(dbenv, ret, "DB_ENV->open");
680	return (1);
681}
682
683#define	FLAG(name, value, keyword, flag)				\
684	if (strcmp(name, keyword) == 0) {				\
685		switch (*value) {					\
686		case '1':						\
687			if ((ret = dbp->set_flags(dbp, flag)) != 0) {	\
688				dbp->err(dbp, ret, "%s: set_flags: %s",	\
689				    G(progname), name);			\
690				goto err;				\
691			}						\
692			break;						\
693		case '0':						\
694			break;						\
695		default:						\
696			badnum(dbenv);					\
697			goto err;					\
698		}							\
699		continue;						\
700	}
701#define	NUMBER(name, value, keyword, func, t)				\
702	if (strcmp(name, keyword) == 0) {				\
703		if ((ret = __db_getlong(dbenv,				\
704		    NULL, value, 0, LONG_MAX, &val)) != 0 ||		\
705		    (ret = dbp->func(dbp, (t)val)) != 0)		\
706			goto nameerr;					\
707		continue;						\
708	}
709#define	STRING(name, value, keyword, func)				\
710	if (strcmp(name, keyword) == 0) {				\
711		if ((ret = dbp->func(dbp, value[0])) != 0)		\
712			goto nameerr;					\
713		continue;						\
714	}
715
716/*
717 * The code to check a command-line or input header argument against a list
718 * of configuration options.  It's #defined because it's used in two places
719 * and the two places have gotten out of sync more than once.
720 */
721#define	CONFIGURATION_LIST_COMPARE					\
722	NUMBER(name, value, "bt_minkey", set_bt_minkey, u_int32_t);	\
723	  FLAG(name, value, "chksum", DB_CHKSUM);			\
724	NUMBER(name, value, "db_lorder", set_lorder, int);		\
725	NUMBER(name, value, "db_pagesize", set_pagesize, u_int32_t);	\
726	  FLAG(name, value, "duplicates", DB_DUP);			\
727	  FLAG(name, value, "dupsort", DB_DUPSORT);			\
728	NUMBER(name, value, "extentsize", set_q_extentsize, u_int32_t);	\
729	NUMBER(name, value, "h_ffactor", set_h_ffactor, u_int32_t);	\
730	NUMBER(name, value, "h_nelem", set_h_nelem, u_int32_t);		\
731	NUMBER(name, value, "re_len", set_re_len, u_int32_t);		\
732	STRING(name, value, "re_pad", set_re_pad);			\
733	  FLAG(name, value, "recnum", DB_RECNUM);			\
734	  FLAG(name, value, "renumber", DB_RENUMBER);			\
735	if (strcmp(name, "compressed") == 0) {				\
736		switch (*value) {					\
737		case '1':						\
738			if ((ret = dbp->set_bt_compress(dbp, NULL,	\
739				NULL)) != 0)				\
740				goto nameerr;				\
741			break;						\
742		case '0':						\
743			break;						\
744		default:						\
745			badnum(dbenv);					\
746			goto err;					\
747		}							\
748		continue;						\
749	}
750
751/*
752 * configure --
753 *	Handle command-line configuration options.
754 */
755int
756configure(dbenv, dbp, clp, subdbp, keysp)
757	DB_ENV *dbenv;
758	DB *dbp;
759	char **clp, **subdbp;
760	int *keysp;
761{
762	long val;
763	int ret, savech;
764	char *name, *value;
765
766	for (; (name = *clp) != NULL; *--value = savech, ++clp) {
767		if ((value = strchr(name, '=')) == NULL) {
768			dbp->errx(dbp,
769		    "command-line configuration uses name=value format");
770			return (1);
771		}
772		savech = *value;
773		*value++ = '\0';
774
775		if (strcmp(name, "database") == 0 ||
776		    strcmp(name, "subdatabase") == 0) {
777			if (*subdbp != NULL)
778				free(*subdbp);
779			if ((*subdbp = strdup(value)) == NULL) {
780				dbp->err(dbp, ENOMEM, NULL);
781				return (1);
782			}
783			continue;
784		}
785		if (strcmp(name, "keys") == 0) {
786			if (strcmp(value, "1") == 0)
787				*keysp = 1;
788			else if (strcmp(value, "0") == 0)
789				*keysp = 0;
790			else {
791				badnum(dbenv);
792				return (1);
793			}
794			continue;
795		}
796
797		CONFIGURATION_LIST_COMPARE;
798
799		dbp->errx(dbp,
800		    "unknown command-line configuration keyword \"%s\"", name);
801		return (1);
802	}
803	return (0);
804
805nameerr:
806	dbp->err(dbp, ret, "%s: %s=%s", G(progname), name, value);
807err:	return (1);
808}
809
810/*
811 * rheader --
812 *	Read the header message.
813 */
814int
815rheader(dbenv, dbp, dbtypep, subdbp, checkprintp, keysp)
816	DB_ENV *dbenv;
817	DB *dbp;
818	DBTYPE *dbtypep;
819	char **subdbp;
820	int *checkprintp, *keysp;
821{
822	DBT *keys, *kp;
823	size_t buflen, linelen, start;
824	long val;
825	int ch, first, hdr, ret;
826	char *buf, *name, *p, *value;
827	u_int32_t i, nparts;
828
829	*dbtypep = DB_UNKNOWN;
830	*checkprintp = 0;
831	name = NULL;
832
833	/*
834	 * We start with a smallish buffer;  most headers are small.
835	 * We may need to realloc it for a large subdatabase name.
836	 */
837	buflen = 4096;
838	if (G(hdrbuf) == NULL) {
839		hdr = 0;
840		if ((buf = malloc(buflen)) == NULL)
841			goto memerr;
842		G(hdrbuf) = buf;
843		G(origline) = G(lineno);
844	} else {
845		hdr = 1;
846		buf = G(hdrbuf);
847		G(lineno) = G(origline);
848	}
849
850	start = 0;
851	for (first = 1;; first = 0) {
852		++G(lineno);
853
854		/* Read a line, which may be of arbitrary length, into buf. */
855		linelen = 0;
856		buf = &G(hdrbuf)[start];
857		if (hdr == 0) {
858			for (;;) {
859				if ((ch = getchar()) == EOF) {
860					if (!first || ferror(stdin))
861						goto badfmt;
862					G(endofile) = 1;
863					break;
864				}
865
866				/*
867				 * If the buffer is too small, double it.
868				 */
869				if (linelen + start == buflen) {
870					G(hdrbuf) =
871					    realloc(G(hdrbuf), buflen *= 2);
872					if (G(hdrbuf) == NULL)
873						goto memerr;
874					buf = &G(hdrbuf)[start];
875				}
876
877				if (ch == '\n')
878					break;
879
880				buf[linelen++] = ch;
881			}
882			if (G(endofile) == 1)
883				break;
884			buf[linelen++] = '\0';
885		} else
886			linelen = strlen(buf) + 1;
887		start += linelen;
888
889		if (name != NULL) {
890			free(name);
891			name = NULL;
892		}
893		/* If we don't see the expected information, it's an error. */
894		if ((name = strdup(buf)) == NULL)
895			goto memerr;
896		if ((p = strchr(name, '=')) == NULL)
897			goto badfmt;
898		*p++ = '\0';
899
900		value = p--;
901
902		if (name[0] == '\0')
903			goto badfmt;
904
905		/*
906		 * The only values that may be zero-length are database names.
907		 * In the original Berkeley DB code it was possible to create
908		 * zero-length database names, and the db_load code was then
909		 * changed to allow such databases to be be dumped and loaded.
910		 * [#8204]
911		 */
912		if (strcmp(name, "database") == 0 ||
913		    strcmp(name, "subdatabase") == 0) {
914			if ((ret = convprintable(dbenv, value, subdbp)) != 0) {
915				dbp->err(dbp, ret, "error reading db name");
916				goto err;
917			}
918			continue;
919		}
920
921		/* No other values may be zero-length. */
922		if (value[0] == '\0')
923			goto badfmt;
924
925		if (strcmp(name, "HEADER") == 0)
926			break;
927		if (strcmp(name, "VERSION") == 0) {
928			/*
929			 * Version 1 didn't have a "VERSION" header line.  We
930			 * only support versions 1, 2, and 3 of the dump format.
931			 */
932			G(version) = atoi(value);
933
934			if (G(version) > 3) {
935				dbp->errx(dbp,
936				    "line %lu: VERSION %d is unsupported",
937				    G(lineno), G(version));
938				goto err;
939			}
940			continue;
941		}
942		if (strcmp(name, "format") == 0) {
943			if (strcmp(value, "bytevalue") == 0) {
944				*checkprintp = 0;
945				continue;
946			}
947			if (strcmp(value, "print") == 0) {
948				*checkprintp = 1;
949				continue;
950			}
951			goto badfmt;
952		}
953		if (strcmp(name, "type") == 0) {
954			if (strcmp(value, "btree") == 0) {
955				*dbtypep = DB_BTREE;
956				continue;
957			}
958			if (strcmp(value, "hash") == 0) {
959				*dbtypep = DB_HASH;
960				continue;
961			}
962			if (strcmp(value, "recno") == 0) {
963				*dbtypep = DB_RECNO;
964				continue;
965			}
966			if (strcmp(value, "queue") == 0) {
967				*dbtypep = DB_QUEUE;
968				continue;
969			}
970			dbp->errx(dbp, "line %lu: unknown type", G(lineno));
971			goto err;
972		}
973		if (strcmp(name, "keys") == 0) {
974			if (strcmp(value, "1") == 0)
975				*keysp = 1;
976			else if (strcmp(value, "0") == 0)
977				*keysp = 0;
978			else {
979				badnum(dbenv);
980				goto err;
981			}
982			continue;
983		}
984		if (strcmp(name, "nparts") == 0) {
985			if ((ret = __db_getlong(dbenv,
986			    NULL, value, 0, LONG_MAX, &val)) != 0) {
987				badnum(dbenv);
988				goto err;
989			}
990			nparts = (u_int32_t) val;
991			if ((keys =
992			    malloc((nparts - 1) * sizeof(DBT))) == NULL) {
993				dbenv->err(dbenv, ENOMEM, NULL);
994				goto err;
995			}
996			kp = keys;
997			for (i = 1; i < nparts; kp++, i++) {
998				if ((kp->data =
999				     malloc(kp->ulen = 1024)) == NULL) {
1000					dbenv->err(dbenv, ENOMEM, NULL);
1001					goto err;
1002				}
1003				if (*checkprintp) {
1004					if (dbt_rprint(dbenv, kp))
1005						goto err;
1006				} else {
1007					if (dbt_rdump(dbenv, kp))
1008						goto err;
1009				}
1010			}
1011			if ((ret = dbp->set_partition(
1012			     dbp, nparts, keys, NULL)) != 0)
1013				goto err;
1014
1015			continue;
1016		}
1017
1018		CONFIGURATION_LIST_COMPARE;
1019
1020		dbp->errx(dbp,
1021		    "unknown input-file header configuration keyword \"%s\"",
1022		    name);
1023		goto err;
1024	}
1025	ret = 0;
1026
1027	if (0) {
1028nameerr:	dbp->err(dbp, ret, "%s: %s=%s", G(progname), name, value);
1029		ret = 1;
1030	}
1031	if (0) {
1032badfmt:		dbp->errx(dbp, "line %lu: unexpected format", G(lineno));
1033		ret = 1;
1034	}
1035	if (0) {
1036memerr:		dbp->errx(dbp, "unable to allocate memory");
1037err:		ret = 1;
1038	}
1039	if (name != NULL)
1040		free(name);
1041	return (ret);
1042}
1043
1044/*
1045 * Macro to convert a pair of hex bytes to a decimal value.
1046 *
1047 * !!!
1048 * Note that this macro is side-effect safe.  This was done deliberately,
1049 * callers depend on it.
1050 */
1051#define	DIGITIZE(store, v1, v2) {					\
1052	char _v1, _v2;							\
1053	_v1 = (v1);							\
1054	_v2 = (v2);							\
1055	if ((_v1) > 'f' || (_v2) > 'f')					\
1056		return (badend(dbenv));					\
1057	(store) =							\
1058	((_v1) == '0' ? 0 :						\
1059	((_v1) == '1' ? 1 :						\
1060	((_v1) == '2' ? 2 :						\
1061	((_v1) == '3' ? 3 :						\
1062	((_v1) == '4' ? 4 :						\
1063	((_v1) == '5' ? 5 :						\
1064	((_v1) == '6' ? 6 :						\
1065	((_v1) == '7' ? 7 :						\
1066	((_v1) == '8' ? 8 :						\
1067	((_v1) == '9' ? 9 :						\
1068	((_v1) == 'a' ? 10 :						\
1069	((_v1) == 'b' ? 11 :						\
1070	((_v1) == 'c' ? 12 :						\
1071	((_v1) == 'd' ? 13 :						\
1072	((_v1) == 'e' ? 14 : 15))))))))))))))) << 4 |			\
1073	((_v2) == '0' ? 0 :						\
1074	((_v2) == '1' ? 1 :						\
1075	((_v2) == '2' ? 2 :						\
1076	((_v2) == '3' ? 3 :						\
1077	((_v2) == '4' ? 4 :						\
1078	((_v2) == '5' ? 5 :						\
1079	((_v2) == '6' ? 6 :						\
1080	((_v2) == '7' ? 7 :						\
1081	((_v2) == '8' ? 8 :						\
1082	((_v2) == '9' ? 9 :						\
1083	((_v2) == 'a' ? 10 :						\
1084	((_v2) == 'b' ? 11 :						\
1085	((_v2) == 'c' ? 12 :						\
1086	((_v2) == 'd' ? 13 :						\
1087	((_v2) == 'e' ? 14 : 15)))))))))))))));				\
1088}
1089
1090/*
1091 * convprintable --
1092 *	Convert a printable-encoded string into a newly allocated string.
1093 *
1094 * In an ideal world, this would probably share code with dbt_rprint, but
1095 * that's set up to read character-by-character (to avoid large memory
1096 * allocations that aren't likely to be a problem here), and this has fewer
1097 * special cases to deal with.
1098 *
1099 * Note that despite the printable encoding, the char * interface to this
1100 * function (which is, not coincidentally, also used for database naming)
1101 * means that outstr cannot contain any nuls.
1102 */
1103int
1104convprintable(dbenv, instr, outstrp)
1105	DB_ENV *dbenv;
1106	char *instr, **outstrp;
1107{
1108	char *outstr;
1109
1110	/*
1111	 * Just malloc a string big enough for the whole input string;
1112	 * the output string will be smaller (or of equal length).
1113	 *
1114	 * Note that we may be passed a zero-length string and need to
1115	 * be able to duplicate it.
1116	 */
1117	if ((outstr = malloc(strlen(instr) + 1)) == NULL)
1118		return (ENOMEM);
1119
1120	*outstrp = outstr;
1121
1122	for ( ; *instr != '\0'; instr++)
1123		if (*instr == '\\') {
1124			if (*++instr == '\\') {
1125				*outstr++ = '\\';
1126				continue;
1127			}
1128			DIGITIZE(*outstr++, *instr, *++instr);
1129		} else
1130			*outstr++ = *instr;
1131
1132	*outstr = '\0';
1133
1134	return (0);
1135}
1136
1137/*
1138 * dbt_rprint --
1139 *	Read a printable line into a DBT structure.
1140 */
1141int
1142dbt_rprint(dbenv, dbtp)
1143	DB_ENV *dbenv;
1144	DBT *dbtp;
1145{
1146	u_int32_t len;
1147	u_int8_t *p;
1148	int c1, c2, escape, first;
1149	char buf[32];
1150
1151	++G(lineno);
1152
1153	first = 1;
1154	escape = 0;
1155	for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) {
1156		if (c1 == EOF) {
1157			if (len == 0) {
1158				G(endofile) = G(endodata) = 1;
1159				return (0);
1160			}
1161			return (badend(dbenv));
1162		}
1163		if (first) {
1164			first = 0;
1165			if (G(version) > 1) {
1166				if (c1 != ' ') {
1167					buf[0] = c1;
1168					if (fgets(buf + 1,
1169					    sizeof(buf) - 1, stdin) == NULL ||
1170					    strcmp(buf, "DATA=END\n") != 0)
1171						return (badend(dbenv));
1172					G(endodata) = 1;
1173					return (0);
1174				}
1175				continue;
1176			}
1177		}
1178		if (escape) {
1179			if (c1 != '\\') {
1180				if ((c2 = getchar()) == EOF)
1181					return (badend(dbenv));
1182				DIGITIZE(c1, c1, c2);
1183			}
1184			escape = 0;
1185		} else
1186			if (c1 == '\\') {
1187				escape = 1;
1188				continue;
1189			}
1190		if (len >= dbtp->ulen - 10) {
1191			dbtp->ulen *= 2;
1192			if ((dbtp->data =
1193			    realloc(dbtp->data, dbtp->ulen)) == NULL) {
1194				dbenv->err(dbenv, ENOMEM, NULL);
1195				return (1);
1196			}
1197			p = (u_int8_t *)dbtp->data + len;
1198		}
1199		++len;
1200		*p++ = c1;
1201	}
1202	dbtp->size = len;
1203
1204	return (0);
1205}
1206
1207/*
1208 * dbt_rdump --
1209 *	Read a byte dump line into a DBT structure.
1210 */
1211int
1212dbt_rdump(dbenv, dbtp)
1213	DB_ENV *dbenv;
1214	DBT *dbtp;
1215{
1216	u_int32_t len;
1217	u_int8_t *p;
1218	int c1, c2, first;
1219	char buf[32];
1220
1221	++G(lineno);
1222
1223	first = 1;
1224	for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) {
1225		if (c1 == EOF) {
1226			if (len == 0) {
1227				G(endofile) = G(endodata) = 1;
1228				return (0);
1229			}
1230			return (badend(dbenv));
1231		}
1232		if (first) {
1233			first = 0;
1234			if (G(version) > 1) {
1235				if (c1 != ' ') {
1236					buf[0] = c1;
1237					if (fgets(buf + 1,
1238					    sizeof(buf) - 1, stdin) == NULL ||
1239					    strcmp(buf, "DATA=END\n") != 0)
1240						return (badend(dbenv));
1241					G(endodata) = 1;
1242					return (0);
1243				}
1244				continue;
1245			}
1246		}
1247		if ((c2 = getchar()) == EOF)
1248			return (badend(dbenv));
1249		if (len >= dbtp->ulen - 10) {
1250			dbtp->ulen *= 2;
1251			if ((dbtp->data =
1252			    realloc(dbtp->data, dbtp->ulen)) == NULL) {
1253				dbenv->err(dbenv, ENOMEM, NULL);
1254				return (1);
1255			}
1256			p = (u_int8_t *)dbtp->data + len;
1257		}
1258		++len;
1259		DIGITIZE(*p++, c1, c2);
1260	}
1261	dbtp->size = len;
1262
1263	return (0);
1264}
1265
1266/*
1267 * dbt_rrecno --
1268 *	Read a record number dump line into a DBT structure.
1269 */
1270int
1271dbt_rrecno(dbenv, dbtp, ishex)
1272	DB_ENV *dbenv;
1273	DBT *dbtp;
1274	int ishex;
1275{
1276	char buf[32], *p, *q;
1277	u_long recno;
1278
1279	++G(lineno);
1280
1281	if (fgets(buf, sizeof(buf), stdin) == NULL) {
1282		G(endofile) = G(endodata) = 1;
1283		return (0);
1284	}
1285
1286	if (strcmp(buf, "DATA=END\n") == 0) {
1287		G(endodata) = 1;
1288		return (0);
1289	}
1290
1291	if (buf[0] != ' ')
1292		goto err;
1293
1294	/*
1295	 * If we're expecting a hex key, do an in-place conversion
1296	 * of hex to straight ASCII before calling __db_getulong().
1297	 */
1298	if (ishex) {
1299		for (p = q = buf + 1; *q != '\0' && *q != '\n';) {
1300			/*
1301			 * 0-9 in hex are 0x30-0x39, so this is easy.
1302			 * We should alternate between 3's and [0-9], and
1303			 * if the [0-9] are something unexpected,
1304			 * __db_getulong will fail, so we only need to catch
1305			 * end-of-string conditions.
1306			 */
1307			if (*q++ != '3')
1308				goto err;
1309			if (*q == '\n' || *q == '\0')
1310				goto err;
1311			*p++ = *q++;
1312		}
1313		*p = '\0';
1314	}
1315
1316	if (__db_getulong(dbenv, G(progname), buf + 1, 0, 0, &recno))
1317		goto err;
1318
1319	*((db_recno_t *)dbtp->data) = recno;
1320	dbtp->size = sizeof(db_recno_t);
1321	return (0);
1322
1323err:	return (badend(dbenv));
1324}
1325
1326int
1327dbt_to_recno(dbenv, dbt, recnop)
1328	DB_ENV *dbenv;
1329	DBT *dbt;
1330	db_recno_t *recnop;
1331{
1332	char buf[32];				/* Large enough for 2^64. */
1333
1334	memcpy(buf, dbt->data, dbt->size);
1335	buf[dbt->size] = '\0';
1336
1337	return (__db_getulong(dbenv, G(progname), buf, 0, 0, (u_long *)recnop));
1338}
1339
1340/*
1341 * badnum --
1342 *	Display the bad number message.
1343 */
1344void
1345badnum(dbenv)
1346	DB_ENV *dbenv;
1347{
1348	dbenv->errx(dbenv,
1349	    "boolean name=value pairs require a value of 0 or 1");
1350}
1351
1352/*
1353 * badend --
1354 *	Display the bad end to input message.
1355 */
1356int
1357badend(dbenv)
1358	DB_ENV *dbenv;
1359{
1360	dbenv->errx(dbenv, "unexpected end of input data or key/data pair");
1361	return (1);
1362}
1363
1364/*
1365 * usage --
1366 *	Display the usage message.
1367 */
1368int
1369usage()
1370{
1371	(void)fprintf(stderr, "usage: %s %s\n\t%s\n", progname,
1372	    "[-nTV] [-c name=value] [-f file]",
1373    "[-h home] [-P password] [-t btree | hash | recno | queue] db_file");
1374	(void)fprintf(stderr, "usage: %s %s\n",
1375	    progname, "-r lsn | fileid [-h home] [-P password] db_file");
1376	return (EXIT_FAILURE);
1377}
1378
1379int
1380version_check()
1381{
1382	int v_major, v_minor, v_patch;
1383
1384	/* Make sure we're loaded with the right version of the DB library. */
1385	(void)db_version(&v_major, &v_minor, &v_patch);
1386	if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
1387		fprintf(stderr,
1388	"%s: version %d.%d doesn't match library version %d.%d\n",
1389		    progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
1390		    v_major, v_minor);
1391		return (EXIT_FAILURE);
1392	}
1393	return (0);
1394}
1395