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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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 * 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 * 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 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 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