xref: /openbsd/regress/lib/libc/db/dbtest.c (revision 07ea8d15)
1 /*	$NetBSD: dbtest.c,v 1.8 1996/05/03 21:57:48 cgd Exp $	*/
2 
3 /*-
4  * Copyright (c) 1992, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1992, 1993, 1994\n\
39 	The Regents of the University of California.  All rights reserved.\n";
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)dbtest.c	8.17 (Berkeley) 9/1/94";
45 #else
46 static char rcsid[] = "$NetBSD: dbtest.c,v 1.8 1996/05/03 21:57:48 cgd Exp $";
47 #endif
48 #endif /* not lint */
49 
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 
53 #include <ctype.h>
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <limits.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61 
62 #include <db.h>
63 
64 enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
65 
66 void	 compare __P((DBT *, DBT *));
67 DBTYPE	 dbtype __P((char *));
68 void	 dump __P((DB *, int));
69 void	 err __P((const char *, ...));
70 void	 get __P((DB *, DBT *));
71 void	 getdata __P((DB *, DBT *, DBT *));
72 void	 put __P((DB *, DBT *, DBT *));
73 void	 rem __P((DB *, DBT *));
74 char	*sflags __P((int));
75 void	 synk __P((DB *));
76 void	*rfile __P((char *, size_t *));
77 void	 seq __P((DB *, DBT *));
78 u_int	 setflags __P((char *));
79 void	*setinfo __P((DBTYPE, char *));
80 void	 usage __P((void));
81 void	*xmalloc __P((char *, size_t));
82 
83 DBTYPE type;				/* Database type. */
84 void *infop;				/* Iflags. */
85 u_long lineno;				/* Current line in test script. */
86 u_int flags;				/* Current DB flags. */
87 int ofd = STDOUT_FILENO;		/* Standard output fd. */
88 
89 DB *XXdbp;				/* Global for gdb. */
90 int XXlineno;				/* Fast breakpoint for gdb. */
91 
92 int
93 main(argc, argv)
94 	int argc;
95 	char *argv[];
96 {
97 	extern int optind;
98 	extern char *optarg;
99 	enum S command, state;
100 	DB *dbp;
101 	DBT data, key, keydata;
102 	size_t len;
103 	int ch, oflags, sflag;
104 	char *fname, *infoarg, *p, *t, buf[8 * 1024];
105 
106 	infoarg = NULL;
107 	fname = NULL;
108 	oflags = O_CREAT | O_RDWR;
109 	sflag = 0;
110 	while ((ch = getopt(argc, argv, "f:i:lo:s")) != EOF)
111 		switch (ch) {
112 		case 'f':
113 			fname = optarg;
114 			break;
115 		case 'i':
116 			infoarg = optarg;
117 			break;
118 		case 'l':
119 			oflags |= DB_LOCK;
120 			break;
121 		case 'o':
122 			if ((ofd = open(optarg,
123 			    O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
124 				err("%s: %s", optarg, strerror(errno));
125 			break;
126 		case 's':
127 			sflag = 1;
128 			break;
129 		case '?':
130 		default:
131 			usage();
132 		}
133 	argc -= optind;
134 	argv += optind;
135 
136 	if (argc != 2)
137 		usage();
138 
139 	/* Set the type. */
140 	type = dbtype(*argv++);
141 
142 	/* Open the descriptor file. */
143         if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
144 	    err("%s: %s", *argv, strerror(errno));
145 
146 	/* Set up the db structure as necessary. */
147 	if (infoarg == NULL)
148 		infop = NULL;
149 	else
150 		for (p = strtok(infoarg, ",\t "); p != NULL;
151 		    p = strtok(0, ",\t "))
152 			if (*p != '\0')
153 				infop = setinfo(type, p);
154 
155 	/*
156 	 * Open the DB.  Delete any preexisting copy, you almost never
157 	 * want it around, and it often screws up tests.
158 	 */
159 	if (fname == NULL) {
160 		p = getenv("TMPDIR");
161 		if (p == NULL)
162 			p = "/var/tmp";
163 		(void)sprintf(buf, "%s/__dbtest", p);
164 		fname = buf;
165 		(void)unlink(buf);
166 	} else  if (!sflag)
167 		(void)unlink(fname);
168 
169 	if ((dbp = dbopen(fname,
170 	    oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
171 		err("dbopen: %s", strerror(errno));
172 	XXdbp = dbp;
173 
174 	state = COMMAND;
175 	for (lineno = 1;
176 	    (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
177 		/* Delete the newline, displaying the key/data is easier. */
178 		if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
179 			*t = '\0';
180 		if ((len = strlen(buf)) == 0 || isspace(*p) || *p == '#')
181 			continue;
182 
183 		/* Convenient gdb break point. */
184 		if (XXlineno == lineno)
185 			XXlineno = 1;
186 		switch (*p) {
187 		case 'c':			/* compare */
188 			if (state != COMMAND)
189 				err("line %lu: not expecting command", lineno);
190 			state = KEY;
191 			command = COMPARE;
192 			break;
193 		case 'e':			/* echo */
194 			if (state != COMMAND)
195 				err("line %lu: not expecting command", lineno);
196 			/* Don't display the newline, if CR at EOL. */
197 			if (p[len - 2] == '\r')
198 				--len;
199 			if (write(ofd, p + 1, len - 1) != len - 1 ||
200 			    write(ofd, "\n", 1) != 1)
201 				err("write: %s", strerror(errno));
202 			break;
203 		case 'g':			/* get */
204 			if (state != COMMAND)
205 				err("line %lu: not expecting command", lineno);
206 			state = KEY;
207 			command = GET;
208 			break;
209 		case 'p':			/* put */
210 			if (state != COMMAND)
211 				err("line %lu: not expecting command", lineno);
212 			state = KEY;
213 			command = PUT;
214 			break;
215 		case 'r':			/* remove */
216 			if (state != COMMAND)
217 				err("line %lu: not expecting command", lineno);
218                         if (flags == R_CURSOR) {
219 				rem(dbp, &key);
220 				state = COMMAND;
221                         } else {
222 				state = KEY;
223 				command = REMOVE;
224 			}
225 			break;
226 		case 'S':			/* sync */
227 			if (state != COMMAND)
228 				err("line %lu: not expecting command", lineno);
229 			synk(dbp);
230 			state = COMMAND;
231 			break;
232 		case 's':			/* seq */
233 			if (state != COMMAND)
234 				err("line %lu: not expecting command", lineno);
235 			if (flags == R_CURSOR) {
236 				state = KEY;
237 				command = SEQ;
238 			} else
239 				seq(dbp, &key);
240 			break;
241 		case 'f':
242 			flags = setflags(p + 1);
243 			break;
244 		case 'D':			/* data file */
245 			if (state != DATA)
246 				err("line %lu: not expecting data", lineno);
247 			data.data = rfile(p + 1, &data.size);
248 			goto ldata;
249 		case 'd':			/* data */
250 			if (state != DATA)
251 				err("line %lu: not expecting data", lineno);
252 			data.data = xmalloc(p + 1, len - 1);
253 			data.size = len - 1;
254 ldata:			switch (command) {
255 			case COMPARE:
256 				compare(&keydata, &data);
257 				break;
258 			case PUT:
259 				put(dbp, &key, &data);
260 				break;
261 			default:
262 				err("line %lu: command doesn't take data",
263 				    lineno);
264 			}
265 			if (type != DB_RECNO)
266 				free(key.data);
267 			free(data.data);
268 			state = COMMAND;
269 			break;
270 		case 'K':			/* key file */
271 			if (state != KEY)
272 				err("line %lu: not expecting a key", lineno);
273 			if (type == DB_RECNO)
274 				err("line %lu: 'K' not available for recno",
275 				    lineno);
276 			key.data = rfile(p + 1, &key.size);
277 			goto lkey;
278 		case 'k':			/* key */
279 			if (state != KEY)
280 				err("line %lu: not expecting a key", lineno);
281 			if (type == DB_RECNO) {
282 				static recno_t recno;
283 				recno = atoi(p + 1);
284 				key.data = &recno;
285 				key.size = sizeof(recno);
286 			} else {
287 				key.data = xmalloc(p + 1, len - 1);
288 				key.size = len - 1;
289 			}
290 lkey:			switch (command) {
291 			case COMPARE:
292 				getdata(dbp, &key, &keydata);
293 				state = DATA;
294 				break;
295 			case GET:
296 				get(dbp, &key);
297 				if (type != DB_RECNO)
298 					free(key.data);
299 				state = COMMAND;
300 				break;
301 			case PUT:
302 				state = DATA;
303 				break;
304 			case REMOVE:
305 				rem(dbp, &key);
306 				if ((type != DB_RECNO) && (flags != R_CURSOR))
307 					free(key.data);
308 				state = COMMAND;
309 				break;
310 			case SEQ:
311 				seq(dbp, &key);
312 				if ((type != DB_RECNO) && (flags != R_CURSOR))
313 					free(key.data);
314 				state = COMMAND;
315 				break;
316 			default:
317 				err("line %lu: command doesn't take a key",
318 				    lineno);
319 			}
320 			break;
321 		case 'o':
322 			dump(dbp, p[1] == 'r');
323 			break;
324 		default:
325 			err("line %lu: %s: unknown command character",
326 			    lineno, p);
327 		}
328 	}
329 #ifdef STATISTICS
330 	/*
331 	 * -l must be used (DB_LOCK must be set) for this to be
332 	 * used, otherwise a page will be locked and it will fail.
333 	 */
334 	if (type == DB_BTREE && oflags & DB_LOCK)
335 		__bt_stat(dbp);
336 #endif
337 	if (dbp->close(dbp))
338 		err("db->close: %s", strerror(errno));
339 	(void)close(ofd);
340 	exit(0);
341 }
342 
343 #define	NOOVERWRITE	"put failed, would overwrite key\n"
344 
345 void
346 compare(db1, db2)
347 	DBT *db1, *db2;
348 {
349 	register size_t len;
350 	register u_char *p1, *p2;
351 
352 	if (db1->size != db2->size)
353 		printf("compare failed: key->data len %lu != data len %lu\n",
354 		    db1->size, db2->size);
355 
356 	len = MIN(db1->size, db2->size);
357 	for (p1 = db1->data, p2 = db2->data; len--;)
358 		if (*p1++ != *p2++) {
359 			printf("compare failed at offset %d\n",
360 			    p1 - (u_char *)db1->data);
361 			break;
362 		}
363 }
364 
365 void
366 get(dbp, kp)
367 	DB *dbp;
368 	DBT *kp;
369 {
370 	DBT data;
371 
372 	switch (dbp->get(dbp, kp, &data, flags)) {
373 	case 0:
374 		(void)write(ofd, data.data, data.size);
375 		if (ofd == STDOUT_FILENO)
376 			(void)write(ofd, "\n", 1);
377 		break;
378 	case -1:
379 		err("line %lu: get: %s", lineno, strerror(errno));
380 		/* NOTREACHED */
381 	case 1:
382 #define	NOSUCHKEY	"get failed, no such key\n"
383 		if (ofd != STDOUT_FILENO)
384 			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
385 		else
386 			(void)fprintf(stderr, "%d: %.*s: %s",
387 			    lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
388 #undef	NOSUCHKEY
389 		break;
390 	}
391 }
392 
393 void
394 getdata(dbp, kp, dp)
395 	DB *dbp;
396 	DBT *kp, *dp;
397 {
398 	switch (dbp->get(dbp, kp, dp, flags)) {
399 	case 0:
400 		return;
401 	case -1:
402 		err("line %lu: getdata: %s", lineno, strerror(errno));
403 		/* NOTREACHED */
404 	case 1:
405 		err("line %lu: getdata failed, no such key", lineno);
406 		/* NOTREACHED */
407 	}
408 }
409 
410 void
411 put(dbp, kp, dp)
412 	DB *dbp;
413 	DBT *kp, *dp;
414 {
415 	switch (dbp->put(dbp, kp, dp, flags)) {
416 	case 0:
417 		break;
418 	case -1:
419 		err("line %lu: put: %s", lineno, strerror(errno));
420 		/* NOTREACHED */
421 	case 1:
422 		(void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
423 		break;
424 	}
425 }
426 
427 void
428 rem(dbp, kp)
429 	DB *dbp;
430 	DBT *kp;
431 {
432 	switch (dbp->del(dbp, kp, flags)) {
433 	case 0:
434 		break;
435 	case -1:
436 		err("line %lu: rem: %s", lineno, strerror(errno));
437 		/* NOTREACHED */
438 	case 1:
439 #define	NOSUCHKEY	"rem failed, no such key\n"
440 		if (ofd != STDOUT_FILENO)
441 			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
442 		else if (flags != R_CURSOR)
443 			(void)fprintf(stderr, "%d: %.*s: %s",
444 			    lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
445 		else
446 			(void)fprintf(stderr,
447 			    "%d: rem of cursor failed\n", lineno);
448 #undef	NOSUCHKEY
449 		break;
450 	}
451 }
452 
453 void
454 synk(dbp)
455 	DB *dbp;
456 {
457 	switch (dbp->sync(dbp, flags)) {
458 	case 0:
459 		break;
460 	case -1:
461 		err("line %lu: synk: %s", lineno, strerror(errno));
462 		/* NOTREACHED */
463 	}
464 }
465 
466 void
467 seq(dbp, kp)
468 	DB *dbp;
469 	DBT *kp;
470 {
471 	DBT data;
472 
473 	switch (dbp->seq(dbp, kp, &data, flags)) {
474 	case 0:
475 		(void)write(ofd, data.data, data.size);
476 		if (ofd == STDOUT_FILENO)
477 			(void)write(ofd, "\n", 1);
478 		break;
479 	case -1:
480 		err("line %lu: seq: %s", lineno, strerror(errno));
481 		/* NOTREACHED */
482 	case 1:
483 #define	NOSUCHKEY	"seq failed, no such key\n"
484 		if (ofd != STDOUT_FILENO)
485 			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
486 		else if (flags == R_CURSOR)
487 			(void)fprintf(stderr, "%d: %.*s: %s",
488 			    lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
489 		else
490 			(void)fprintf(stderr,
491 			    "%d: seq (%s) failed\n", lineno, sflags(flags));
492 #undef	NOSUCHKEY
493 		break;
494 	}
495 }
496 
497 void
498 dump(dbp, rev)
499 	DB *dbp;
500 	int rev;
501 {
502 	DBT key, data;
503 	int flags, nflags;
504 
505 	if (rev) {
506 		flags = R_LAST;
507 		nflags = R_PREV;
508 	} else {
509 		flags = R_FIRST;
510 		nflags = R_NEXT;
511 	}
512 	for (;; flags = nflags)
513 		switch (dbp->seq(dbp, &key, &data, flags)) {
514 		case 0:
515 			(void)write(ofd, data.data, data.size);
516 			if (ofd == STDOUT_FILENO)
517 				(void)write(ofd, "\n", 1);
518 			break;
519 		case 1:
520 			goto done;
521 		case -1:
522 			err("line %lu: (dump) seq: %s",
523 			    lineno, strerror(errno));
524 			/* NOTREACHED */
525 		}
526 done:	return;
527 }
528 
529 u_int
530 setflags(s)
531 	char *s;
532 {
533 	char *p, *index();
534 
535 	for (; isspace(*s); ++s);
536 	if (*s == '\n' || *s == '\0')
537 		return (0);
538 	if ((p = index(s, '\n')) != NULL)
539 		*p = '\0';
540 	if (!strcmp(s, "R_CURSOR"))		return (R_CURSOR);
541 	if (!strcmp(s, "R_FIRST"))		return (R_FIRST);
542 	if (!strcmp(s, "R_IAFTER")) 		return (R_IAFTER);
543 	if (!strcmp(s, "R_IBEFORE")) 		return (R_IBEFORE);
544 	if (!strcmp(s, "R_LAST")) 		return (R_LAST);
545 	if (!strcmp(s, "R_NEXT")) 		return (R_NEXT);
546 	if (!strcmp(s, "R_NOOVERWRITE"))	return (R_NOOVERWRITE);
547 	if (!strcmp(s, "R_PREV"))		return (R_PREV);
548 	if (!strcmp(s, "R_SETCURSOR"))		return (R_SETCURSOR);
549 
550 	err("line %lu: %s: unknown flag", lineno, s);
551 	/* NOTREACHED */
552 }
553 
554 char *
555 sflags(flags)
556 	int flags;
557 {
558 	switch (flags) {
559 	case R_CURSOR:		return ("R_CURSOR");
560 	case R_FIRST:		return ("R_FIRST");
561 	case R_IAFTER:		return ("R_IAFTER");
562 	case R_IBEFORE:		return ("R_IBEFORE");
563 	case R_LAST:		return ("R_LAST");
564 	case R_NEXT:		return ("R_NEXT");
565 	case R_NOOVERWRITE:	return ("R_NOOVERWRITE");
566 	case R_PREV:		return ("R_PREV");
567 	case R_SETCURSOR:	return ("R_SETCURSOR");
568 	}
569 
570 	return ("UNKNOWN!");
571 }
572 
573 DBTYPE
574 dbtype(s)
575 	char *s;
576 {
577 	if (!strcmp(s, "btree"))
578 		return (DB_BTREE);
579 	if (!strcmp(s, "hash"))
580 		return (DB_HASH);
581 	if (!strcmp(s, "recno"))
582 		return (DB_RECNO);
583 	err("%s: unknown type (use btree, hash or recno)", s);
584 	/* NOTREACHED */
585 }
586 
587 void *
588 setinfo(type, s)
589 	DBTYPE type;
590 	char *s;
591 {
592 	static BTREEINFO ib;
593 	static HASHINFO ih;
594 	static RECNOINFO rh;
595 	char *eq, *index();
596 
597 	if ((eq = index(s, '=')) == NULL)
598 		err("%s: illegal structure set statement", s);
599 	*eq++ = '\0';
600 	if (!isdigit(*eq))
601 		err("%s: structure set statement must be a number", s);
602 
603 	switch (type) {
604 	case DB_BTREE:
605 		if (!strcmp("flags", s)) {
606 			ib.flags = atoi(eq);
607 			return (&ib);
608 		}
609 		if (!strcmp("cachesize", s)) {
610 			ib.cachesize = atoi(eq);
611 			return (&ib);
612 		}
613 		if (!strcmp("maxkeypage", s)) {
614 			ib.maxkeypage = atoi(eq);
615 			return (&ib);
616 		}
617 		if (!strcmp("minkeypage", s)) {
618 			ib.minkeypage = atoi(eq);
619 			return (&ib);
620 		}
621 		if (!strcmp("lorder", s)) {
622 			ib.lorder = atoi(eq);
623 			return (&ib);
624 		}
625 		if (!strcmp("psize", s)) {
626 			ib.psize = atoi(eq);
627 			return (&ib);
628 		}
629 		break;
630 	case DB_HASH:
631 		if (!strcmp("bsize", s)) {
632 			ih.bsize = atoi(eq);
633 			return (&ih);
634 		}
635 		if (!strcmp("ffactor", s)) {
636 			ih.ffactor = atoi(eq);
637 			return (&ih);
638 		}
639 		if (!strcmp("nelem", s)) {
640 			ih.nelem = atoi(eq);
641 			return (&ih);
642 		}
643 		if (!strcmp("cachesize", s)) {
644 			ih.cachesize = atoi(eq);
645 			return (&ih);
646 		}
647 		if (!strcmp("lorder", s)) {
648 			ih.lorder = atoi(eq);
649 			return (&ih);
650 		}
651 		break;
652 	case DB_RECNO:
653 		if (!strcmp("flags", s)) {
654 			rh.flags = atoi(eq);
655 			return (&rh);
656 		}
657 		if (!strcmp("cachesize", s)) {
658 			rh.cachesize = atoi(eq);
659 			return (&rh);
660 		}
661 		if (!strcmp("lorder", s)) {
662 			rh.lorder = atoi(eq);
663 			return (&rh);
664 		}
665 		if (!strcmp("reclen", s)) {
666 			rh.reclen = atoi(eq);
667 			return (&rh);
668 		}
669 		if (!strcmp("bval", s)) {
670 			rh.bval = atoi(eq);
671 			return (&rh);
672 		}
673 		if (!strcmp("psize", s)) {
674 			rh.psize = atoi(eq);
675 			return (&rh);
676 		}
677 		break;
678 	}
679 	err("%s: unknown structure value", s);
680 	/* NOTREACHED */
681 }
682 
683 void *
684 rfile(name, lenp)
685 	char *name;
686 	size_t *lenp;
687 {
688 	struct stat sb;
689 	void *p;
690 	int fd;
691 	char *np, *index();
692 
693 	for (; isspace(*name); ++name);
694 	if ((np = index(name, '\n')) != NULL)
695 		*np = '\0';
696 	if ((fd = open(name, O_RDONLY, 0)) < 0 ||
697 	    fstat(fd, &sb))
698 		err("%s: %s\n", name, strerror(errno));
699 #ifdef NOT_PORTABLE
700 	if (sb.st_size > (off_t)SIZE_T_MAX)
701 		err("%s: %s\n", name, strerror(E2BIG));
702 #endif
703 	if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)
704 		err("%s", strerror(errno));
705 	(void)read(fd, p, (int)sb.st_size);
706 	*lenp = sb.st_size;
707 	(void)close(fd);
708 	return (p);
709 }
710 
711 void *
712 xmalloc(text, len)
713 	char *text;
714 	size_t len;
715 {
716 	void *p;
717 
718 	if ((p = (void *)malloc(len)) == NULL)
719 		err("%s", strerror(errno));
720 	memmove(p, text, len);
721 	return (p);
722 }
723 
724 void
725 usage()
726 {
727 	(void)fprintf(stderr,
728 	    "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
729 	exit(1);
730 }
731 
732 #if __STDC__
733 #include <stdarg.h>
734 #else
735 #include <varargs.h>
736 #endif
737 
738 void
739 #if __STDC__
740 err(const char *fmt, ...)
741 #else
742 err(fmt, va_alist)
743 	char *fmt;
744         va_dcl
745 #endif
746 {
747 	va_list ap;
748 #if __STDC__
749 	va_start(ap, fmt);
750 #else
751 	va_start(ap);
752 #endif
753 	(void)fprintf(stderr, "dbtest: ");
754 	(void)vfprintf(stderr, fmt, ap);
755 	va_end(ap);
756 	(void)fprintf(stderr, "\n");
757 	exit(1);
758 	/* NOTREACHED */
759 }
760