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