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(argc, argv) 125 int argc; 126 char *argv[]; 127 { 128 extern int optind; 129 extern char *optarg; 130 enum S command = COMMAND, state; 131 DB *dbp; 132 DBT data, key, keydata; 133 size_t len; 134 int ch, oflags, sflag; 135 char *fname, *infoarg, *p, *t, buf[8 * 1024]; 136 137 infoarg = NULL; 138 fname = NULL; 139 oflags = O_CREAT | O_RDWR | O_BINARY; 140 sflag = 0; 141 while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1) 142 switch (ch) { 143 case 'f': 144 fname = optarg; 145 break; 146 case 'i': 147 infoarg = optarg; 148 break; 149 case 'l': 150 oflags |= DB_LOCK; 151 break; 152 case 'o': 153 if ((ofd = open(optarg, 154 O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 155 err("%s: %s", optarg, strerror(errno)); 156 break; 157 case 's': 158 sflag = 1; 159 break; 160 case '?': 161 default: 162 usage(); 163 } 164 argc -= optind; 165 argv += optind; 166 167 if (argc != 2) 168 usage(); 169 170 /* Set the type. */ 171 type = dbtype(*argv++); 172 173 /* Open the descriptor file. */ 174 if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL) 175 err("%s: %s", *argv, strerror(errno)); 176 177 /* Set up the db structure as necessary. */ 178 if (infoarg == NULL) 179 infop = NULL; 180 else 181 for (p = strtok(infoarg, ",\t "); p != NULL; 182 p = strtok(0, ",\t ")) 183 if (*p != '\0') 184 infop = setinfo(type, p); 185 186 /* 187 * Open the DB. Delete any preexisting copy, you almost never 188 * want it around, and it often screws up tests. 189 */ 190 if (fname == NULL) { 191 p = getenv("TMPDIR"); 192 if (p == NULL) 193 p = "/var/tmp"; 194 (void)snprintf(buf, sizeof(buf), "%s/__dbtest", p); 195 fname = buf; 196 (void)unlink(buf); 197 } else if (!sflag) 198 (void)unlink(fname); 199 200 if ((dbp = dbopen(fname, 201 oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL) 202 err("dbopen: %s", strerror(errno)); 203 XXdbp = dbp; 204 205 state = COMMAND; 206 for (lineno = 1; 207 (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) { 208 /* Delete the newline, displaying the key/data is easier. */ 209 if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL) 210 *t = '\0'; 211 if ((len = strlen(buf)) == 0 || isspace((int) *p) || *p == '#') 212 continue; 213 214 /* Convenient gdb break point. */ 215 if (XXlineno == lineno) 216 XXlineno = 1; 217 switch (*p) { 218 case 'c': /* compare */ 219 if (state != COMMAND) 220 err("line %lu: not expecting command", lineno); 221 state = KEY; 222 command = COMPARE; 223 break; 224 case 'e': /* echo */ 225 if (state != COMMAND) 226 err("line %lu: not expecting command", lineno); 227 /* Don't display the newline, if CR at EOL. */ 228 if (p[len - 2] == '\r') 229 --len; 230 if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 || 231 write(ofd, "\n", 1) != 1) 232 err("write: %s", strerror(errno)); 233 break; 234 case 'g': /* get */ 235 if (state != COMMAND) 236 err("line %lu: not expecting command", lineno); 237 state = KEY; 238 command = GET; 239 break; 240 case 'p': /* put */ 241 if (state != COMMAND) 242 err("line %lu: not expecting command", lineno); 243 state = KEY; 244 command = PUT; 245 break; 246 case 'r': /* remove */ 247 if (state != COMMAND) 248 err("line %lu: not expecting command", lineno); 249 if (flags == R_CURSOR) { 250 rem(dbp, &key); 251 state = COMMAND; 252 } else { 253 state = KEY; 254 command = REMOVE; 255 } 256 break; 257 case 'S': /* sync */ 258 if (state != COMMAND) 259 err("line %lu: not expecting command", lineno); 260 synk(dbp); 261 state = COMMAND; 262 break; 263 case 's': /* seq */ 264 if (state != COMMAND) 265 err("line %lu: not expecting command", lineno); 266 if (flags == R_CURSOR) { 267 state = KEY; 268 command = SEQ; 269 } else 270 seq(dbp, &key); 271 break; 272 case 'f': 273 flags = setflags(p + 1); 274 break; 275 case 'D': /* data file */ 276 if (state != DATA) 277 err("line %lu: not expecting data", lineno); 278 data.data = rfile(p + 1, &data.size); 279 goto ldata; 280 case 'd': /* data */ 281 if (state != DATA) 282 err("line %lu: not expecting data", lineno); 283 data.data = xmalloc(p + 1, len - 1); 284 data.size = len - 1; 285 ldata: switch (command) { 286 case COMPARE: 287 compare(&keydata, &data); 288 break; 289 case PUT: 290 put(dbp, &key, &data); 291 break; 292 default: 293 err("line %lu: command doesn't take data", 294 lineno); 295 } 296 if (type != DB_RECNO) 297 free(key.data); 298 free(data.data); 299 state = COMMAND; 300 break; 301 case 'K': /* key file */ 302 if (state != KEY) 303 err("line %lu: not expecting a key", lineno); 304 if (type == DB_RECNO) 305 err("line %lu: 'K' not available for recno", 306 lineno); 307 key.data = rfile(p + 1, &key.size); 308 goto lkey; 309 case 'k': /* key */ 310 if (state != KEY) 311 err("line %lu: not expecting a key", lineno); 312 if (type == DB_RECNO) { 313 static recno_t recno; 314 recno = atoi(p + 1); 315 key.data = &recno; 316 key.size = sizeof(recno); 317 } else { 318 key.data = xmalloc(p + 1, len - 1); 319 key.size = len - 1; 320 } 321 lkey: switch (command) { 322 case COMPARE: 323 getdata(dbp, &key, &keydata); 324 state = DATA; 325 break; 326 case GET: 327 get(dbp, &key); 328 if (type != DB_RECNO) 329 free(key.data); 330 state = COMMAND; 331 break; 332 case PUT: 333 state = DATA; 334 break; 335 case REMOVE: 336 rem(dbp, &key); 337 if ((type != DB_RECNO) && (flags != R_CURSOR)) 338 free(key.data); 339 state = COMMAND; 340 break; 341 case SEQ: 342 seq(dbp, &key); 343 if ((type != DB_RECNO) && (flags != R_CURSOR)) 344 free(key.data); 345 state = COMMAND; 346 break; 347 default: 348 err("line %lu: command doesn't take a key", 349 lineno); 350 } 351 break; 352 case 'o': 353 dump(dbp, p[1] == 'r', 0); 354 break; 355 case 'O': 356 dump(dbp, p[1] == 'r', 1); 357 break; 358 case 'u': 359 unlinkpg(dbp); 360 break; 361 default: 362 err("line %lu: %s: unknown command character", 363 lineno, p); 364 } 365 } 366 #ifdef STATISTICS 367 /* 368 * -l must be used (DB_LOCK must be set) for this to be 369 * used, otherwise a page will be locked and it will fail. 370 */ 371 if (type == DB_BTREE && oflags & DB_LOCK) 372 __bt_stat(dbp); 373 #endif 374 if (dbp->close(dbp)) 375 err("db->close: %s", strerror(errno)); 376 (void)close(ofd); 377 exit(0); 378 } 379 380 #define NOOVERWRITE "put failed, would overwrite key\n" 381 382 void 383 compare(db1, db2) 384 DBT *db1, *db2; 385 { 386 size_t len; 387 u_char *p1, *p2; 388 389 if (db1->size != db2->size) { 390 printf("compare failed: key->data len %lu != data len %lu\n", 391 (u_long) db1->size, (u_long) db2->size); 392 exit (1); 393 } 394 395 len = MIN(db1->size, db2->size); 396 for (p1 = db1->data, p2 = db2->data; len--;) 397 if (*p1++ != *p2++) { 398 err("compare failed at offset %d\n", 399 (int)(p1 - (u_char *)db1->data)); 400 break; 401 } 402 } 403 404 void 405 get(dbp, kp) 406 DB *dbp; 407 DBT *kp; 408 { 409 DBT data; 410 411 switch (dbp->get(dbp, kp, &data, flags)) { 412 case 0: 413 if (write(ofd, data.data, data.size) != (ssize_t)data.size) 414 err("write: %s", strerror(errno)); 415 if (ofd == STDOUT_FILENO) { 416 if (write(ofd, "\n", 1) != 1) 417 err("write: %s", strerror(errno)); 418 } 419 break; 420 case -1: 421 err("line %lu: get: %s", lineno, strerror(errno)); 422 /* NOTREACHED */ 423 case 1: 424 #define NOSUCHKEY "get failed, no such key\n" 425 if (ofd != STDOUT_FILENO) { 426 if (write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1) != 427 sizeof(NOSUCHKEY) - 1) 428 err("write: %s", strerror(errno)); 429 exit(1); 430 } else 431 (void)fprintf(stderr, "%lu: %.*s: %s", 432 lineno, (int) MIN(kp->size, 20), (char *) kp->data, 433 NOSUCHKEY); 434 #undef NOSUCHKEY 435 break; 436 } 437 } 438 439 void 440 getdata(dbp, kp, dp) 441 DB *dbp; 442 DBT *kp, *dp; 443 { 444 switch (dbp->get(dbp, kp, dp, flags)) { 445 case 0: 446 return; 447 case -1: 448 err("line %lu: getdata: %s", lineno, strerror(errno)); 449 /* NOTREACHED */ 450 case 1: 451 err("line %lu: getdata failed, no such key", lineno); 452 /* NOTREACHED */ 453 } 454 } 455 456 void 457 put(dbp, kp, dp) 458 DB *dbp; 459 DBT *kp, *dp; 460 { 461 switch (dbp->put(dbp, kp, dp, flags)) { 462 case 0: 463 break; 464 case -1: 465 err("line %lu: put: %s", lineno, strerror(errno)); 466 /* NOTREACHED */ 467 case 1: 468 if (write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1) != 469 sizeof(NOOVERWRITE) - 1) 470 err("write: %s", strerror(errno)); 471 break; 472 } 473 } 474 475 void 476 rem(dbp, kp) 477 DB *dbp; 478 DBT *kp; 479 { 480 switch (dbp->del(dbp, kp, flags)) { 481 case 0: 482 break; 483 case -1: 484 err("line %lu: rem: %s", lineno, strerror(errno)); 485 /* NOTREACHED */ 486 case 1: 487 #define NOSUCHKEY "rem failed, no such key\n" 488 if (ofd != STDOUT_FILENO) { 489 if (write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1) != 490 sizeof(NOSUCHKEY) - 1) 491 err("write: %s", strerror(errno)); 492 } else if (flags != R_CURSOR) 493 (void)fprintf(stderr, "%lu: %.*s: %s", 494 lineno, (int) MIN(kp->size, 20), (char *) kp->data, 495 NOSUCHKEY); 496 else 497 (void)fprintf(stderr, 498 "%lu: rem of cursor failed\n", lineno); 499 #undef NOSUCHKEY 500 break; 501 } 502 } 503 504 void 505 synk(dbp) 506 DB *dbp; 507 { 508 switch (dbp->sync(dbp, flags)) { 509 case 0: 510 break; 511 case -1: 512 err("line %lu: synk: %s", lineno, strerror(errno)); 513 /* NOTREACHED */ 514 } 515 } 516 517 void 518 seq(dbp, kp) 519 DB *dbp; 520 DBT *kp; 521 { 522 DBT data; 523 524 switch (dbp->seq(dbp, kp, &data, flags)) { 525 case 0: 526 if (write(ofd, data.data, data.size) != (ssize_t)data.size) 527 err("write: %s", strerror(errno)); 528 if (ofd == STDOUT_FILENO) 529 if (write(ofd, "\n", 1) != 1) 530 err("write: %s", strerror(errno)); 531 break; 532 case -1: 533 err("line %lu: seq: %s", lineno, strerror(errno)); 534 /* NOTREACHED */ 535 case 1: 536 #define NOSUCHKEY "seq failed, no such key\n" 537 if (ofd != STDOUT_FILENO) { 538 if (write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1) != 539 sizeof(NOSUCHKEY) - 1) 540 err("write: %s", strerror(errno)); 541 } else if (flags == R_CURSOR) 542 (void)fprintf(stderr, "%lu: %.*s: %s", 543 lineno, (int) MIN(kp->size, 20), (char *) kp->data, 544 NOSUCHKEY); 545 else 546 (void)fprintf(stderr, 547 "%lu: seq (%s) failed\n", lineno, sflags(flags)); 548 #undef NOSUCHKEY 549 break; 550 } 551 } 552 553 void 554 dump(dbp, rev, recurse) 555 DB *dbp; 556 int rev; 557 int recurse; 558 { 559 DBT key, data; 560 int lflags, nflags; 561 562 if (rev) { 563 lflags = R_LAST; 564 nflags = recurse ? R_RPREV : R_PREV; 565 } else { 566 lflags = R_FIRST; 567 nflags = recurse ? R_RNEXT : R_NEXT; 568 } 569 for (;; lflags = nflags) 570 switch (dbp->seq(dbp, &key, &data, lflags)) { 571 case 0: 572 if (write(ofd, data.data, data.size) != 573 (ssize_t)data.size) 574 err("write: %s", strerror(errno)); 575 if (ofd == STDOUT_FILENO) { 576 if (write(ofd, "\n", 1) != 1) 577 err("write: %s", strerror(errno)); 578 } 579 break; 580 case 1: 581 goto done; 582 case -1: 583 err("line %lu: (dump) seq: %s", 584 lineno, strerror(errno)); 585 /* NOTREACHED */ 586 } 587 done: return; 588 } 589 590 void 591 unlinkpg(dbp) 592 DB *dbp; 593 { 594 BTREE *t = dbp->internal; 595 PAGE *h = NULL; 596 db_pgno_t pg; 597 598 for (pg = P_ROOT; pg < t->bt_mp->npages; 599 mpool_put(t->bt_mp, h, 0), pg++) { 600 if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 601 break; 602 /* Look for a nonempty leaf page that has both left 603 * and right siblings. */ 604 if (h->prevpg == P_INVALID || h->nextpg == P_INVALID) 605 continue; 606 if (NEXTINDEX(h) == 0) 607 continue; 608 if ((h->flags & (P_BLEAF | P_RLEAF))) 609 break; 610 } 611 if (h == NULL || pg == t->bt_mp->npages) { 612 fprintf(stderr, "unlinkpg: no appropriate page found\n"); 613 return; 614 } 615 if (__bt_relink(t, h) != 0) { 616 perror("unlinkpg"); 617 goto cleanup; 618 } 619 h->prevpg = P_INVALID; 620 h->nextpg = P_INVALID; 621 cleanup: 622 mpool_put(t->bt_mp, h, MPOOL_DIRTY); 623 } 624 625 u_int 626 setflags(s) 627 char *s; 628 { 629 char *p; 630 631 for (; isspace((int) *s); ++s); 632 if (*s == '\n' || *s == '\0') 633 return (0); 634 if ((p = strchr(s, '\n')) != NULL) 635 *p = '\0'; 636 if (!strcmp(s, "R_CURSOR")) return (R_CURSOR); 637 if (!strcmp(s, "R_FIRST")) return (R_FIRST); 638 if (!strcmp(s, "R_IAFTER")) return (R_IAFTER); 639 if (!strcmp(s, "R_IBEFORE")) return (R_IBEFORE); 640 if (!strcmp(s, "R_LAST")) return (R_LAST); 641 if (!strcmp(s, "R_NEXT")) return (R_NEXT); 642 if (!strcmp(s, "R_NOOVERWRITE")) return (R_NOOVERWRITE); 643 if (!strcmp(s, "R_PREV")) return (R_PREV); 644 if (!strcmp(s, "R_SETCURSOR")) return (R_SETCURSOR); 645 646 err("line %lu: %s: unknown flag", lineno, s); 647 /* NOTREACHED */ 648 } 649 650 char * 651 sflags(lflags) 652 int lflags; 653 { 654 switch (lflags) { 655 case R_CURSOR: return ("R_CURSOR"); 656 case R_FIRST: return ("R_FIRST"); 657 case R_IAFTER: return ("R_IAFTER"); 658 case R_IBEFORE: return ("R_IBEFORE"); 659 case R_LAST: return ("R_LAST"); 660 case R_NEXT: return ("R_NEXT"); 661 case R_NOOVERWRITE: return ("R_NOOVERWRITE"); 662 case R_PREV: return ("R_PREV"); 663 case R_SETCURSOR: return ("R_SETCURSOR"); 664 } 665 666 return ("UNKNOWN!"); 667 } 668 669 DBTYPE 670 dbtype(s) 671 char *s; 672 { 673 if (!strcmp(s, "btree")) 674 return (DB_BTREE); 675 if (!strcmp(s, "hash")) 676 return (DB_HASH); 677 if (!strcmp(s, "recno")) 678 return (DB_RECNO); 679 err("%s: unknown type (use btree, hash or recno)", s); 680 /* NOTREACHED */ 681 } 682 683 void * 684 setinfo(db_type, s) 685 DBTYPE db_type; 686 char *s; 687 { 688 static BTREEINFO ib; 689 static HASHINFO ih; 690 static RECNOINFO rh; 691 char *eq; 692 693 if ((eq = strchr(s, '=')) == NULL) 694 err("%s: illegal structure set statement", s); 695 *eq++ = '\0'; 696 if (!isdigit((int) *eq)) 697 err("%s: structure set statement must be a number", s); 698 699 switch (db_type) { 700 case DB_BTREE: 701 if (!strcmp("flags", s)) { 702 ib.flags = atoi(eq); 703 return (&ib); 704 } 705 if (!strcmp("cachesize", s)) { 706 ib.cachesize = atoi(eq); 707 return (&ib); 708 } 709 if (!strcmp("maxkeypage", s)) { 710 ib.maxkeypage = atoi(eq); 711 return (&ib); 712 } 713 if (!strcmp("minkeypage", s)) { 714 ib.minkeypage = atoi(eq); 715 return (&ib); 716 } 717 if (!strcmp("lorder", s)) { 718 ib.lorder = atoi(eq); 719 return (&ib); 720 } 721 if (!strcmp("psize", s)) { 722 ib.psize = atoi(eq); 723 return (&ib); 724 } 725 break; 726 case DB_HASH: 727 if (!strcmp("bsize", s)) { 728 ih.bsize = atoi(eq); 729 return (&ih); 730 } 731 if (!strcmp("ffactor", s)) { 732 ih.ffactor = atoi(eq); 733 return (&ih); 734 } 735 if (!strcmp("nelem", s)) { 736 ih.nelem = atoi(eq); 737 return (&ih); 738 } 739 if (!strcmp("cachesize", s)) { 740 ih.cachesize = atoi(eq); 741 return (&ih); 742 } 743 if (!strcmp("lorder", s)) { 744 ih.lorder = atoi(eq); 745 return (&ih); 746 } 747 break; 748 case DB_RECNO: 749 if (!strcmp("flags", s)) { 750 rh.flags = atoi(eq); 751 return (&rh); 752 } 753 if (!strcmp("cachesize", s)) { 754 rh.cachesize = atoi(eq); 755 return (&rh); 756 } 757 if (!strcmp("lorder", s)) { 758 rh.lorder = atoi(eq); 759 return (&rh); 760 } 761 if (!strcmp("reclen", s)) { 762 rh.reclen = atoi(eq); 763 return (&rh); 764 } 765 if (!strcmp("bval", s)) { 766 rh.bval = atoi(eq); 767 return (&rh); 768 } 769 if (!strcmp("psize", s)) { 770 rh.psize = atoi(eq); 771 return (&rh); 772 } 773 break; 774 } 775 err("%s: unknown structure value", s); 776 /* NOTREACHED */ 777 } 778 779 void * 780 rfile(name, lenp) 781 char *name; 782 size_t *lenp; 783 { 784 struct stat sb; 785 void *p; 786 int fd; 787 char *np; 788 789 for (; isspace((int) *name); ++name); 790 if ((np = strchr(name, '\n')) != NULL) 791 *np = '\0'; 792 if ((fd = open(name, O_RDONLY, 0)) < 0 || 793 fstat(fd, &sb)) 794 err("%s: %s\n", name, strerror(errno)); 795 #ifdef NOT_PORTABLE 796 if (sb.st_size > (off_t)SIZE_T_MAX) 797 err("%s: %s\n", name, strerror(E2BIG)); 798 #endif 799 if ((p = (void *)malloc((u_int)sb.st_size)) == NULL) 800 err("%s", strerror(errno)); 801 if (read(fd, p, (int)sb.st_size) == -1) 802 err("%s", strerror(errno)); 803 *lenp = sb.st_size; 804 (void)close(fd); 805 return (p); 806 } 807 808 void * 809 xmalloc(text, len) 810 char *text; 811 size_t len; 812 { 813 void *p; 814 815 if ((p = (void *)malloc(len)) == NULL) 816 err("%s", strerror(errno)); 817 memmove(p, text, len); 818 return (p); 819 } 820 821 void 822 usage() 823 { 824 (void)fprintf(stderr, 825 "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n"); 826 exit(1); 827 } 828 829 #include <stdarg.h> 830 831 void 832 err(const char *fmt, ...) 833 { 834 va_list ap; 835 va_start(ap, fmt); 836 (void)fprintf(stderr, "dbtest: "); 837 (void)vfprintf(stderr, fmt, ap); 838 va_end(ap); 839 (void)fprintf(stderr, "\n"); 840 exit(1); 841 /* NOTREACHED */ 842 } 843