db_printlog.c 8.55 KB
Newer Older
unknown's avatar
unknown committed
1 2 3
/*-
 * See the file LICENSE for redistribution information.
 *
unknown's avatar
unknown committed
4
 * Copyright (c) 1996-2002
unknown's avatar
unknown committed
5 6 7 8 9 10 11
 *	Sleepycat Software.  All rights reserved.
 */

#include "db_config.h"

#ifndef lint
static const char copyright[] =
unknown's avatar
unknown committed
12
    "Copyright (c) 1996-2002\nSleepycat Software Inc.  All rights reserved.\n";
unknown's avatar
unknown committed
13
static const char revid[] =
unknown's avatar
unknown committed
14
    "$Id: db_printlog.c,v 11.52 2002/08/08 03:50:38 bostic Exp $";
unknown's avatar
unknown committed
15 16 17 18 19
#endif

#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>

unknown's avatar
unknown committed
20
#include <ctype.h>
unknown's avatar
unknown committed
21 22 23 24 25 26 27
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#endif

#include "db_int.h"
unknown's avatar
unknown committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include "dbinc/db_page.h"
#include "dbinc/btree.h"
#include "dbinc/fop.h"
#include "dbinc/hash.h"
#include "dbinc/log.h"
#include "dbinc/qam.h"
#include "dbinc/rep.h"
#include "dbinc/txn.h"

int main __P((int, char *[]));
int usage __P((void));
int version_check __P((const char *));
int print_app_record __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
int open_rep_db __P((DB_ENV *, DB **, DBC **));
unknown's avatar
unknown committed
42 43 44 45 46 47 48 49

int
main(argc, argv)
	int argc;
	char *argv[];
{
	extern char *optarg;
	extern int optind;
unknown's avatar
unknown committed
50 51 52 53 54 55 56 57
	const char *progname = "db_printlog";
	DB *dbp;
	DBC *dbc;
	DB_ENV	*dbenv;
	DB_LOGC *logc;
	int (**dtab) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
	size_t dtabsize;
	DBT data, keydbt;
unknown's avatar
unknown committed
58
	DB_LSN key;
unknown's avatar
unknown committed
59 60
	int ch, e_close, exitval, nflag, rflag, ret, repflag;
	char *home, *passwd;
unknown's avatar
unknown committed
61

unknown's avatar
unknown committed
62 63
	if ((ret = version_check(progname)) != 0)
		return (ret);
unknown's avatar
unknown committed
64

unknown's avatar
unknown committed
65 66 67 68 69 70 71 72
	dbp = NULL;
	dbc = NULL;
	logc = NULL;
	e_close = exitval = nflag = rflag = repflag = 0;
	home = passwd = NULL;
	dtabsize = 0;
	dtab = NULL;
	while ((ch = getopt(argc, argv, "h:NP:rRV")) != EOF)
unknown's avatar
unknown committed
73 74 75 76 77 78
		switch (ch) {
		case 'h':
			home = optarg;
			break;
		case 'N':
			nflag = 1;
unknown's avatar
unknown committed
79 80 81 82 83 84 85 86
			break;
		case 'P':
			passwd = strdup(optarg);
			memset(optarg, 0, strlen(optarg));
			if (passwd == NULL) {
				fprintf(stderr, "%s: strdup: %s\n",
				    progname, strerror(errno));
				return (EXIT_FAILURE);
unknown's avatar
unknown committed
87 88
			}
			break;
unknown's avatar
unknown committed
89 90 91 92 93 94
		case 'r':
			rflag = 1;
			break;
		case 'R':
			repflag = 1;
			break;
unknown's avatar
unknown committed
95 96
		case 'V':
			printf("%s\n", db_version(NULL, NULL, NULL));
unknown's avatar
unknown committed
97
			return (EXIT_SUCCESS);
unknown's avatar
unknown committed
98 99
		case '?':
		default:
unknown's avatar
unknown committed
100
			return (usage());
unknown's avatar
unknown committed
101 102 103 104 105
		}
	argc -= optind;
	argv += optind;

	if (argc > 0)
unknown's avatar
unknown committed
106
		return (usage());
unknown's avatar
unknown committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124

	/* Handle possible interruptions. */
	__db_util_siginit();

	/*
	 * Create an environment object and initialize it for error
	 * reporting.
	 */
	if ((ret = db_env_create(&dbenv, 0)) != 0) {
		fprintf(stderr,
		    "%s: db_env_create: %s\n", progname, db_strerror(ret));
		goto shutdown;
	}
	e_close = 1;

	dbenv->set_errfile(dbenv, stderr);
	dbenv->set_errpfx(dbenv, progname);

unknown's avatar
unknown committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
	if (nflag) {
		if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) {
			dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING");
			goto shutdown;
		}
		if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) {
			dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC");
			goto shutdown;
		}
	}

	if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
	    passwd, DB_ENCRYPT_AES)) != 0) {
		dbenv->err(dbenv, ret, "set_passwd");
		goto shutdown;
	}

	/*
	 * Set up an app-specific dispatch function so that we can gracefully
	 * handle app-specific log records.
	 */
	if ((ret = dbenv->set_app_dispatch(dbenv, print_app_record)) != 0) {
		dbenv->err(dbenv, ret, "app_dispatch");
unknown's avatar
unknown committed
148 149 150 151 152 153 154
		goto shutdown;
	}

	/*
	 * An environment is required, but as all we're doing is reading log
	 * files, we create one if it doesn't already exist.  If we create
	 * it, create it private so it automatically goes away when we're done.
unknown's avatar
unknown committed
155 156
	 * If we are reading the replication database, do not open the env
	 * with logging, because we don't want to log the opens.
unknown's avatar
unknown committed
157
	 */
unknown's avatar
unknown committed
158 159 160 161 162 163 164 165 166 167
	if (repflag) {
		if ((ret = dbenv->open(dbenv, home,
		    DB_INIT_MPOOL | DB_USE_ENVIRON, 0)) != 0 &&
		    (ret = dbenv->open(dbenv, home,
		    DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0))
		    != 0) {
			dbenv->err(dbenv, ret, "open");
			goto shutdown;
		}
	} else if ((ret = dbenv->open(dbenv, home,
unknown's avatar
unknown committed
168 169 170 171 172 173 174 175
	    DB_JOINENV | DB_USE_ENVIRON, 0)) != 0 &&
	    (ret = dbenv->open(dbenv, home,
	    DB_CREATE | DB_INIT_LOG | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) {
		dbenv->err(dbenv, ret, "open");
		goto shutdown;
	}

	/* Initialize print callbacks. */
unknown's avatar
unknown committed
176 177 178 179 180 181 182 183
	if ((ret = __bam_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
	    (ret = __dbreg_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
	    (ret = __crdel_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
	    (ret = __db_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
	    (ret = __fop_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
	    (ret = __qam_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
	    (ret = __ham_init_print(dbenv, &dtab, &dtabsize)) != 0 ||
	    (ret = __txn_init_print(dbenv, &dtab, &dtabsize)) != 0) {
unknown's avatar
unknown committed
184 185 186 187
		dbenv->err(dbenv, ret, "callback: initialization");
		goto shutdown;
	}

unknown's avatar
unknown committed
188 189 190 191 192 193 194 195 196
	/* Allocate a log cursor. */
	if (repflag) {
		if ((ret = open_rep_db(dbenv, &dbp, &dbc)) != 0)
			goto shutdown;
	} else if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB_ENV->log_cursor");
		goto shutdown;
	}

unknown's avatar
unknown committed
197
	memset(&data, 0, sizeof(data));
unknown's avatar
unknown committed
198
	memset(&keydbt, 0, sizeof(keydbt));
unknown's avatar
unknown committed
199
	while (!__db_util_interrupted()) {
unknown's avatar
unknown committed
200 201 202 203 204 205 206 207 208
		if (repflag) {
			ret = dbc->c_get(dbc,
			    &keydbt, &data, rflag ? DB_PREV : DB_NEXT);
			if (ret == 0)
				key = ((REP_CONTROL *)keydbt.data)->lsn;
		} else
			ret = logc->get(logc,
			    &key, &data, rflag ? DB_PREV : DB_NEXT);
		if (ret != 0) {
unknown's avatar
unknown committed
209 210
			if (ret == DB_NOTFOUND)
				break;
unknown's avatar
unknown committed
211 212
			dbenv->err(dbenv,
			    ret, repflag ? "DB_LOGC->get" : "DBC->get");
unknown's avatar
unknown committed
213 214 215
			goto shutdown;
		}

unknown's avatar
unknown committed
216 217
		ret = __db_dispatch(dbenv,
		    dtab, dtabsize, &data, &key, DB_TXN_PRINT, NULL);
unknown's avatar
unknown committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233

		/*
		 * XXX
		 * Just in case the underlying routines don't flush.
		 */
		(void)fflush(stdout);

		if (ret != 0) {
			dbenv->err(dbenv, ret, "tx: dispatch");
			goto shutdown;
		}
	}

	if (0) {
shutdown:	exitval = 1;
	}
unknown's avatar
unknown committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	if (logc != NULL && (ret = logc->close(logc, 0)) != 0)
		exitval = 1;

	if (dbc != NULL && (ret = dbc->c_close(dbc)) != 0)
		exitval = 1;

	if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0)
		exitval = 1;

	/*
	 * The dtab is allocated by __db_add_recovery (called by *_init_print)
	 * using the library malloc function (__os_malloc).  It thus needs to be
	 * freed using the corresponding free (__os_free).
	 */
	if (dtab != NULL)
		__os_free(dbenv, dtab);
unknown's avatar
unknown committed
250 251 252 253 254 255 256 257 258
	if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) {
		exitval = 1;
		fprintf(stderr,
		    "%s: dbenv->close: %s\n", progname, db_strerror(ret));
	}

	/* Resend any caught signal. */
	__db_util_sigresend();

unknown's avatar
unknown committed
259
	return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
unknown's avatar
unknown committed
260 261
}

unknown's avatar
unknown committed
262
int
unknown's avatar
unknown committed
263 264
usage()
{
unknown's avatar
unknown committed
265 266 267
	fprintf(stderr, "%s\n",
	    "usage: db_printlog [-NrV] [-h home] [-P password]");
	return (EXIT_FAILURE);
unknown's avatar
unknown committed
268 269
}

unknown's avatar
unknown committed
270 271 272
int
version_check(progname)
	const char *progname;
unknown's avatar
unknown committed
273 274 275 276 277 278 279 280 281 282 283
{
	int v_major, v_minor, v_patch;

	/* Make sure we're loaded with the right version of the DB library. */
	(void)db_version(&v_major, &v_minor, &v_patch);
	if (v_major != DB_VERSION_MAJOR ||
	    v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) {
		fprintf(stderr,
	"%s: version %d.%d.%d doesn't match library version %d.%d.%d\n",
		    progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
		    DB_VERSION_PATCH, v_major, v_minor, v_patch);
unknown's avatar
unknown committed
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
		return (EXIT_FAILURE);
	}
	return (0);
}

/* Print an unknown, application-specific log record as best we can. */
int
print_app_record(dbenv, dbt, lsnp, op)
	DB_ENV *dbenv;
	DBT *dbt;
	DB_LSN *lsnp;
	db_recops op;
{
	int ch;
	u_int32_t i, rectype;

	DB_ASSERT(op == DB_TXN_PRINT);
	COMPQUIET(dbenv, NULL);

	/*
	 * Fetch the rectype, which always must be at the beginning of the
	 * record (if dispatching is to work at all).
	 */
	memcpy(&rectype, dbt->data, sizeof(rectype));

	/*
	 * Applications may wish to customize the output here based on the
	 * rectype.  We just print the entire log record in the generic
	 * mixed-hex-and-printable format we use for binary data.
	 */
	printf("[%lu][%lu]application specific record: rec: %lu\n",
	    (u_long)lsnp->file, (u_long)lsnp->offset, (u_long)rectype);
	printf("\tdata: ");
	for (i = 0; i < dbt->size; i++) {
		ch = ((u_int8_t *)dbt->data)[i];
		printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch);
unknown's avatar
unknown committed
320
	}
unknown's avatar
unknown committed
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
	printf("\n\n");

	return (0);
}

int
open_rep_db(dbenv, dbpp, dbcp)
	DB_ENV *dbenv;
	DB **dbpp;
	DBC **dbcp;
{
	int ret;

	DB *dbp;
	*dbpp = NULL;
	*dbcp = NULL;

	if ((ret = db_create(dbpp, dbenv, 0)) != 0) {
		dbenv->err(dbenv, ret, "db_create");
		return (ret);
	}

	dbp = *dbpp;
	if ((ret =
	    dbp->open(dbp, NULL, "__db.rep.db", NULL, DB_BTREE, 0, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB->open");
		goto err;
	}

	if ((ret = dbp->cursor(dbp, NULL, dbcp, 0)) != 0) {
		dbenv->err(dbenv, ret, "DB->cursor");
		goto err;
	}

	return (0);

err:	if (*dbpp != NULL)
		(void)(*dbpp)->close(*dbpp, 0);
	return (ret);
unknown's avatar
unknown committed
360
}