1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: db_verify.c,v 12.13 2008/01/08 20:58:17 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_verify_main __P((int, char *[])); 19int db_verify_usage __P((void)); 20int db_verify_version_check __P((void)); 21 22const char *progname; 23 24int 25db_verify(args) 26 char *args; 27{ 28 int argc; 29 char **argv; 30 31 __db_util_arg("db_verify", args, &argc, &argv); 32 return (db_verify_main(argc, argv) ? EXIT_FAILURE : EXIT_SUCCESS); 33} 34 35#include <stdio.h> 36#define ERROR_RETURN ERROR 37 38int 39db_verify_main(argc, argv) 40 int argc; 41 char *argv[]; 42{ 43 extern char *optarg; 44 extern int optind, __db_getopt_reset; 45 DB *dbp, *dbp1; 46 DB_ENV *dbenv; 47 u_int32_t flags, cache; 48 int ch, exitval, nflag, private; 49 int quiet, resize, ret; 50 char *home, *passwd; 51 52 if ((progname = __db_rpath(argv[0])) == NULL) 53 progname = argv[0]; 54 else 55 ++progname; 56 57 if ((ret = db_verify_version_check()) != 0) 58 return (ret); 59 60 dbenv = NULL; 61 dbp = NULL; 62 cache = MEGABYTE; 63 exitval = nflag = quiet = 0; 64 flags = 0; 65 home = passwd = NULL; 66 __db_getopt_reset = 1; 67 while ((ch = getopt(argc, argv, "h:NoP:quV")) != EOF) 68 switch (ch) { 69 case 'h': 70 home = optarg; 71 break; 72 case 'N': 73 nflag = 1; 74 break; 75 case 'P': 76 passwd = strdup(optarg); 77 memset(optarg, 0, strlen(optarg)); 78 if (passwd == NULL) { 79 fprintf(stderr, "%s: strdup: %s\n", 80 progname, strerror(errno)); 81 return (EXIT_FAILURE); 82 } 83 break; 84 case 'o': 85 LF_SET(DB_NOORDERCHK); 86 break; 87 case 'q': 88 quiet = 1; 89 break; 90 case 'u': /* Undocumented. */ 91 LF_SET(DB_UNREF); 92 break; 93 case 'V': 94 printf("%s\n", db_version(NULL, NULL, NULL)); 95 return (EXIT_SUCCESS); 96 case '?': 97 default: 98 return (db_verify_usage()); 99 } 100 argc -= optind; 101 argv += optind; 102 103 if (argc <= 0) 104 return (db_verify_usage()); 105 106 /* Handle possible interruptions. */ 107 __db_util_siginit(); 108 109 /* 110 * Create an environment object and initialize it for error 111 * reporting. 112 */ 113retry: if ((ret = db_env_create(&dbenv, 0)) != 0) { 114 fprintf(stderr, 115 "%s: db_env_create: %s\n", progname, db_strerror(ret)); 116 goto shutdown; 117 } 118 119 if (!quiet) { 120 dbenv->set_errfile(dbenv, stderr); 121 dbenv->set_errpfx(dbenv, progname); 122 } 123 124 if (nflag) { 125 if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) { 126 dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING"); 127 goto shutdown; 128 } 129 if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) { 130 dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC"); 131 goto shutdown; 132 } 133 } 134 135 if (passwd != NULL && 136 (ret = dbenv->set_encrypt(dbenv, passwd, DB_ENCRYPT_AES)) != 0) { 137 dbenv->err(dbenv, ret, "set_passwd"); 138 goto shutdown; 139 } 140 /* 141 * Attach to an mpool if it exists, but if that fails, attach to a 142 * private region. In the latter case, declare a reasonably large 143 * cache so that we don't fail when verifying large databases. 144 */ 145 private = 0; 146 if ((ret = 147 dbenv->open(dbenv, home, DB_INIT_MPOOL | DB_USE_ENVIRON, 0)) != 0) { 148 if (ret != DB_VERSION_MISMATCH) { 149 if ((ret = 150 dbenv->set_cachesize(dbenv, 0, cache, 1)) != 0) { 151 dbenv->err(dbenv, ret, "set_cachesize"); 152 goto shutdown; 153 } 154 private = 1; 155 ret = dbenv->open(dbenv, home, DB_CREATE | 156 DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0); 157 } 158 if (ret != 0) { 159 dbenv->err(dbenv, ret, "DB_ENV->open"); 160 goto shutdown; 161 } 162 } 163 164 /* 165 * Find out if we have a transactional environment so that we can 166 * make sure that we don't open the verify database with logging 167 * enabled. 168 */ 169 for (; !__db_util_interrupted() && argv[0] != NULL; ++argv) { 170 if ((ret = db_create(&dbp, dbenv, 0)) != 0) { 171 dbenv->err(dbenv, ret, "%s: db_create", progname); 172 goto shutdown; 173 } 174 175 if (TXN_ON(dbenv->env) && 176 (ret = dbp->set_flags(dbp, DB_TXN_NOT_DURABLE)) != 0) { 177 dbenv->err( 178 dbenv, ret, "%s: db_set_flags", progname); 179 goto shutdown; 180 } 181 182 /* 183 * We create a 2nd dbp to this database to get its pagesize 184 * because the dbp we're using for verify cannot be opened. 185 * 186 * If the database is corrupted, we may not be able to open 187 * it, of course. In that case, just continue, using the 188 * cache size we have. 189 */ 190 if (private) { 191 if ((ret = db_create(&dbp1, dbenv, 0)) != 0) { 192 dbenv->err( 193 dbenv, ret, "%s: db_create", progname); 194 goto shutdown; 195 } 196 197 if (TXN_ON(dbenv->env) && (ret = 198 dbp1->set_flags(dbp1, DB_TXN_NOT_DURABLE)) != 0) { 199 dbenv->err( 200 dbenv, ret, "%s: db_set_flags", progname); 201 goto shutdown; 202 } 203 204 ret = dbp1->open(dbp1, 205 NULL, argv[0], NULL, DB_UNKNOWN, DB_RDONLY, 0); 206 207 /* 208 * If we get here, we can check the cache/page. 209 * !!! 210 * If we have to retry with an env with a larger 211 * cache, we jump out of this loop. However, we 212 * will still be working on the same argv when we 213 * get back into the for-loop. 214 */ 215 if (ret == 0) { 216 if (__db_util_cache( 217 dbp1, &cache, &resize) == 0 && resize) { 218 (void)dbp1->close(dbp1, 0); 219 (void)dbp->close(dbp, 0); 220 dbp = NULL; 221 222 (void)dbenv->close(dbenv, 0); 223 dbenv = NULL; 224 goto retry; 225 } 226 } 227 (void)dbp1->close(dbp1, 0); 228 } 229 230 /* The verify method is a destructor. */ 231 ret = dbp->verify(dbp, argv[0], NULL, NULL, flags); 232 dbp = NULL; 233 if (ret != 0) 234 goto shutdown; 235 } 236 237 if (0) { 238shutdown: exitval = 1; 239 } 240 241 if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0) { 242 exitval = 1; 243 dbenv->err(dbenv, ret, "close"); 244 } 245 if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) { 246 exitval = 1; 247 fprintf(stderr, 248 "%s: dbenv->close: %s\n", progname, db_strerror(ret)); 249 } 250 251 if (passwd != NULL) 252 free(passwd); 253 254 /* Resend any caught signal. */ 255 __db_util_sigresend(); 256 257 return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 258} 259 260int 261db_verify_usage() 262{ 263 fprintf(stderr, "usage: %s %s\n", progname, 264 "[-NoqV] [-h home] [-P password] db_file ..."); 265 return (EXIT_FAILURE); 266} 267 268int 269db_verify_version_check() 270{ 271 int v_major, v_minor, v_patch; 272 273 /* Make sure we're loaded with the right version of the DB library. */ 274 (void)db_version(&v_major, &v_minor, &v_patch); 275 if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) { 276 fprintf(stderr, 277 "%s: version %d.%d doesn't match library version %d.%d\n", 278 progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, 279 v_major, v_minor); 280 return (EXIT_FAILURE); 281 } 282 return (0); 283} 284