xref: /csrg-svn/lib/libc/db/test/dbtest.c (revision 64367)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1992, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)dbtest.c	8.3 (Berkeley) 08/27/93";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 
21 #include <ctype.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include <db.h>
31 #include "../PORT/include/compat.h"
32 
33 enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
34 
35 void	 compare __P((DBT *, DBT *));
36 DBTYPE	 dbtype __P((char *));
37 void	 dump __P((DB *, int));
38 void	 err __P((const char *, ...));
39 void	 get __P((DB *, DBT *));
40 void	 getdata __P((DB *, DBT *, DBT *));
41 void	 put __P((DB *, DBT *, DBT *));
42 void	 rem __P((DB *, DBT *));
43 void	*rfile __P((char *, size_t *));
44 void	 seq __P((DB *, DBT *));
45 u_int	 setflags __P((char *));
46 void	*setinfo __P((DBTYPE, char *));
47 void	 usage __P((void));
48 void	*xmalloc __P((char *, size_t));
49 
50 DBTYPE type;
51 void *infop;
52 u_long lineno;
53 u_int flags;
54 int ofd = STDOUT_FILENO;
55 
56 DB *XXdbp;				/* Global for gdb. */
57 
58 int
59 main(argc, argv)
60 	int argc;
61 	char *argv[];
62 {
63 	extern int optind;
64 	extern char *optarg;
65 	enum S command, state;
66 	DB *dbp;
67 	DBT data, key, keydata;
68 	size_t len;
69 	int ch;
70 	char *fname, *infoarg, *p, buf[8 * 1024];
71 
72 	infoarg = NULL;
73 	fname = NULL;
74 	while ((ch = getopt(argc, argv, "f:i:o:")) != EOF)
75 		switch(ch) {
76 		case 'f':
77 			fname = optarg;
78 			break;
79 		case 'i':
80 			infoarg = optarg;
81 			break;
82 		case 'o':
83 			if ((ofd = open(optarg,
84 			    O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
85 				err("%s: %s", optarg, strerror(errno));
86 			break;
87 		case '?':
88 		default:
89 			usage();
90 		}
91 	argc -= optind;
92 	argv += optind;
93 
94 	if (argc != 2)
95 		usage();
96 
97 	/* Set the type. */
98 	type = dbtype(*argv++);
99 
100 	/* Open the descriptor file. */
101 	if (freopen(*argv, "r", stdin) == NULL)
102 		err("%s: %s", *argv, strerror(errno));
103 
104 	/* Set up the db structure as necessary. */
105 	if (infoarg == NULL)
106 		infop = NULL;
107 	else
108 		for (p = strtok(infoarg, ",\t "); p != NULL;
109 		    p = strtok(0, ",\t "))
110 			if (*p != '\0')
111 				infop = setinfo(type, p);
112 
113 	/* Open the DB. */
114 	if (fname == NULL) {
115 		p = getenv("TMPDIR");
116 		if (p == NULL)
117 			p = "/var/tmp";
118 		(void)sprintf(buf, "%s/__dbtest", p);
119 		fname = buf;
120 		(void)unlink(buf);
121 	}
122 	if ((dbp = dbopen(fname,
123 	    O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, type, infop)) == NULL)
124 		err("dbopen: %s", strerror(errno));
125 	XXdbp = dbp;
126 
127 	state = COMMAND;
128 	for (lineno = 1;
129 	    (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
130 		len = strlen(buf);
131 		switch(*p) {
132 		case 'c':			/* compare */
133 			if (state != COMMAND)
134 				err("line %lu: not expecting command", lineno);
135 			state = KEY;
136 			command = COMPARE;
137 			break;
138 		case 'e':			/* echo */
139 			if (state != COMMAND)
140 				err("line %lu: not expecting command", lineno);
141 			/* Don't display the newline, if CR at EOL. */
142 			if (p[len - 2] == '\r')
143 				--len;
144 			if (write(ofd, p + 1, len - 1) != len - 1)
145 				err("write: %s", strerror(errno));
146 			break;
147 		case 'g':			/* get */
148 			if (state != COMMAND)
149 				err("line %lu: not expecting command", lineno);
150 			state = KEY;
151 			command = GET;
152 			break;
153 		case 'p':			/* put */
154 			if (state != COMMAND)
155 				err("line %lu: not expecting command", lineno);
156 			state = KEY;
157 			command = PUT;
158 			break;
159 		case 'r':			/* remove */
160 			if (state != COMMAND)
161 				err("line %lu: not expecting command", lineno);
162 			state = KEY;
163 			command = REMOVE;
164 			break;
165 		case 's':			/* seq */
166 			if (state != COMMAND)
167 				err("line %lu: not expecting command", lineno);
168 			if (flags == R_CURSOR) {
169 				state = KEY;
170 				command = SEQ;
171 			} else
172 				seq(dbp, &key);
173 			break;
174 		case 'f':
175 			flags = setflags(p + 1);
176 			break;
177 		case 'D':			/* data file */
178 			if (state != DATA)
179 				err("line %lu: not expecting data", lineno);
180 			data.data = rfile(p + 1, &data.size);
181 			goto ldata;
182 		case 'd':			/* data */
183 			if (state != DATA)
184 				err("line %lu: not expecting data", lineno);
185 			data.data = xmalloc(p + 1, len - 1);
186 			data.size = len - 1;
187 ldata:			switch(command) {
188 			case COMPARE:
189 				compare(&keydata, &data);
190 				break;
191 			case PUT:
192 				put(dbp, &key, &data);
193 				break;
194 			default:
195 				err("line %lu: command doesn't take data",
196 				    lineno);
197 			}
198 			if (type != DB_RECNO)
199 				free(key.data);
200 			free(data.data);
201 			state = COMMAND;
202 			break;
203 		case 'K':			/* key file */
204 			if (state != KEY)
205 				err("line %lu: not expecting a key", lineno);
206 			if (type == DB_RECNO)
207 				err("line %lu: 'K' not available for recno",
208 				    lineno);
209 			key.data = rfile(p + 1, &key.size);
210 			goto lkey;
211 		case 'k':			/* key */
212 			if (state != KEY)
213 				err("line %lu: not expecting a key", lineno);
214 			if (type == DB_RECNO) {
215 				static recno_t recno;
216 				recno = strtol(p + 1, NULL, 0);
217 				key.data = &recno;
218 				key.size = sizeof(recno);
219 			} else {
220 				key.data = xmalloc(p + 1, len - 1);
221 				key.size = len - 1;
222 			}
223 lkey:			switch(command) {
224 			case COMPARE:
225 				getdata(dbp, &key, &keydata);
226 				state = DATA;
227 				break;
228 			case GET:
229 				get(dbp, &key);
230 				if (type != DB_RECNO)
231 					free(key.data);
232 				state = COMMAND;
233 				break;
234 			case PUT:
235 				state = DATA;
236 				break;
237 			case REMOVE:
238 				rem(dbp, &key);
239 				if (type != DB_RECNO)
240 					free(key.data);
241 				state = COMMAND;
242 				break;
243 			case SEQ:
244 				seq(dbp, &key);
245 				if (type != DB_RECNO)
246 					free(key.data);
247 				state = COMMAND;
248 				break;
249 			default:
250 				err("line %lu: command doesn't take a key",
251 				    lineno);
252 			}
253 			break;
254 		case 'o':
255 			dump(dbp, p[1] == 'r');
256 			break;
257 		default:
258 			err("line %lu: %s: unknown command character",
259 			    p, lineno);
260 		}
261 	}
262 	if (dbp->close(dbp))
263 		err("db->close: %s", strerror(errno));
264 	(void)close(ofd);
265 	exit(0);
266 }
267 
268 #define	NOOVERWRITE	"put failed, would overwrite key\n"
269 #define	NOSUCHKEY	"get failed, no such key\n"
270 
271 void
272 compare(db1, db2)
273 	DBT *db1, *db2;
274 {
275 	register size_t len;
276 	register u_char *p1, *p2;
277 
278 	if (db1->size != db2->size)
279 		printf("compare failed: key->data len %lu != data len %lu\n",
280 		    db1->size, db2->size);
281 
282 	len = MIN(db1->size, db2->size);
283 	for (p1 = db1->data, p2 = db2->data; len--;)
284 		if (*p1++ != *p2++) {
285 			printf("compare failed at offset %d\n",
286 			    p1 - (u_char *)db1->data);
287 			break;
288 		}
289 }
290 
291 void
292 get(dbp, kp)
293 	DB *dbp;
294 	DBT *kp;
295 {
296 	DBT data;
297 
298 	switch(dbp->get(dbp, kp, &data, flags)) {
299 	case 0:
300 		(void)write(ofd, data.data, data.size);
301 		break;
302 	case -1:
303 		err("line %lu: get: %s", lineno, strerror(errno));
304 		/* NOTREACHED */
305 	case 1:
306 		(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
307 		(void)fprintf(stderr, "%d: %.*s: %s\n",
308 		    lineno, kp->size, kp->data, NOSUCHKEY);
309 		break;
310 	}
311 }
312 
313 void
314 getdata(dbp, kp, dp)
315 	DB *dbp;
316 	DBT *kp, *dp;
317 {
318 	switch(dbp->get(dbp, kp, dp, flags)) {
319 	case 0:
320 		return;
321 	case -1:
322 		err("line %lu: getdata: %s", lineno, strerror(errno));
323 		/* NOTREACHED */
324 	case 1:
325 		err("line %lu: get failed, no such key", lineno);
326 		/* NOTREACHED */
327 	}
328 }
329 
330 void
331 put(dbp, kp, dp)
332 	DB *dbp;
333 	DBT *kp, *dp;
334 {
335 	switch(dbp->put(dbp, kp, dp, flags)) {
336 	case 0:
337 		break;
338 	case -1:
339 		err("line %lu: put: %s", lineno, strerror(errno));
340 		/* NOTREACHED */
341 	case 1:
342 		(void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
343 		break;
344 	}
345 }
346 
347 void
348 rem(dbp, kp)
349 	DB *dbp;
350 	DBT *kp;
351 {
352 	switch(dbp->del(dbp, kp, flags)) {
353 	case 0:
354 		break;
355 	case -1:
356 		err("line %lu: get: %s", lineno, strerror(errno));
357 		/* NOTREACHED */
358 	case 1:
359 		(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
360 		break;
361 	}
362 }
363 
364 void
365 seq(dbp, kp)
366 	DB *dbp;
367 	DBT *kp;
368 {
369 	DBT data;
370 
371 	switch(dbp->seq(dbp, kp, &data, flags)) {
372 	case 0:
373 		(void)write(ofd, data.data, data.size);
374 		break;
375 	case -1:
376 		err("line %lu: seq: %s", lineno, strerror(errno));
377 		/* NOTREACHED */
378 	case 1:
379 		(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
380 		break;
381 	}
382 }
383 
384 void
385 dump(dbp, rev)
386 	DB *dbp;
387 	int rev;
388 {
389 	DBT key, data;
390 	int flags, nflags;
391 
392 	if (rev) {
393 		flags = R_LAST;
394 		nflags = R_PREV;
395 	} else {
396 		flags = R_FIRST;
397 		nflags = R_NEXT;
398 	}
399 	for (;; flags = nflags)
400 		switch(dbp->seq(dbp, &key, &data, flags)) {
401 		case 0:
402 			(void)write(ofd, data.data, data.size);
403 			break;
404 		case 1:
405 			goto done;
406 		case -1:
407 			err("line %lu: (dump) seq: %s",
408 			    lineno, strerror(errno));
409 			/* NOTREACHED */
410 		}
411 done:	return;
412 }
413 
414 u_int
415 setflags(s)
416 	char *s;
417 {
418 	char *p;
419 
420 	for (; isspace(*s); ++s);
421 	if (*s == '\n')
422 		return (0);
423 	if ((p = index(s, '\n')) != NULL)
424 		*p = '\0';
425 	if (!strcmp(s, "R_CURSOR"))
426 		return (R_CURSOR);
427 	if (!strcmp(s, "R_FIRST"))
428 		return (R_FIRST);
429 	if (!strcmp(s, "R_IAFTER"))
430 		return (R_IAFTER);
431 	if (!strcmp(s, "R_IBEFORE"))
432 		return (R_IBEFORE);
433 	if (!strcmp(s, "R_LAST"))
434 		return (R_LAST);
435 	if (!strcmp(s, "R_NEXT"))
436 		return (R_NEXT);
437 	if (!strcmp(s, "R_NOOVERWRITE"))
438 		return (R_NOOVERWRITE);
439 	if (!strcmp(s, "R_PREV"))
440 		return (R_PREV);
441 	if (!strcmp(s, "R_SETCURSOR"))
442 		return (R_SETCURSOR);
443 	err("line %lu: %s: unknown flag", lineno, s);
444 	/* NOTREACHED */
445 }
446 
447 DBTYPE
448 dbtype(s)
449 	char *s;
450 {
451 	if (!strcmp(s, "btree"))
452 		return (DB_BTREE);
453 	if (!strcmp(s, "hash"))
454 		return (DB_HASH);
455 	if (!strcmp(s, "recno"))
456 		return (DB_RECNO);
457 	err("%s: unknown type (use btree, hash or recno)", s);
458 	/* NOTREACHED */
459 }
460 
461 void *
462 setinfo(type, s)
463 	DBTYPE type;
464 	char *s;
465 {
466 	static BTREEINFO ib;
467 	static HASHINFO ih;
468 	static RECNOINFO rh;
469 	char *eq;
470 
471 	if ((eq = index(s, '=')) == NULL)
472 		err("%s: illegal structure set statement", s);
473 	*eq++ = '\0';
474 	if (!isdigit(*eq))
475 		err("%s: structure set statement must be a number", s);
476 
477 	switch(type) {
478 	case DB_BTREE:
479 		if (!strcmp("flags", s)) {
480 			ib.flags = atoi(eq);
481 			return (&ib);
482 		}
483 		if (!strcmp("cachesize", s)) {
484 			ib.cachesize = atoi(eq);
485 			return (&ib);
486 		}
487 		if (!strcmp("maxkeypage", s)) {
488 			ib.maxkeypage = atoi(eq);
489 			return (&ib);
490 		}
491 		if (!strcmp("minkeypage", s)) {
492 			ib.minkeypage = atoi(eq);
493 			return (&ib);
494 		}
495 		if (!strcmp("lorder", s)) {
496 			ib.lorder = atoi(eq);
497 			return (&ib);
498 		}
499 		if (!strcmp("psize", s)) {
500 			ib.psize = atoi(eq);
501 			return (&ib);
502 		}
503 		break;
504 	case DB_HASH:
505 		if (!strcmp("bsize", s)) {
506 			ih.bsize = atoi(eq);
507 			return (&ih);
508 		}
509 		if (!strcmp("ffactor", s)) {
510 			ih.ffactor = atoi(eq);
511 			return (&ih);
512 		}
513 		if (!strcmp("nelem", s)) {
514 			ih.nelem = atoi(eq);
515 			return (&ih);
516 		}
517 		if (!strcmp("cachesize", s)) {
518 			ih.cachesize = atoi(eq);
519 			return (&ih);
520 		}
521 		if (!strcmp("lorder", s)) {
522 			ih.lorder = atoi(eq);
523 			return (&ih);
524 		}
525 		break;
526 	case DB_RECNO:
527 		if (!strcmp("flags", s)) {
528 			rh.flags = atoi(eq);
529 			return (&rh);
530 		}
531 		if (!strcmp("cachesize", s)) {
532 			rh.cachesize = atoi(eq);
533 			return (&rh);
534 		}
535 		if (!strcmp("lorder", s)) {
536 			rh.lorder = atoi(eq);
537 			return (&rh);
538 		}
539 		if (!strcmp("reclen", s)) {
540 			rh.reclen = atoi(eq);
541 			return (&rh);
542 		}
543 		if (!strcmp("bval", s)) {
544 			rh.bval = atoi(eq);
545 			return (&rh);
546 		}
547 		if (!strcmp("psize", s)) {
548 			rh.psize = atoi(eq);
549 			return (&rh);
550 		}
551 		break;
552 	}
553 	err("%s: unknown structure value", s);
554 	/* NOTREACHED */
555 }
556 
557 void *
558 rfile(name, lenp)
559 	char *name;
560 	size_t *lenp;
561 {
562 	struct stat sb;
563 	void *p;
564 	int fd;
565 	char *np;
566 
567 	for (; isspace(*name); ++name);
568 	if ((np = index(name, '\n')) != NULL)
569 		*np = '\0';
570 	if ((fd = open(name, O_RDONLY, 0)) < 0 ||
571 	    fstat(fd, &sb))
572 		err("%s: %s\n", name, strerror(errno));
573 #ifdef NOT_PORTABLE
574 	if (sb.st_size > (off_t)SIZE_T_MAX)
575 		err("%s: %s\n", name, strerror(E2BIG));
576 #endif
577 	if ((p = malloc((u_int)sb.st_size)) == NULL)
578 		err("%s", strerror(errno));
579 	(void)read(fd, p, (int)sb.st_size);
580 	*lenp = sb.st_size;
581 	(void)close(fd);
582 	return (p);
583 }
584 
585 void *
586 xmalloc(text, len)
587 	char *text;
588 	size_t len;
589 {
590 	void *p;
591 
592 	if ((p = malloc(len)) == NULL)
593 		err("%s", strerror(errno));
594 	memmove(p, text, len);
595 	return (p);
596 }
597 
598 void
599 usage()
600 {
601 	(void)fprintf(stderr,
602 	    "usage: dbtest [-f file] [-i info] [-o file] type script\n");
603 	exit(1);
604 }
605 
606 #if __STDC__
607 #include <stdarg.h>
608 #else
609 #include <varargs.h>
610 #endif
611 
612 void
613 #if __STDC__
614 err(const char *fmt, ...)
615 #else
616 err(fmt, va_alist)
617 	char *fmt;
618         va_dcl
619 #endif
620 {
621 	va_list ap;
622 #if __STDC__
623 	va_start(ap, fmt);
624 #else
625 	va_start(ap);
626 #endif
627 	(void)fprintf(stderr, "dbtest: ");
628 	(void)vfprintf(stderr, fmt, ap);
629 	va_end(ap);
630 	(void)fprintf(stderr, "\n");
631 	exit(1);
632 	/* NOTREACHED */
633 }
634