1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: db_dump185.c,v 12.8 2008/02/25 19:06:21 bostic Exp $
7 */
8
9#ifndef lint
10static const char copyright[] =
11    "Copyright (c) 1996,2008 Oracle.  All rights reserved.\n";
12#endif
13
14#include <sys/types.h>
15
16#include <ctype.h>
17#include <errno.h>
18#include <fcntl.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#ifdef HAVE_DB_185_H
24#include <db_185.h>
25#else
26#include <db.h>
27#endif
28
29/* Hash Table Information */
30typedef struct hashhdr185 {		/* Disk resident portion */
31	int		magic;		/* Magic NO for hash tables */
32	int		version;	/* Version ID */
33	u_int32_t	lorder;		/* Byte Order */
34	int		bsize;		/* Bucket/Page Size */
35	int		bshift;		/* Bucket shift */
36	int		dsize;		/* Directory Size */
37	int		ssize;		/* Segment Size */
38	int		sshift;		/* Segment shift */
39	int		ovfl_point;	/* Where overflow pages are being
40					 * allocated */
41	int		last_freed;	/* Last overflow page freed */
42	int		max_bucket;	/* ID of Maximum bucket in use */
43	int		high_mask;	/* Mask to modulo into entire table */
44	int		low_mask;	/* Mask to modulo into lower half of
45					 * table */
46	int		ffactor;	/* Fill factor */
47	int		nkeys;		/* Number of keys in hash table */
48} HASHHDR185;
49typedef struct htab185	 {		/* Memory resident data structure */
50	HASHHDR185	hdr;		/* Header */
51} HTAB185;
52
53/* Hash Table Information */
54typedef struct hashhdr186 {	/* Disk resident portion */
55	int32_t	magic;		/* Magic NO for hash tables */
56	int32_t	version;	/* Version ID */
57	int32_t	lorder;		/* Byte Order */
58	int32_t	bsize;		/* Bucket/Page Size */
59	int32_t	bshift;		/* Bucket shift */
60	int32_t	ovfl_point;	/* Where overflow pages are being allocated */
61	int32_t	last_freed;	/* Last overflow page freed */
62	int32_t	max_bucket;	/* ID of Maximum bucket in use */
63	int32_t	high_mask;	/* Mask to modulo into entire table */
64	int32_t	low_mask;	/* Mask to modulo into lower half of table */
65	int32_t	ffactor;	/* Fill factor */
66	int32_t	nkeys;		/* Number of keys in hash table */
67	int32_t	hdrpages;	/* Size of table header */
68	int32_t	h_charkey;	/* value of hash(CHARKEY) */
69#define	NCACHED	32		/* number of bit maps and spare points */
70	int32_t	spares[NCACHED];/* spare pages for overflow */
71				/* address of overflow page bitmaps */
72	u_int16_t bitmaps[NCACHED];
73} HASHHDR186;
74typedef struct htab186	 {		/* Memory resident data structure */
75	void *unused[2];
76	HASHHDR186	hdr;		/* Header */
77} HTAB186;
78
79typedef struct _epgno {
80	u_int32_t pgno;			/* the page number */
81	u_int16_t index;		/* the index on the page */
82} EPGNO;
83
84typedef struct _epg {
85	void	*page;			/* the (pinned) page */
86	u_int16_t index;		/* the index on the page */
87} EPG;
88
89typedef struct _cursor {
90	EPGNO	 pg;			/* B: Saved tree reference. */
91	DBT	 key;			/* B: Saved key, or key.data == NULL. */
92	u_int32_t rcursor;		/* R: recno cursor (1-based) */
93
94#define	CURS_ACQUIRE	0x01		/*  B: Cursor needs to be reacquired. */
95#define	CURS_AFTER	0x02		/*  B: Unreturned cursor after key. */
96#define	CURS_BEFORE	0x04		/*  B: Unreturned cursor before key. */
97#define	CURS_INIT	0x08		/* RB: Cursor initialized. */
98	u_int8_t flags;
99} CURSOR;
100
101/* The in-memory btree/recno data structure. */
102typedef struct _btree {
103	void	 *bt_mp;		/* memory pool cookie */
104
105	void	 *bt_dbp;		/* pointer to enclosing DB */
106
107	EPG	  bt_cur;		/* current (pinned) page */
108	void	 *bt_pinned;		/* page pinned across calls */
109
110	CURSOR	  bt_cursor;		/* cursor */
111
112	EPGNO	  bt_stack[50];		/* stack of parent pages */
113	EPGNO	 *bt_sp;		/* current stack pointer */
114
115	DBT	  bt_rkey;		/* returned key */
116	DBT	  bt_rdata;		/* returned data */
117
118	int	  bt_fd;		/* tree file descriptor */
119
120	u_int32_t bt_free;		/* next free page */
121	u_int32_t bt_psize;		/* page size */
122	u_int16_t bt_ovflsize;		/* cut-off for key/data overflow */
123	int	  bt_lorder;		/* byte order */
124					/* sorted order */
125	enum { NOT, BACK, FORWARD } bt_order;
126	EPGNO	  bt_last;		/* last insert */
127
128					/* B: key comparison function */
129	int	(*bt_cmp) __P((DBT *, DBT *));
130					/* B: prefix comparison function */
131	size_t	(*bt_pfx) __P((DBT *, DBT *));
132					/* R: recno input function */
133	int	(*bt_irec) __P((struct _btree *, u_int32_t));
134
135	FILE	 *bt_rfp;		/* R: record FILE pointer */
136	int	  bt_rfd;		/* R: record file descriptor */
137
138	void	 *bt_cmap;		/* R: current point in mapped space */
139	void	 *bt_smap;		/* R: start of mapped space */
140	void	 *bt_emap;		/* R: end of mapped space */
141	size_t	  bt_msize;		/* R: size of mapped region. */
142
143	u_int32_t bt_nrecs;		/* R: number of records */
144	size_t	  bt_reclen;		/* R: fixed record length */
145	u_char	  bt_bval;		/* R: delimiting byte/pad character */
146
147/*
148 * NB:
149 * B_NODUPS and R_RECNO are stored on disk, and may not be changed.
150 */
151#define	B_INMEM		0x00001		/* in-memory tree */
152#define	B_METADIRTY	0x00002		/* need to write metadata */
153#define	B_MODIFIED	0x00004		/* tree modified */
154#define	B_NEEDSWAP	0x00008		/* if byte order requires swapping */
155#define	B_RDONLY	0x00010		/* read-only tree */
156
157#define	B_NODUPS	0x00020		/* no duplicate keys permitted */
158#define	R_RECNO		0x00080		/* record oriented tree */
159
160#define	R_CLOSEFP	0x00040		/* opened a file pointer */
161#define	R_EOF		0x00100		/* end of input file reached. */
162#define	R_FIXLEN	0x00200		/* fixed length records */
163#define	R_MEMMAPPED	0x00400		/* memory mapped file. */
164#define	R_INMEM		0x00800		/* in-memory file */
165#define	R_MODIFIED	0x01000		/* modified file */
166#define	R_RDONLY	0x02000		/* read-only file */
167
168#define	B_DB_LOCK	0x04000		/* DB_LOCK specified. */
169#define	B_DB_SHMEM	0x08000		/* DB_SHMEM specified. */
170#define	B_DB_TXN	0x10000		/* DB_TXN specified. */
171	u_int32_t flags;
172} BTREE;
173
174void	db_btree __P((DB *, int));
175void	db_hash __P((DB *, int));
176void	dbt_dump __P((DBT *));
177void	dbt_print __P((DBT *));
178int	main __P((int, char *[]));
179int	usage __P((void));
180
181int
182main(argc, argv)
183	int argc;
184	char *argv[];
185{
186	extern char *optarg;
187	extern int optind;
188	DB *dbp;
189	DBT key, data;
190	int ch, pflag, rval;
191
192	pflag = 0;
193	while ((ch = getopt(argc, argv, "f:p")) != EOF)
194		switch (ch) {
195		case 'f':
196			if (freopen(optarg, "w", stdout) == NULL) {
197				fprintf(stderr, "db_dump185: %s: %s\n",
198				    optarg, strerror(errno));
199				return (EXIT_FAILURE);
200			}
201			break;
202		case 'p':
203			pflag = 1;
204			break;
205		case '?':
206		default:
207			return (usage());
208		}
209	argc -= optind;
210	argv += optind;
211
212	if (argc != 1)
213		return (usage());
214
215	if ((dbp = dbopen(argv[0], O_RDONLY, 0, DB_BTREE, NULL)) == NULL) {
216		if ((dbp =
217		    dbopen(argv[0], O_RDONLY, 0, DB_HASH, NULL)) == NULL) {
218			fprintf(stderr,
219			    "db_dump185: %s: %s\n", argv[0], strerror(errno));
220			return (EXIT_FAILURE);
221		}
222		db_hash(dbp, pflag);
223	} else
224		db_btree(dbp, pflag);
225
226	/*
227	 * !!!
228	 * DB 1.85 DBTs are a subset of DB 2.0 DBTs, so we just use the
229	 * new dump/print routines.
230	 */
231	if (pflag)
232		while (!(rval = dbp->seq(dbp, &key, &data, R_NEXT))) {
233			dbt_print(&key);
234			dbt_print(&data);
235		}
236	else
237		while (!(rval = dbp->seq(dbp, &key, &data, R_NEXT))) {
238			dbt_dump(&key);
239			dbt_dump(&data);
240		}
241
242	if (rval == -1) {
243		fprintf(stderr, "db_dump185: seq: %s\n", strerror(errno));
244		return (EXIT_FAILURE);
245	}
246	return (EXIT_SUCCESS);
247}
248
249/*
250 * db_hash --
251 *	Dump out hash header information.
252 */
253void
254db_hash(dbp, pflag)
255	DB *dbp;
256	int pflag;
257{
258	HTAB185 *hash185p;
259	HTAB186 *hash186p;
260
261	printf("format=%s\n", pflag ? "print" : "bytevalue");
262	printf("type=hash\n");
263
264	/* DB 1.85 was version 2, DB 1.86 was version 3. */
265	hash185p = dbp->internal;
266	if (hash185p->hdr.version > 2) {
267		hash186p = dbp->internal;
268		printf("h_ffactor=%lu\n", (u_long)hash186p->hdr.ffactor);
269		if (hash186p->hdr.lorder != 0)
270			printf("db_lorder=%lu\n", (u_long)hash186p->hdr.lorder);
271		printf("db_pagesize=%lu\n", (u_long)hash186p->hdr.bsize);
272	} else {
273		printf("h_ffactor=%lu\n", (u_long)hash185p->hdr.ffactor);
274		if (hash185p->hdr.lorder != 0)
275			printf("db_lorder=%lu\n", (u_long)hash185p->hdr.lorder);
276		printf("db_pagesize=%lu\n", (u_long)hash185p->hdr.bsize);
277	}
278	printf("HEADER=END\n");
279}
280
281/*
282 * db_btree --
283 *	Dump out btree header information.
284 */
285void
286db_btree(dbp, pflag)
287	DB *dbp;
288	int pflag;
289{
290	BTREE *btp;
291
292	btp = dbp->internal;
293
294	printf("format=%s\n", pflag ? "print" : "bytevalue");
295	printf("type=btree\n");
296#ifdef NOT_AVAILABLE_IN_185
297	printf("bt_minkey=%lu\n", (u_long)XXX);
298	printf("bt_maxkey=%lu\n", (u_long)XXX);
299#endif
300	if (btp->bt_lorder != 0)
301		printf("db_lorder=%lu\n", (u_long)btp->bt_lorder);
302	printf("db_pagesize=%lu\n", (u_long)btp->bt_psize);
303	if (!(btp->flags & B_NODUPS))
304		printf("duplicates=1\n");
305	printf("HEADER=END\n");
306}
307
308static char hex[] = "0123456789abcdef";
309
310/*
311 * dbt_dump --
312 *	Write out a key or data item using byte values.
313 */
314void
315dbt_dump(dbtp)
316	DBT *dbtp;
317{
318	size_t len;
319	u_int8_t *p;
320
321	for (len = dbtp->size, p = dbtp->data; len--; ++p)
322		(void)printf("%c%c",
323		    hex[(*p & 0xf0) >> 4], hex[*p & 0x0f]);
324	printf("\n");
325}
326
327/*
328 * dbt_print --
329 *	Write out a key or data item using printable characters.
330 */
331void
332dbt_print(dbtp)
333	DBT *dbtp;
334{
335	size_t len;
336	u_int8_t *p;
337
338	for (len = dbtp->size, p = dbtp->data; len--; ++p)
339		if (isprint((int)*p)) {
340			if (*p == '\\')
341				(void)printf("\\");
342			(void)printf("%c", *p);
343		} else
344			(void)printf("\\%c%c",
345			    hex[(*p & 0xf0) >> 4], hex[*p & 0x0f]);
346	printf("\n");
347}
348
349/*
350 * usage --
351 *	Display the usage message.
352 */
353int
354usage()
355{
356	(void)fprintf(stderr, "usage: db_dump185 [-p] [-f file] db_file\n");
357	return (EXIT_FAILURE);
358}
359