1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 2013 Oracle and/or its affiliates. All rights reserved.
5 *
6 * $Id$
7 */
8
9 #include "db_config.h"
10
11 #include "db_int.h"
12
13 #ifndef lint
14 static const char copyright[] =
15 "Copyright (c) 1996, 2013 Oracle and/or its affiliates. All rights reserved.\n";
16 #endif
17
18 void db_recover_feedback __P((DB_ENV *, int, int));
19 int main __P((int, char *[]));
20 int read_timestamp __P((char *, time_t *));
21 int usage __P((void));
22 int version_check __P((void));
23
24 const char *progname;
25 int newline_needed;
26
27 int
main(argc,argv)28 main(argc, argv)
29 int argc;
30 char *argv[];
31 {
32 extern char *optarg;
33 extern int optind;
34 DB_ENV *dbenv;
35 time_t timestamp;
36 u_int32_t flags;
37 int ch, exitval, fatal_recover, ret, retain_env, set_feedback, verbose;
38 char *home, *passwd;
39
40 if ((progname = __db_rpath(argv[0])) == NULL)
41 progname = argv[0];
42 else
43 ++progname;
44
45 if ((ret = version_check()) != 0)
46 return (ret);
47
48 home = passwd = NULL;
49 timestamp = 0;
50 exitval = fatal_recover = retain_env = set_feedback = verbose = 0;
51 while ((ch = getopt(argc, argv, "cefh:P:t:Vv")) != EOF)
52 switch (ch) {
53 case 'c':
54 fatal_recover = 1;
55 break;
56 case 'e':
57 retain_env = 1;
58 break;
59 case 'f':
60 set_feedback = 1;
61 break;
62 case 'h':
63 home = optarg;
64 break;
65 case 'P':
66 if (passwd != NULL) {
67 fprintf(stderr, DB_STR("5137",
68 "Password may not be specified twice"));
69 free(passwd);
70 return (EXIT_FAILURE);
71 }
72 passwd = strdup(optarg);
73 memset(optarg, 0, strlen(optarg));
74 if (passwd == NULL) {
75 fprintf(stderr, DB_STR_A("5021",
76 "%s: strdup: %s\n", "%s %s\n"),
77 progname, strerror(errno));
78 return (EXIT_FAILURE);
79 }
80 break;
81 case 't':
82 if ((ret = read_timestamp(optarg, ×tamp)) != 0)
83 return (ret);
84 break;
85 case 'V':
86 printf("%s\n", db_version(NULL, NULL, NULL));
87 return (EXIT_SUCCESS);
88 case 'v':
89 verbose = 1;
90 break;
91 case '?':
92 default:
93 return (usage());
94 }
95 argc -= optind;
96 argv += optind;
97
98 if (argc != 0)
99 return (usage());
100
101 /* Handle possible interruptions. */
102 __db_util_siginit();
103
104 /*
105 * Create an environment object and initialize it for error
106 * reporting.
107 */
108 if ((ret = db_env_create(&dbenv, 0)) != 0) {
109 fprintf(stderr,
110 "%s: db_env_create: %s\n", progname, db_strerror(ret));
111 return (EXIT_FAILURE);
112 }
113 dbenv->set_errfile(dbenv, stderr);
114 dbenv->set_errpfx(dbenv, progname);
115 if (set_feedback)
116 (void)dbenv->set_feedback(dbenv, db_recover_feedback);
117 if (verbose)
118 (void)dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1);
119 if (timestamp &&
120 (ret = dbenv->set_tx_timestamp(dbenv, ×tamp)) != 0) {
121 dbenv->err(dbenv, ret, "DB_ENV->set_timestamp");
122 goto err;
123 }
124
125 if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
126 passwd, DB_ENCRYPT_AES)) != 0) {
127 dbenv->err(dbenv, ret, "set_passwd");
128 goto err;
129 }
130
131 /*
132 * Initialize the environment -- we don't actually do anything
133 * else, that all that's needed to run recovery.
134 *
135 * Note that unless the caller specified the -e option, we use a
136 * private environment, as we're about to create a region, and we
137 * don't want to to leave it around. If we leave the region around,
138 * the application that should create it will simply join it instead,
139 * and will then be running with incorrectly sized (and probably
140 * terribly small) caches. Applications that use -e should almost
141 * certainly use DB_CONFIG files in the directory.
142 */
143 flags = 0;
144 LF_SET(DB_CREATE | DB_INIT_LOG |
145 DB_INIT_MPOOL | DB_INIT_TXN | DB_USE_ENVIRON);
146 LF_SET(fatal_recover ? DB_RECOVER_FATAL : DB_RECOVER);
147 LF_SET(retain_env ? DB_INIT_LOCK : DB_PRIVATE);
148 if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) {
149 dbenv->err(dbenv, ret, "DB_ENV->open");
150 goto err;
151 }
152
153 if (0) {
154 err: exitval = 1;
155 }
156
157 /* Flush to the next line of the output device. */
158 if (newline_needed)
159 printf("\n");
160
161 /* Clean up the environment. */
162 if ((ret = dbenv->close(dbenv, 0)) != 0) {
163 exitval = 1;
164 fprintf(stderr,
165 "%s: dbenv->close: %s\n", progname, db_strerror(ret));
166 }
167 if (passwd != NULL)
168 free(passwd);
169
170 /* Resend any caught signal. */
171 __db_util_sigresend();
172
173 return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
174 }
175
176 /*
177 * db_recover_feedback --
178 * Provide feedback on recovery progress.
179 */
180 void
db_recover_feedback(dbenv,opcode,percent)181 db_recover_feedback(dbenv, opcode, percent)
182 DB_ENV *dbenv;
183 int opcode;
184 int percent;
185 {
186 COMPQUIET(dbenv, NULL);
187
188 if (opcode == DB_RECOVER) {
189 printf(DB_STR_A("5022", "\rrecovery %d%% complete", "%d"),
190 percent);
191 (void)fflush(stdout);
192 newline_needed = 1;
193 }
194 }
195
196 #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
197
198 /*
199 * read_timestamp --
200 * Convert a time argument to Epoch seconds.
201 *
202 * Copyright (c) 1993
203 * The Regents of the University of California. All rights reserved.
204 *
205 * Redistribution and use in source and binary forms, with or without
206 * modification, are permitted provided that the following conditions
207 * are met:
208 * 1. Redistributions of source code must retain the above copyright
209 * notice, this list of conditions and the following disclaimer.
210 * 2. Redistributions in binary form must reproduce the above copyright
211 * notice, this list of conditions and the following disclaimer in the
212 * documentation and/or other materials provided with the distribution.
213 * 3. Neither the name of the University nor the names of its contributors
214 * may be used to endorse or promote products derived from this software
215 * without specific prior written permission.
216 *
217 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
218 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
220 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
221 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
222 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
226 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
227 * SUCH DAMAGE.
228 */
229 int
read_timestamp(arg,timep)230 read_timestamp(arg, timep)
231 char *arg;
232 time_t *timep;
233 {
234 struct tm *t;
235 time_t now;
236 int yearset;
237 char *p;
238 /* Start with the current time. */
239 (void)time(&now);
240 if ((t = localtime(&now)) == NULL) {
241 fprintf(stderr, DB_STR_A("5023", "%s: localtime: %s\n",
242 "%s %s\n"), progname, strerror(errno));
243 return (EXIT_FAILURE);
244 }
245 /* [[CC]YY]MMDDhhmm[.SS] */
246 if ((p = strchr(arg, '.')) == NULL)
247 t->tm_sec = 0; /* Seconds defaults to 0. */
248 else {
249 if (strlen(p + 1) != 2)
250 goto terr;
251 *p++ = '\0';
252 t->tm_sec = ATOI2(p);
253 }
254
255 yearset = 0;
256 switch (strlen(arg)) {
257 case 12: /* CCYYMMDDhhmm */
258 t->tm_year = ATOI2(arg);
259 t->tm_year *= 100;
260 yearset = 1;
261 /* FALLTHROUGH */
262 case 10: /* YYMMDDhhmm */
263 if (yearset) {
264 yearset = ATOI2(arg);
265 t->tm_year += yearset;
266 } else {
267 yearset = ATOI2(arg);
268 if (yearset < 69)
269 t->tm_year = yearset + 2000;
270 else
271 t->tm_year = yearset + 1900;
272 }
273 t->tm_year -= 1900; /* Convert to UNIX time. */
274 /* FALLTHROUGH */
275 case 8: /* MMDDhhmm */
276 t->tm_mon = ATOI2(arg);
277 --t->tm_mon; /* Convert from 01-12 to 00-11 */
278 t->tm_mday = ATOI2(arg);
279 t->tm_hour = ATOI2(arg);
280 t->tm_min = ATOI2(arg);
281 break;
282 default:
283 goto terr;
284 }
285
286 t->tm_isdst = -1; /* Figure out DST. */
287
288 *timep = mktime(t);
289 if (*timep == -1) {
290 terr: fprintf(stderr, DB_STR_A("5024",
291 "%s: out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]",
292 "%s"), progname);
293 return (EXIT_FAILURE);
294 }
295 return (0);
296 }
297
298 int
usage()299 usage()
300 {
301 (void)fprintf(stderr, "usage: %s %s\n", progname,
302 "[-cefVv] [-h home] [-P password] [-t [[CC]YY]MMDDhhmm[.SS]]");
303 return (EXIT_FAILURE);
304 }
305
306 int
version_check()307 version_check()
308 {
309 int v_major, v_minor, v_patch;
310
311 /* Make sure we're loaded with the right version of the DB library. */
312 (void)db_version(&v_major, &v_minor, &v_patch);
313 if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
314 fprintf(stderr, DB_STR_A("5025",
315 "%s: version %d.%d doesn't match library version %d.%d\n",
316 "%s %d %d %d %d\n"), progname,
317 DB_VERSION_MAJOR, DB_VERSION_MINOR,
318 v_major, v_minor);
319 return (EXIT_FAILURE);
320 }
321 return (0);
322 }
323