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