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