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