Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_printlog.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_printlog.c,v 12.5 2005/09/09 12:38:33 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef lint
00013 static const char copyright[] =
00014     "Copyright (c) 1996-2005\nSleepycat Software Inc.  All rights reserved.\n";
00015 #endif
00016 
00017 #ifndef NO_SYSTEM_INCLUDES
00018 #include <sys/types.h>
00019 
00020 #include <ctype.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #endif
00026 
00027 #include "db_int.h"
00028 #include "dbinc/db_page.h"
00029 #include "dbinc/btree.h"
00030 #include "dbinc/fop.h"
00031 #include "dbinc/hash.h"
00032 #include "dbinc/log.h"
00033 #include "dbinc/qam.h"
00034 #include "dbinc/txn.h"
00035 
00036 int lsn_arg __P((char *, DB_LSN *));
00037 int main __P((int, char *[]));
00038 int open_rep_db __P((DB_ENV *, DB **, DBC **));
00039 int print_app_record __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
00040 int usage __P((void));
00041 int version_check __P((void));
00042 
00043 const char *progname;
00044 
00045 int
00046 main(argc, argv)
00047         int argc;
00048         char *argv[];
00049 {
00050         extern char *optarg;
00051         extern int optind;
00052         DB *dbp;
00053         DBC *dbc;
00054         DBT data, keydbt;
00055         DB_ENV  *dbenv;
00056         DB_LOGC *logc;
00057         DB_LSN key, start, stop;
00058         size_t dtabsize;
00059         u_int32_t logcflag;
00060         int ch, cmp, exitval, nflag, rflag, ret, repflag;
00061         int (**dtab) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00062         char *home, *passwd;
00063 
00064         if ((progname = strrchr(argv[0], '/')) == NULL)
00065                 progname = argv[0];
00066         else
00067                 ++progname;
00068 
00069         if ((ret = version_check()) != 0)
00070                 return (ret);
00071 
00072         dbp = NULL;
00073         dbc = NULL;
00074         dbenv = NULL;
00075         logc = NULL;
00076         ZERO_LSN(start);
00077         ZERO_LSN(stop);
00078         dtabsize = 0;
00079         exitval = nflag = rflag = repflag = 0;
00080         dtab = NULL;
00081         home = passwd = NULL;
00082 
00083         while ((ch = getopt(argc, argv, "b:e:h:NP:rRV")) != EOF)
00084                 switch (ch) {
00085                 case 'b':
00086                         if (lsn_arg(optarg, &start))
00087                                 return (usage());
00088                         break;
00089                 case 'e':
00090                         if (lsn_arg(optarg, &stop))
00091                                 return (usage());
00092                         break;
00093                 case 'h':
00094                         home = optarg;
00095                         break;
00096                 case 'N':
00097                         nflag = 1;
00098                         break;
00099                 case 'P':
00100                         passwd = strdup(optarg);
00101                         memset(optarg, 0, strlen(optarg));
00102                         if (passwd == NULL) {
00103                                 fprintf(stderr, "%s: strdup: %s\n",
00104                                     progname, strerror(errno));
00105                                 return (EXIT_FAILURE);
00106                         }
00107                         break;
00108                 case 'r':
00109                         rflag = 1;
00110                         break;
00111                 case 'R':               /* Undocumented */
00112                         repflag = 1;
00113                         break;
00114                 case 'V':
00115                         printf("%s\n", db_version(NULL, NULL, NULL));
00116                         return (EXIT_SUCCESS);
00117                 case '?':
00118                 default:
00119                         return (usage());
00120                 }
00121         argc -= optind;
00122         argv += optind;
00123 
00124         if (argc > 0)
00125                 return (usage());
00126 
00127         /* Handle possible interruptions. */
00128         __db_util_siginit();
00129 
00130         /*
00131          * Create an environment object and initialize it for error
00132          * reporting.
00133          */
00134         if ((ret = db_env_create(&dbenv, 0)) != 0) {
00135                 fprintf(stderr,
00136                     "%s: db_env_create: %s\n", progname, db_strerror(ret));
00137                 goto shutdown;
00138         }
00139 
00140         dbenv->set_errfile(dbenv, stderr);
00141         dbenv->set_errpfx(dbenv, progname);
00142 
00143         if (nflag) {
00144                 if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) {
00145                         dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING");
00146                         goto shutdown;
00147                 }
00148                 if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) {
00149                         dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC");
00150                         goto shutdown;
00151                 }
00152         }
00153 
00154         if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
00155             passwd, DB_ENCRYPT_AES)) != 0) {
00156                 dbenv->err(dbenv, ret, "set_passwd");
00157                 goto shutdown;
00158         }
00159 
00160         /*
00161          * Set up an app-specific dispatch function so that we can gracefully
00162          * handle app-specific log records.
00163          */
00164         if ((ret = dbenv->set_app_dispatch(dbenv, print_app_record)) != 0) {
00165                 dbenv->err(dbenv, ret, "app_dispatch");
00166                 goto shutdown;
00167         }
00168 
00169         /*
00170          * An environment is required, but as all we're doing is reading log
00171          * files, we create one if it doesn't already exist.  If we create
00172          * it, create it private so it automatically goes away when we're done.
00173          * If we are reading the replication database, do not open the env
00174          * with logging, because we don't want to log the opens.
00175          */
00176         if (repflag) {
00177                 if ((ret = dbenv->open(dbenv, home,
00178                     DB_INIT_MPOOL | DB_USE_ENVIRON, 0)) != 0 &&
00179                     (ret == DB_VERSION_MISMATCH ||
00180                     (ret = dbenv->open(dbenv, home,
00181                     DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0))
00182                     != 0)) {
00183                         dbenv->err(dbenv, ret, "DB_ENV->open");
00184                         goto shutdown;
00185                 }
00186         } else if ((ret = dbenv->open(dbenv, home, DB_USE_ENVIRON, 0)) != 0 &&
00187             (ret == DB_VERSION_MISMATCH ||
00188             (ret = dbenv->open(dbenv, home,
00189             DB_CREATE | DB_INIT_LOG | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0)) {
00190                 dbenv->err(dbenv, ret, "DB_ENV->open");
00191                 goto shutdown;
00192         }
00193 
00194         /* Initialize print callbacks. */
00195         if ((ret = __bam_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
00196             (ret = __crdel_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
00197             (ret = __db_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
00198             (ret = __dbreg_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
00199             (ret = __fop_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
00200 #ifdef HAVE_HASH
00201             (ret = __ham_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
00202 #endif
00203 #ifdef HAVE_QUEUE
00204             (ret = __qam_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
00205 #endif
00206             (ret = __txn_init_print(dbenv, &dtab, &dtabsize)) != 0) {
00207                 dbenv->err(dbenv, ret, "callback: initialization");
00208                 goto shutdown;
00209         }
00210 
00211         /* Allocate a log cursor. */
00212         if (repflag) {
00213                 if ((ret = open_rep_db(dbenv, &dbp, &dbc)) != 0)
00214                         goto shutdown;
00215         } else if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0) {
00216                 dbenv->err(dbenv, ret, "DB_ENV->log_cursor");
00217                 goto shutdown;
00218         }
00219 
00220         if (IS_ZERO_LSN(start)) {
00221                 memset(&keydbt, 0, sizeof(keydbt));
00222                 logcflag = rflag ? DB_PREV : DB_NEXT;
00223         } else {
00224                 key = start;
00225                 logcflag = DB_SET;
00226         }
00227         memset(&data, 0, sizeof(data));
00228 
00229         for (; !__db_util_interrupted(); logcflag = rflag ? DB_PREV : DB_NEXT) {
00230                 if (repflag) {
00231                         ret = dbc->c_get(dbc, &keydbt, &data, logcflag);
00232                         if (ret == 0)
00233                                 key = ((REP_CONTROL *)keydbt.data)->lsn;
00234                 } else
00235                         ret = logc->get(logc, &key, &data, logcflag);
00236                 if (ret != 0) {
00237                         if (ret == DB_NOTFOUND)
00238                                 break;
00239                         dbenv->err(dbenv,
00240                             ret, repflag ? "DB_LOGC->get" : "DBC->get");
00241                         goto shutdown;
00242                 }
00243 
00244                 /*
00245                  * We may have reached the end of the range we're displaying.
00246                  */
00247                 if (!IS_ZERO_LSN(stop)) {
00248                         cmp = log_compare(&key, &stop);
00249                         if ((rflag && cmp < 0) || (!rflag && cmp > 0))
00250                                 break;
00251                 }
00252 
00253                 ret = __db_dispatch(dbenv,
00254                     dtab, dtabsize, &data, &key, DB_TXN_PRINT, NULL);
00255 
00256                 /*
00257                  * XXX
00258                  * Just in case the underlying routines don't flush.
00259                  */
00260                 (void)fflush(stdout);
00261 
00262                 if (ret != 0) {
00263                         dbenv->err(dbenv, ret, "tx: dispatch");
00264                         goto shutdown;
00265                 }
00266         }
00267 
00268         if (0) {
00269 shutdown:       exitval = 1;
00270         }
00271         if (logc != NULL && (ret = logc->close(logc, 0)) != 0)
00272                 exitval = 1;
00273 
00274         if (dbc != NULL && (ret = dbc->c_close(dbc)) != 0)
00275                 exitval = 1;
00276 
00277         if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0)
00278                 exitval = 1;
00279 
00280         /*
00281          * The dtab is allocated by __db_add_recovery (called by *_init_print)
00282          * using the library malloc function (__os_malloc).  It thus needs to be
00283          * freed using the corresponding free (__os_free).
00284          */
00285         if (dtab != NULL)
00286                 __os_free(dbenv, dtab);
00287         if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
00288                 exitval = 1;
00289                 fprintf(stderr,
00290                     "%s: dbenv->close: %s\n", progname, db_strerror(ret));
00291         }
00292 
00293         if (passwd != NULL)
00294                 free(passwd);
00295 
00296         /* Resend any caught signal. */
00297         __db_util_sigresend();
00298 
00299         return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
00300 }
00301 
00302 int
00303 usage()
00304 {
00305         fprintf(stderr, "usage: %s %s\n", progname,
00306             "[-NrV] [-b file/offset] [-e file/offset] [-h home] [-P password]");
00307         return (EXIT_FAILURE);
00308 }
00309 
00310 int
00311 version_check()
00312 {
00313         int v_major, v_minor, v_patch;
00314 
00315         /* Make sure we're loaded with the right version of the DB library. */
00316         (void)db_version(&v_major, &v_minor, &v_patch);
00317         if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
00318                 fprintf(stderr,
00319         "%s: version %d.%d doesn't match library version %d.%d\n",
00320                     progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
00321                     v_major, v_minor);
00322                 return (EXIT_FAILURE);
00323         }
00324         return (0);
00325 }
00326 
00327 /* Print an unknown, application-specific log record as best we can. */
00328 int
00329 print_app_record(dbenv, dbt, lsnp, op)
00330         DB_ENV *dbenv;
00331         DBT *dbt;
00332         DB_LSN *lsnp;
00333         db_recops op;
00334 {
00335         int ch;
00336         u_int32_t i, rectype;
00337 
00338         DB_ASSERT(op == DB_TXN_PRINT);
00339 
00340         COMPQUIET(dbenv, NULL);
00341         COMPQUIET(op, DB_TXN_PRINT);
00342 
00343         /*
00344          * Fetch the rectype, which always must be at the beginning of the
00345          * record (if dispatching is to work at all).
00346          */
00347         memcpy(&rectype, dbt->data, sizeof(rectype));
00348 
00349         /*
00350          * Applications may wish to customize the output here based on the
00351          * rectype.  We just print the entire log record in the generic
00352          * mixed-hex-and-printable format we use for binary data.
00353          */
00354         printf("[%lu][%lu]application specific record: rec: %lu\n",
00355             (u_long)lsnp->file, (u_long)lsnp->offset, (u_long)rectype);
00356         printf("\tdata: ");
00357         for (i = 0; i < dbt->size; i++) {
00358                 ch = ((u_int8_t *)dbt->data)[i];
00359                 printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch);
00360         }
00361         printf("\n\n");
00362 
00363         return (0);
00364 }
00365 
00366 int
00367 open_rep_db(dbenv, dbpp, dbcp)
00368         DB_ENV *dbenv;
00369         DB **dbpp;
00370         DBC **dbcp;
00371 {
00372         int ret;
00373 
00374         DB *dbp;
00375         *dbpp = NULL;
00376         *dbcp = NULL;
00377 
00378         if ((ret = db_create(dbpp, dbenv, 0)) != 0) {
00379                 dbenv->err(dbenv, ret, "db_create");
00380                 return (ret);
00381         }
00382 
00383         dbp = *dbpp;
00384         if ((ret =
00385             dbp->open(dbp, NULL, "__db.rep.db", NULL, DB_BTREE, 0, 0)) != 0) {
00386                 dbenv->err(dbenv, ret, "DB->open");
00387                 goto err;
00388         }
00389 
00390         if ((ret = dbp->cursor(dbp, NULL, dbcp, 0)) != 0) {
00391                 dbenv->err(dbenv, ret, "DB->cursor");
00392                 goto err;
00393         }
00394 
00395         return (0);
00396 
00397 err:    if (*dbpp != NULL)
00398                 (void)(*dbpp)->close(*dbpp, 0);
00399         return (ret);
00400 }
00401 
00402 /*
00403  * lsn_arg --
00404  *      Parse a LSN argument.
00405  */
00406 int
00407 lsn_arg(arg, lsnp)
00408         char *arg;
00409         DB_LSN *lsnp;
00410 {
00411         char *p;
00412         u_long uval;
00413 
00414         /*
00415          * Expected format is: lsn.file/lsn.offset.
00416          *
00417          * Don't use getsubopt(3), some systems don't have it.
00418          */
00419         if ((p = strchr(arg, '/')) == NULL)
00420                 return (1);
00421         *p = '\0';
00422 
00423         if (__db_getulong(NULL, progname, arg, 0, 0, &uval))
00424                 return (1);
00425         if (uval > UINT32_MAX)
00426                 return (1);
00427         lsnp->file = uval;
00428         if (__db_getulong(NULL, progname, p + 1, 0, 0, &uval))
00429                 return (1);
00430         if (uval > UINT32_MAX)
00431                 return (1);
00432         lsnp->offset = uval;
00433         return (0);
00434 }

Generated on Sun Dec 25 12:14:17 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2