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