1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 2013 Oracle and/or its affiliates.  All rights reserved.
5  *
6  * $Id$
7  */
8 
9 #ifndef lint
10 static const char copyright[] =
11     "Copyright (c) 1996, 2013 Oracle and/or its affiliates.  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 */
30 typedef 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;
49 typedef struct htab185	 {		/* Memory resident data structure */
50 	HASHHDR185	hdr;		/* Header */
51 } HTAB185;
52 
53 /* Hash Table Information */
54 typedef 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;
74 typedef struct htab186	 {		/* Memory resident data structure */
75 	void *unused[2];
76 	HASHHDR186	hdr;		/* Header */
77 } HTAB186;
78 
79 typedef struct _epgno {
80 	u_int32_t pgno;			/* the page number */
81 	u_int16_t index;		/* the index on the page */
82 } EPGNO;
83 
84 typedef struct _epg {
85 	void	*page;			/* the (pinned) page */
86 	u_int16_t index;		/* the index on the page */
87 } EPG;
88 
89 typedef 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. */
102 typedef 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 
174 void	db_btree __P((DB *, int));
175 void	db_hash __P((DB *, int));
176 void	dbt_dump __P((DBT *));
177 void	dbt_print __P((DBT *));
178 int	main __P((int, char *[]));
179 int	usage __P((void));
180 
181 int
main(argc,argv)182 main(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  */
253 void
db_hash(dbp,pflag)254 db_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  */
285 void
db_btree(dbp,pflag)286 db_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 
308 static char hex[] = "0123456789abcdef";
309 
310 /*
311  * dbt_dump --
312  *	Write out a key or data item using byte values.
313  */
314 void
dbt_dump(dbtp)315 dbt_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  */
331 void
dbt_print(dbtp)332 dbt_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  */
353 int
usage()354 usage()
355 {
356 	(void)fprintf(stderr, "usage: db_dump185 [-p] [-f file] db_file\n");
357 	return (EXIT_FAILURE);
358 }
359