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

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