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