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