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