Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / util / db_log_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: db_log_verify.c,v 0f73af5ae3da 2010/05/10 05:38:40 alexander $
7  */
8 #include "db_config.h"
9
10 #include "db_int.h"
11
12 #define MB 1024 * 1024
13
14 int main __P((int, char *[]));
15 int lsn_arg __P((char *, DB_LSN *));
16 int usage __P((void));
17 int version_check __P((void));
18 int db_log_verify_app_record __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
19 const char *progname;
20
21 int
22 main(argc, argv)
23         int argc;
24         char *argv[];
25 {
26         extern char *optarg;
27         extern int optind;
28         DB_ENV  *dbenv;
29         DB_LSN start, stop;
30         int ch, cmb, exitval, nflag, rflag, ret, vsn_mismtch;
31         time_t starttime, endtime;
32         char *dbfile, *dbname, *home, *lvhome, *passwd;
33         DB_LOG_VERIFY_CONFIG lvconfig;
34
35         vsn_mismtch = 0;
36         if ((progname = __db_rpath(argv[0])) == NULL)
37                 progname = argv[0];
38         else
39                 ++progname;
40
41         if ((ret = version_check()) != 0)
42                 return (ret);
43
44         dbenv = NULL;
45         dbfile = dbname = home = lvhome = passwd = NULL;
46         exitval = nflag = rflag = 0;
47         starttime = endtime = 0;
48         ZERO_LSN(start);
49         ZERO_LSN(stop);
50
51         memset(&lvconfig, 0, sizeof(lvconfig));
52
53         while ((ch = getopt(argc, argv, "b:cC:d:D:e:h:H:NP:Vvs:z:")) != EOF)
54                 switch (ch) {
55                 case 'b':
56                         /* Don't use getsubopt(3), not all systems have it. */
57                         if (lsn_arg(optarg, &start))
58                                 return (usage());
59                         break;
60                 case 'c':
61                         lvconfig.continue_after_fail = 1;
62                         break;
63                 case 'C':
64                         cmb = atoi(optarg);
65                         if (cmb <= 0)
66                                 return (usage());
67                         lvconfig.cachesize = cmb * MB;
68                         break;
69                 case 'd':
70                         dbfile = optarg;
71                         break;
72                 case 'D':
73                         dbname = optarg;
74                         break;
75                 case 'e':
76                         /* Don't use getsubopt(3), not all systems have it. */
77                         if (lsn_arg(optarg, &stop))
78                                 return (usage());
79                         break;
80                 case 'h':
81                         home = optarg;
82                         break;
83                 case 'H':
84                         lvhome = optarg;
85                         break;
86                 case 'N':
87                         nflag = 1;
88                         break;
89                 case 'P':
90                         if ((ret = __os_strdup(NULL, optarg, &passwd)) != 0) {
91                                 __db_err(NULL, ret, "__os_strdup: ");
92                                 return (EXIT_FAILURE);
93                         }
94                         memset(optarg, 0, strlen(optarg));
95                         break;
96                 case 'V':
97                         printf("%s\n", db_version(NULL, NULL, NULL));
98                         return (EXIT_SUCCESS);
99                 case 'v':
100                         lvconfig.verbose = 1;
101                         break;
102                 case 's':
103                         starttime = atoi(optarg);
104                         break;
105                 case 'z':
106                         endtime = atoi(optarg);
107                         break;
108                 case '?':
109                 default:
110                         return (usage());
111                 }
112         argc -= optind;
113         argv += optind;
114
115         if (argc > 0)
116                 return (usage());
117
118         lvconfig.temp_envhome = lvhome;
119         lvconfig.dbfile = dbfile;
120         lvconfig.dbname = dbname;
121         lvconfig.start_lsn = start;
122         lvconfig.end_lsn = stop;
123         lvconfig.start_time = starttime;
124         lvconfig.end_time = endtime;
125
126 create_again:
127         /*
128          * Create an environment object and initialize it for error
129          * reporting.
130          */
131         if ((ret = db_env_create(&dbenv, 0)) != 0) {
132                 fprintf(stderr,
133                     "%s: db_env_create: %s\n", progname, db_strerror(ret));
134                 goto err;
135         }
136
137         dbenv->set_errfile(dbenv, stderr);
138         dbenv->set_errpfx(dbenv, progname);
139
140         if (nflag) {
141                 if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) {
142                         dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING");
143                         goto err;
144                 }
145                 if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) {
146                         dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC");
147                         goto err;
148                 }
149         }
150
151         if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
152             passwd, DB_ENCRYPT_AES)) != 0) {
153                 dbenv->err(dbenv, ret, "set_passwd");
154                 goto err;
155         }
156
157         /*
158          * Set up an app-specific dispatch function so that we can gracefully
159          * handle app-specific log records.
160          */
161         if ((ret = dbenv->set_app_dispatch(
162             dbenv, db_log_verify_app_record)) != 0) {
163                 dbenv->err(dbenv, ret, "app_dispatch");
164                 goto err;
165         }
166
167         /*
168          * An environment is required, but as all we're doing is reading log
169          * files, we create one if it doesn't already exist.  If we create
170          * it, create it private so it automatically goes away when we're done.
171          * If we are reading the replication database, do not open the env
172          * with logging, because we don't want to log the opens.
173          */
174         if (!vsn_mismtch && (ret = dbenv->open(dbenv, home,
175             DB_USE_ENVIRON, 0)) != 0) {
176                 if (dbenv->close(dbenv, 0) != 0) {
177                         dbenv = NULL;
178                         goto err;
179                 }
180                 vsn_mismtch = 1;
181                 goto create_again;
182         }
183         if (vsn_mismtch && (ret = dbenv->open(dbenv, home, DB_CREATE |
184             DB_INIT_LOG | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) {
185                 dbenv->err(dbenv, ret, "DB_ENV->open");
186                 goto err;
187         }
188
189         /* Handle possible interruptions. */
190         __db_util_siginit();
191
192         if ((ret = dbenv->log_verify(dbenv, &lvconfig)) != 0)
193                 goto err;
194
195         if (0) {
196 err:            exitval = 1;
197         }
198
199         if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
200                 exitval = 1;
201                 fprintf(stderr,
202                     "%s: dbenv->close: %s\n", progname, db_strerror(ret));
203         }
204
205         /* Resend any caught signal. */
206         __db_util_sigresend();
207
208         if (passwd != NULL)
209                 __os_free(NULL, passwd);
210
211         return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
212 }
213
214 int
215 usage()
216 {
217         fprintf(stderr, "\nusage: %s %s\n%s\n%s\n%s\n%s\n", progname,
218             "[-NcvV] [-h home] "
219             "[-H temporary environment home for internal use]",
220             "[-P password] [-C cache size in megabytes]",
221             "[-d db file name] [-D db name]",
222             "[-b file/offset] [-e file/offset]",
223             "[-s start time] [-z end time]");
224
225         return (EXIT_FAILURE);
226 }
227
228 int
229 version_check()
230 {
231         int v_major, v_minor, v_patch;
232
233         /* Make sure we're loaded with the right version of the DB library. */
234         (void)db_version(&v_major, &v_minor, &v_patch);
235         if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
236                 fprintf(stderr, DB_STR_A("5003",
237                     "%s: version %d.%d doesn't match library version %d.%d\n",
238                     "%s %d %d %d %d\n"), progname,
239                     DB_VERSION_MAJOR, DB_VERSION_MINOR,
240                     v_major, v_minor);
241                 return (EXIT_FAILURE);
242         }
243         return (0);
244 }
245
246 /*
247  * Print an unknown, application-specific log record as best we can, this is
248  * all we can do to such a log record during the verification. The counting
249  * is done in __db_dispatch because we can't pass the log verify handle into
250  * this function.
251  */
252 int
253 db_log_verify_app_record(dbenv, dbt, lsnp, op)
254         DB_ENV *dbenv;
255         DBT *dbt;
256         DB_LSN *lsnp;
257         db_recops op;
258 {
259         u_int32_t i, len, len2, rectype;
260         int ret;
261         u_int8_t ch;
262         char *buf, *p;
263
264         DB_ASSERT(dbenv->env, op == DB_TXN_LOG_VERIFY);
265         COMPQUIET(op, DB_TXN_LOG_VERIFY);
266         ch = 0;
267         ret = 0;
268         i = len = len2 = rectype = 0;
269         buf = p = NULL;
270
271         /*
272          * Fetch the rectype, which always must be at the beginning of the
273          * record (if dispatching is to work at all).
274          */
275         memcpy(&rectype, dbt->data, sizeof(rectype));
276
277         /*
278          * Applications may wish to customize the output here based on the
279          * rectype.  We just print the entire log record in the generic
280          * mixed-hex-and-printable format we use for binary data.
281          */
282         if ((ret = __os_malloc(dbenv->env,
283             len = 256 + 2 * dbt->size, &buf)) != 0)
284                 goto err;
285         memset(buf, 0, len);
286         snprintf(buf, len, DB_STR_A("5004",
287             "[%lu][%lu] App-specific log record: %lu\n\tdata: ",
288             "%lu %lu %lu"), (u_long)lsnp->file, (u_long)lsnp->offset,
289             (u_long)rectype);
290
291         /*
292          * Each unprintable character takes up several bytes, so be aware of
293          * memory violation.
294          */
295         for (i = 0; i < dbt->size && len2 < len; i++) {
296                 ch = ((u_int8_t *)dbt->data)[i];
297                 len2 = (u_int32_t)strlen(buf);
298                 p = buf + len2;
299                 snprintf(p, len - len2 - 1,
300                     isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch);
301         }
302         len2 = (u_int32_t)strlen(buf);
303         p = buf + len2;
304         snprintf(p, len - len2 - 1, "\n\n");
305         __db_msg(dbenv->env, "%s", buf);
306
307 err:    if (buf != NULL)
308                 __os_free(dbenv->env, buf);
309         return (ret);
310 }
311
312 /*
313  * lsn_arg --
314  *      Parse a LSN argument.
315  */
316 int
317 lsn_arg(arg, lsnp)
318         char *arg;
319         DB_LSN *lsnp;
320 {
321         u_long uval;
322         char *p;
323
324         /*
325          * Expected format is: lsn.file/lsn.offset.
326          */
327         if ((p = strchr(arg, '/')) == NULL)
328                 return (1);
329         *p = '\0';
330
331         if (__db_getulong(NULL, progname, arg, 0, UINT32_MAX, &uval))
332                 return (1);
333         lsnp->file = uval;
334         if (__db_getulong(NULL, progname, p + 1, 0, UINT32_MAX, &uval))
335                 return (1);
336         lsnp->offset = uval;
337         return (0);
338 }