• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/db-4.8.30/build_vxworks/db_printlog/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/db_page.h"
13#include "dbinc/btree.h"
14#include "dbinc/fop.h"
15#include "dbinc/hash.h"
16#include "dbinc/log.h"
17#include "dbinc/qam.h"
18#include "dbinc/txn.h"
19
20#ifndef lint
21static const char copyright[] =
22    "Copyright (c) 1996-2009 Oracle.  All rights reserved.\n";
23#endif
24
25int db_printlog_print_app_record __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
26int db_printlog_env_init_print __P((ENV *, u_int32_t, DB_DISTAB *));
27int db_printlog_env_init_print_42 __P((ENV *, DB_DISTAB *));
28int db_printlog_env_init_print_43 __P((ENV *, DB_DISTAB *));
29int db_printlog_env_init_print_47 __P((ENV *, DB_DISTAB *));
30int db_printlog_lsn_arg __P((char *, DB_LSN *));
31int db_printlog_main __P((int, char *[]));
32int db_printlog_open_rep_db __P((DB_ENV *, DB **, DBC **));
33int db_printlog_usage __P((void));
34int db_printlog_version_check __P((void));
35
36const char *progname;
37
38int
39db_printlog(args)
40	char *args;
41{
42	int argc;
43	char **argv;
44
45	__db_util_arg("db_printlog", args, &argc, &argv);
46	return (db_printlog_main(argc, argv) ? EXIT_FAILURE : EXIT_SUCCESS);
47}
48
49#include <stdio.h>
50#define	ERROR_RETURN	ERROR
51
52int
53db_printlog_main(argc, argv)
54	int argc;
55	char *argv[];
56{
57	extern char *optarg;
58	extern int optind, __db_getopt_reset;
59	DB *dbp;
60	DBC *dbc;
61	DBT data, keydbt;
62	DB_DISTAB dtab;
63	DB_ENV	*dbenv;
64	DB_LOGC *logc;
65	DB_LSN key, start, stop, verslsn;
66	ENV *env;
67	u_int32_t logcflag, newversion, version;
68	int ch, cmp, exitval, nflag, rflag, ret, repflag;
69	char *home, *passwd;
70
71	if ((progname = __db_rpath(argv[0])) == NULL)
72		progname = argv[0];
73	else
74		++progname;
75
76	if ((ret = db_printlog_version_check()) != 0)
77		return (ret);
78
79	dbp = NULL;
80	dbc = NULL;
81	dbenv = NULL;
82	logc = NULL;
83	ZERO_LSN(start);
84	ZERO_LSN(stop);
85	exitval = nflag = rflag = repflag = 0;
86	home = passwd = NULL;
87
88	memset(&dtab, 0, sizeof(dtab));
89
90	__db_getopt_reset = 1;
91	while ((ch = getopt(argc, argv, "b:e:h:NP:rRV")) != EOF)
92		switch (ch) {
93		case 'b':
94			/* Don't use getsubopt(3), not all systems have it. */
95			if (db_printlog_lsn_arg(optarg, &start))
96				return (db_printlog_usage());
97			break;
98		case 'e':
99			/* Don't use getsubopt(3), not all systems have it. */
100			if (db_printlog_lsn_arg(optarg, &stop))
101				return (db_printlog_usage());
102			break;
103		case 'h':
104			home = optarg;
105			break;
106		case 'N':
107			nflag = 1;
108			break;
109		case 'P':
110			passwd = strdup(optarg);
111			memset(optarg, 0, strlen(optarg));
112			if (passwd == NULL) {
113				fprintf(stderr, "%s: strdup: %s\n",
114				    progname, strerror(errno));
115				return (EXIT_FAILURE);
116			}
117			break;
118		case 'r':
119			rflag = 1;
120			break;
121		case 'R':		/* Undocumented */
122			repflag = 1;
123			break;
124		case 'V':
125			printf("%s\n", db_version(NULL, NULL, NULL));
126			return (EXIT_SUCCESS);
127		case '?':
128		default:
129			return (db_printlog_usage());
130		}
131	argc -= optind;
132	argv += optind;
133
134	if (argc > 0)
135		return (db_printlog_usage());
136
137	/* Handle possible interruptions. */
138	__db_util_siginit();
139
140	/*
141	 * Create an environment object and initialize it for error
142	 * reporting.
143	 */
144	if ((ret = db_env_create(&dbenv, 0)) != 0) {
145		fprintf(stderr,
146		    "%s: db_env_create: %s\n", progname, db_strerror(ret));
147		goto shutdown;
148	}
149
150	dbenv->set_errfile(dbenv, stderr);
151	dbenv->set_errpfx(dbenv, progname);
152
153	if (nflag) {
154		if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) {
155			dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING");
156			goto shutdown;
157		}
158		if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) {
159			dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC");
160			goto shutdown;
161		}
162	}
163
164	if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
165	    passwd, DB_ENCRYPT_AES)) != 0) {
166		dbenv->err(dbenv, ret, "set_passwd");
167		goto shutdown;
168	}
169
170	/*
171	 * Set up an app-specific dispatch function so that we can gracefully
172	 * handle app-specific log records.
173	 */
174	if ((ret = dbenv->set_app_dispatch(
175	    dbenv, db_printlog_print_app_record)) != 0) {
176		dbenv->err(dbenv, ret, "app_dispatch");
177		goto shutdown;
178	}
179
180	/*
181	 * An environment is required, but as all we're doing is reading log
182	 * files, we create one if it doesn't already exist.  If we create
183	 * it, create it private so it automatically goes away when we're done.
184	 * If we are reading the replication database, do not open the env
185	 * with logging, because we don't want to log the opens.
186	 */
187	if (repflag) {
188		if ((ret = dbenv->open(dbenv, home,
189		    DB_INIT_MPOOL | DB_USE_ENVIRON, 0)) != 0 &&
190		    (ret == DB_VERSION_MISMATCH ||
191		    (ret = dbenv->open(dbenv, home,
192		    DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0))
193		    != 0)) {
194			dbenv->err(dbenv, ret, "DB_ENV->open");
195			goto shutdown;
196		}
197	} else if ((ret = dbenv->open(dbenv, home, DB_USE_ENVIRON, 0)) != 0 &&
198	    (ret == DB_VERSION_MISMATCH ||
199	    (ret = dbenv->open(dbenv, home,
200	    DB_CREATE | DB_INIT_LOG | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0)) {
201		dbenv->err(dbenv, ret, "DB_ENV->open");
202		goto shutdown;
203	}
204	env = dbenv->env;
205
206	/* Allocate a log cursor. */
207	if (repflag) {
208		if ((ret = db_printlog_open_rep_db(dbenv, &dbp, &dbc)) != 0)
209			goto shutdown;
210	} else if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0) {
211		dbenv->err(dbenv, ret, "DB_ENV->log_cursor");
212		goto shutdown;
213	}
214
215	if (IS_ZERO_LSN(start)) {
216		memset(&keydbt, 0, sizeof(keydbt));
217		logcflag = rflag ? DB_PREV : DB_NEXT;
218	} else {
219		key = start;
220		logcflag = DB_SET;
221	}
222	memset(&data, 0, sizeof(data));
223
224	/*
225	 * If we're using the repflag, we're immediately initializing
226	 * the print table.  Use the current version.  If we're printing
227	 * the log then initialize version to 0 so that we get the
228	 * correct version right away.
229	 */
230	if (repflag)
231		version = DB_LOGVERSION;
232	else
233		version = 0;
234	ZERO_LSN(verslsn);
235
236	/* Initialize print callbacks if repflag. */
237	if (repflag &&
238	    (ret = db_printlog_env_init_print(env, version, &dtab)) != 0) {
239		dbenv->err(dbenv, ret, "callback: initialization");
240		goto shutdown;
241	}
242	for (; !__db_util_interrupted(); logcflag = rflag ? DB_PREV : DB_NEXT) {
243		if (repflag) {
244			ret = dbc->get(dbc, &keydbt, &data, logcflag);
245			if (ret == 0)
246				key = ((__rep_control_args *)keydbt.data)->lsn;
247		} else
248			ret = logc->get(logc, &key, &data, logcflag);
249		if (ret != 0) {
250			if (ret == DB_NOTFOUND)
251				break;
252			dbenv->err(dbenv,
253			    ret, repflag ? "DBC->get" : "DB_LOGC->get");
254			goto shutdown;
255		}
256
257		/*
258		 * We may have reached the end of the range we're displaying.
259		 */
260		if (!IS_ZERO_LSN(stop)) {
261			cmp = LOG_COMPARE(&key, &stop);
262			if ((rflag && cmp < 0) || (!rflag && cmp > 0))
263				break;
264		}
265		if (!repflag && key.file != verslsn.file) {
266			/*
267			 * If our log file changed, we need to see if the
268			 * version of the log file changed as well.
269			 * If it changed, reset the print table.
270			 */
271			if ((ret = logc->version(logc, &newversion, 0)) != 0) {
272				dbenv->err(dbenv, ret, "DB_LOGC->version");
273				goto shutdown;
274			}
275			if (version != newversion) {
276				version = newversion;
277				if ((ret = db_printlog_env_init_print(env, version,
278				    &dtab)) != 0) {
279					dbenv->err(dbenv, ret,
280					    "callback: initialization");
281					goto shutdown;
282				}
283			}
284		}
285
286		ret = __db_dispatch(dbenv->env,
287		    &dtab, &data, &key, DB_TXN_PRINT, NULL);
288
289		/*
290		 * XXX
291		 * Just in case the underlying routines don't flush.
292		 */
293		(void)fflush(stdout);
294
295		if (ret != 0) {
296			dbenv->err(dbenv, ret, "tx: dispatch");
297			goto shutdown;
298		}
299	}
300
301	if (0) {
302shutdown:	exitval = 1;
303	}
304	if (logc != NULL && (ret = logc->close(logc, 0)) != 0)
305		exitval = 1;
306
307	if (dbc != NULL && (ret = dbc->close(dbc)) != 0)
308		exitval = 1;
309
310	if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0)
311		exitval = 1;
312
313	if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
314		exitval = 1;
315		fprintf(stderr,
316		    "%s: dbenv->close: %s\n", progname, db_strerror(ret));
317	}
318
319	if (passwd != NULL)
320		free(passwd);
321
322	/* Resend any caught signal. */
323	__db_util_sigresend();
324
325	return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
326}
327
328/*
329 * env_init_print --
330 */
331int
332db_printlog_env_init_print(env, version, dtabp)
333	ENV *env;
334	u_int32_t version;
335	DB_DISTAB *dtabp;
336{
337	int ret;
338
339	/*
340	 * We need to prime the print table with the current print
341	 * functions.  Then we overwrite only specific entries based on
342	 * each previous version we support.
343	 */
344	if ((ret = __bam_init_print(env, dtabp)) != 0)
345		goto err;
346	if ((ret = __crdel_init_print(env, dtabp)) != 0)
347		goto err;
348	if ((ret = __db_init_print(env, dtabp)) != 0)
349		goto err;
350	if ((ret = __dbreg_init_print(env, dtabp)) != 0)
351		goto err;
352	if ((ret = __fop_init_print(env, dtabp)) != 0)
353		goto err;
354#ifdef HAVE_HASH
355	if ((ret = __ham_init_print(env, dtabp)) != 0)
356		goto err;
357#endif
358#ifdef HAVE_QUEUE
359	if ((ret = __qam_init_print(env, dtabp)) != 0)
360		goto err;
361#endif
362	if ((ret = __txn_init_print(env, dtabp)) != 0)
363		goto err;
364
365	switch (version) {
366	case DB_LOGVERSION:
367		ret = 0;
368		break;
369
370	/*
371	 * There are no log record/recovery differences between
372	 * 4.4 and 4.5.  The log version changed due to checksum.
373	 * There are no log recovery differences between
374	 * 4.5 and 4.6.  The name of the rep_gen in txn_checkpoint
375	 * changed (to spare, since we don't use it anymore).
376	 */
377	case DB_LOGVERSION_48:
378		if ((ret = __db_add_recovery_int(env, dtabp,
379		    __db_pg_sort_44_print, DB___db_pg_sort_44)) != 0)
380			goto err;
381		break;
382	case DB_LOGVERSION_47:
383	case DB_LOGVERSION_46:
384	case DB_LOGVERSION_45:
385	case DB_LOGVERSION_44:
386		ret = db_printlog_env_init_print_47(env, dtabp);
387		break;
388	case DB_LOGVERSION_43:
389		ret = db_printlog_env_init_print_43(env, dtabp);
390		break;
391	case DB_LOGVERSION_42:
392		ret = db_printlog_env_init_print_42(env, dtabp);
393		break;
394	default:
395		env->dbenv->errx(env->dbenv,
396		    "Unknown version %lu", (u_long)version);
397		ret = EINVAL;
398		break;
399	}
400err:	return (ret);
401}
402
403int
404db_printlog_env_init_print_42(env, dtabp)
405	ENV *env;
406	DB_DISTAB *dtabp;
407{
408	int ret;
409
410	if ((ret = __db_add_recovery_int(env, dtabp,
411	   __bam_split_42_print, DB___bam_split_42)) != 0)
412		goto err;
413	if ((ret = __db_add_recovery_int(env, dtabp,
414	    __db_relink_42_print, DB___db_relink_42)) != 0)
415		goto err;
416	if ((ret = __db_add_recovery_int(env, dtabp,
417	    __db_pg_alloc_42_print, DB___db_pg_alloc_42)) != 0)
418		goto err;
419	if ((ret = __db_add_recovery_int(env, dtabp,
420	    __db_pg_free_42_print, DB___db_pg_free_42)) != 0)
421		goto err;
422	if ((ret = __db_add_recovery_int(env, dtabp,
423	    __db_pg_freedata_42_print, DB___db_pg_freedata_42)) != 0)
424		goto err;
425#if HAVE_HASH
426	if ((ret = __db_add_recovery_int(env, dtabp,
427	    __ham_metagroup_42_print, DB___ham_metagroup_42)) != 0)
428		goto err;
429	if ((ret = __db_add_recovery_int(env, dtabp,
430	    __ham_groupalloc_42_print, DB___ham_groupalloc_42)) != 0)
431		goto err;
432#endif
433	if ((ret = __db_add_recovery_int(env, dtabp,
434	    __txn_ckp_42_print, DB___txn_ckp_42)) != 0)
435		goto err;
436	if ((ret = __db_add_recovery_int(env, dtabp,
437	    __txn_regop_42_print, DB___txn_regop_42)) != 0)
438		goto err;
439	if ((ret = __db_add_recovery_int(env, dtabp,
440	    __fop_create_42_print, DB___fop_create_42)) != 0)
441		goto err;
442	if ((ret = __db_add_recovery_int(env, dtabp,
443	    __fop_write_42_print, DB___fop_write_42)) != 0)
444		goto err;
445	if ((ret = __db_add_recovery_int(env, dtabp,
446	    __fop_rename_42_print, DB___fop_rename_42)) != 0)
447		goto err;
448	if ((ret = __db_add_recovery_int(env, dtabp,
449	    __fop_rename_42_print, DB___fop_rename_noundo_46)) != 0)
450		goto err;
451	if ((ret = __db_add_recovery_int(env, dtabp,
452	    __txn_xa_regop_42_print, DB___txn_xa_regop_42)) != 0)
453		goto err;
454err:
455	return (ret);
456}
457
458int
459db_printlog_env_init_print_43(env, dtabp)
460	ENV *env;
461	DB_DISTAB *dtabp;
462{
463	int ret;
464
465	if ((ret = __db_add_recovery_int(env, dtabp,
466	    __bam_relink_43_print, DB___bam_relink_43)) != 0)
467		goto err;
468	if ((ret = __db_add_recovery_int(env, dtabp,
469	   __bam_split_42_print, DB___bam_split_42)) != 0)
470		goto err;
471	/*
472	 * We want to use the 4.2-based txn_regop record.
473	 */
474	if ((ret = __db_add_recovery_int(env, dtabp,
475	    __txn_regop_42_print, DB___txn_regop_42)) != 0)
476		goto err;
477
478	if ((ret = __db_add_recovery_int(env, dtabp,
479	    __fop_create_42_print, DB___fop_create_42)) != 0)
480		goto err;
481	if ((ret = __db_add_recovery_int(env, dtabp,
482	    __fop_write_42_print, DB___fop_write_42)) != 0)
483		goto err;
484	if ((ret = __db_add_recovery_int(env, dtabp,
485	    __fop_rename_42_print, DB___fop_rename_42)) != 0)
486		goto err;
487	if ((ret = __db_add_recovery_int(env, dtabp,
488	    __fop_rename_42_print, DB___fop_rename_noundo_46)) != 0)
489		goto err;
490	if ((ret = __db_add_recovery_int(env, dtabp,
491	    __txn_xa_regop_42_print, DB___txn_xa_regop_42)) != 0)
492		goto err;
493err:
494	return (ret);
495}
496
497/*
498 * env_init_print_47 --
499 *
500 */
501int
502db_printlog_env_init_print_47(env, dtabp)
503	ENV *env;
504	DB_DISTAB *dtabp;
505{
506	int ret;
507
508	if ((ret = __db_add_recovery_int(env, dtabp,
509	   __bam_split_42_print, DB___bam_split_42)) != 0)
510		goto err;
511	if ((ret = __db_add_recovery_int(env, dtabp,
512	    __db_pg_sort_44_print, DB___db_pg_sort_44)) != 0)
513		goto err;
514	if ((ret = __db_add_recovery_int(env, dtabp,
515	    __db_pg_sort_44_print, DB___db_pg_sort_44)) != 0)
516		goto err;
517	if ((ret = __db_add_recovery_int(env, dtabp,
518	    __fop_create_42_print, DB___fop_create_42)) != 0)
519		goto err;
520	if ((ret = __db_add_recovery_int(env, dtabp,
521	    __fop_write_42_print, DB___fop_write_42)) != 0)
522		goto err;
523	if ((ret = __db_add_recovery_int(env, dtabp,
524	    __fop_rename_42_print, DB___fop_rename_42)) != 0)
525		goto err;
526	if ((ret = __db_add_recovery_int(env, dtabp,
527	    __fop_rename_42_print, DB___fop_rename_noundo_46)) != 0)
528		goto err;
529	if ((ret = __db_add_recovery_int(env, dtabp,
530	    __txn_xa_regop_42_print, DB___txn_xa_regop_42)) != 0)
531		goto err;
532
533err:
534	return (ret);
535}
536
537int
538db_printlog_usage()
539{
540	fprintf(stderr, "usage: %s %s\n", progname,
541	    "[-NrV] [-b file/offset] [-e file/offset] [-h home] [-P password]");
542	return (EXIT_FAILURE);
543}
544
545int
546db_printlog_version_check()
547{
548	int v_major, v_minor, v_patch;
549
550	/* Make sure we're loaded with the right version of the DB library. */
551	(void)db_version(&v_major, &v_minor, &v_patch);
552	if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
553		fprintf(stderr,
554	"%s: version %d.%d doesn't match library version %d.%d\n",
555		    progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
556		    v_major, v_minor);
557		return (EXIT_FAILURE);
558	}
559	return (0);
560}
561
562/* Print an unknown, application-specific log record as best we can. */
563int
564db_printlog_print_app_record(dbenv, dbt, lsnp, op)
565	DB_ENV *dbenv;
566	DBT *dbt;
567	DB_LSN *lsnp;
568	db_recops op;
569{
570	u_int32_t i, rectype;
571	int ch;
572
573	DB_ASSERT(dbenv->env, op == DB_TXN_PRINT);
574
575	COMPQUIET(dbenv, NULL);
576	COMPQUIET(op, DB_TXN_PRINT);
577
578	/*
579	 * Fetch the rectype, which always must be at the beginning of the
580	 * record (if dispatching is to work at all).
581	 */
582	memcpy(&rectype, dbt->data, sizeof(rectype));
583
584	/*
585	 * Applications may wish to customize the output here based on the
586	 * rectype.  We just print the entire log record in the generic
587	 * mixed-hex-and-printable format we use for binary data.
588	 */
589	printf("[%lu][%lu]application specific record: rec: %lu\n",
590	    (u_long)lsnp->file, (u_long)lsnp->offset, (u_long)rectype);
591	printf("\tdata: ");
592	for (i = 0; i < dbt->size; i++) {
593		ch = ((u_int8_t *)dbt->data)[i];
594		printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch);
595	}
596	printf("\n\n");
597
598	return (0);
599}
600
601int
602db_printlog_open_rep_db(dbenv, dbpp, dbcp)
603	DB_ENV *dbenv;
604	DB **dbpp;
605	DBC **dbcp;
606{
607	int ret;
608
609	DB *dbp;
610	*dbpp = NULL;
611	*dbcp = NULL;
612
613	if ((ret = db_create(dbpp, dbenv, 0)) != 0) {
614		dbenv->err(dbenv, ret, "db_create");
615		return (ret);
616	}
617
618	dbp = *dbpp;
619	if ((ret =
620	    dbp->open(dbp, NULL, REPDBNAME, NULL, DB_BTREE, 0, 0)) != 0) {
621		dbenv->err(dbenv, ret, "DB->open");
622		goto err;
623	}
624
625	if ((ret = dbp->cursor(dbp, NULL, dbcp, 0)) != 0) {
626		dbenv->err(dbenv, ret, "DB->cursor");
627		goto err;
628	}
629
630	return (0);
631
632err:	if (*dbpp != NULL)
633		(void)(*dbpp)->close(*dbpp, 0);
634	return (ret);
635}
636
637/*
638 * lsn_arg --
639 *	Parse a LSN argument.
640 */
641int
642db_printlog_lsn_arg(arg, lsnp)
643	char *arg;
644	DB_LSN *lsnp;
645{
646	u_long uval;
647	char *p;
648
649	/*
650	 * Expected format is: lsn.file/lsn.offset.
651	 */
652	if ((p = strchr(arg, '/')) == NULL)
653		return (1);
654	*p = '\0';
655
656	if (__db_getulong(NULL, progname, arg, 0, UINT32_MAX, &uval))
657		return (1);
658	lsnp->file = uval;
659	if (__db_getulong(NULL, progname, p + 1, 0, UINT32_MAX, &uval))
660		return (1);
661	lsnp->offset = uval;
662	return (0);
663}
664