1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: db_upgrade.c,v 12.13 2008/01/08 20:58:16 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12
13#ifndef lint
14static const char copyright[] =
15    "Copyright (c) 1996,2008 Oracle.  All rights reserved.\n";
16#endif
17
18int main __P((int, char *[]));
19int usage __P((void));
20int version_check __P((void));
21
22const char *progname;
23
24int
25main(argc, argv)
26	int argc;
27	char *argv[];
28{
29	extern char *optarg;
30	extern int optind;
31	DB *dbp;
32	DB_ENV *dbenv;
33	u_int32_t flags;
34	int ch, exitval, nflag, ret, t_ret, verbose;
35	char *home, *passwd;
36
37	if ((progname = __db_rpath(argv[0])) == NULL)
38		progname = argv[0];
39	else
40		++progname;
41
42	if ((ret = version_check()) != 0)
43		return (ret);
44
45	dbenv = NULL;
46	flags = nflag = verbose = 0;
47	exitval = 0;
48	home = passwd = NULL;
49	while ((ch = getopt(argc, argv, "h:NP:sVv")) != EOF)
50		switch (ch) {
51		case 'h':
52			home = optarg;
53			break;
54		case 'N':
55			nflag = 1;
56			break;
57		case 'P':
58			passwd = strdup(optarg);
59			memset(optarg, 0, strlen(optarg));
60			if (passwd == NULL) {
61				fprintf(stderr, "%s: strdup: %s\n",
62				    progname, strerror(errno));
63				return (EXIT_FAILURE);
64			}
65			break;
66		case 's':
67			LF_SET(DB_DUPSORT);
68			break;
69		case 'V':
70			printf("%s\n", db_version(NULL, NULL, NULL));
71			return (EXIT_SUCCESS);
72		case 'v':
73			verbose = 1;
74			break;
75		case '?':
76		default:
77			return (usage());
78		}
79	argc -= optind;
80	argv += optind;
81
82	if (argc <= 0)
83		return (usage());
84
85	/* Handle possible interruptions. */
86	__db_util_siginit();
87
88	/*
89	 * Create an environment object and initialize it for error
90	 * reporting.
91	 */
92	if ((ret = db_env_create(&dbenv, 0)) != 0) {
93		fprintf(stderr, "%s: db_env_create: %s\n",
94		    progname, db_strerror(ret));
95		goto shutdown;
96	}
97
98	dbenv->set_errfile(dbenv, stderr);
99	dbenv->set_errpfx(dbenv, progname);
100
101	if (nflag) {
102		if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) {
103			dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING");
104			goto shutdown;
105		}
106		if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) {
107			dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC");
108			goto shutdown;
109		}
110	}
111
112	if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
113	    passwd, DB_ENCRYPT_AES)) != 0) {
114		dbenv->err(dbenv, ret, "set_passwd");
115		goto shutdown;
116	}
117
118	/*
119	 * If attaching to a pre-existing environment fails, create a
120	 * private one and try again.
121	 */
122	if ((ret = dbenv->open(dbenv, home, DB_USE_ENVIRON, 0)) != 0 &&
123	    (ret == DB_VERSION_MISMATCH ||
124	    (ret = dbenv->open(dbenv, home,
125	    DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON,
126	    0)) != 0)) {
127		dbenv->err(dbenv, ret, "DB_ENV->open");
128		goto shutdown;
129	}
130
131	for (; !__db_util_interrupted() && argv[0] != NULL; ++argv) {
132		if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
133			fprintf(stderr,
134			    "%s: db_create: %s\n", progname, db_strerror(ret));
135			goto shutdown;
136		}
137		dbp->set_errfile(dbp, stderr);
138		dbp->set_errpfx(dbp, progname);
139		if ((ret = dbp->upgrade(dbp, argv[0], flags)) != 0)
140			dbp->err(dbp, ret, "DB->upgrade: %s", argv[0]);
141		if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) {
142			dbenv->err(dbenv, ret, "DB->close: %s", argv[0]);
143			ret = t_ret;
144		}
145		if (ret != 0)
146			goto shutdown;
147		/*
148		 * People get concerned if they don't see a success message.
149		 * If verbose is set, give them one.
150		 */
151		if (verbose)
152			printf("%s: %s upgraded successfully\n",
153			    progname, argv[0]);
154	}
155
156	if (0) {
157shutdown:	exitval = 1;
158	}
159	if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
160		exitval = 1;
161		fprintf(stderr,
162		    "%s: dbenv->close: %s\n", progname, db_strerror(ret));
163	}
164
165	if (passwd != NULL)
166		free(passwd);
167
168	/* Resend any caught signal. */
169	__db_util_sigresend();
170
171	return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
172}
173
174int
175usage()
176{
177	fprintf(stderr, "usage: %s %s\n", progname,
178	    "[-NsVv] [-h home] [-P password] db_file ...");
179	return (EXIT_FAILURE);
180}
181
182int
183version_check()
184{
185	int v_major, v_minor, v_patch;
186
187	/* Make sure we're loaded with the right version of the DB library. */
188	(void)db_version(&v_major, &v_minor, &v_patch);
189	if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
190		fprintf(stderr,
191	"%s: version %d.%d doesn't match library version %d.%d\n",
192		    progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
193		    v_major, v_minor);
194		return (EXIT_FAILURE);
195	}
196	return (0);
197}
198