1 /*- 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1992 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)dbtest.c 5.5 (Berkeley) 11/13/92"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 21 #include <ctype.h> 22 #include <db.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <limits.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA }; 32 33 void compare __P((DBT *, DBT *)); 34 DBTYPE dbtype __P((char *)); 35 void err __P((const char *, ...)); 36 void get __P((DB *, DBT *)); 37 void getdata __P((DB *, DBT *, DBT *)); 38 void put __P((DB *, DBT *, DBT *)); 39 void rem __P((DB *, DBT *)); 40 void *rfile __P((char *, size_t *)); 41 void seq __P((DB *, DBT *)); 42 u_int setflags __P((char *)); 43 void *setinfo __P((DBTYPE, char *)); 44 void usage __P((void)); 45 void *xmalloc __P((char *, size_t)); 46 47 DBTYPE type; 48 void *infop; 49 u_long lineno; 50 u_int flags; 51 int ofd = STDOUT_FILENO; 52 53 int 54 main(argc, argv) 55 int argc; 56 char *argv[]; 57 { 58 enum S command, state; 59 DB *dbp; 60 DBT data, key, keydata; 61 size_t len; 62 int ch; 63 char *infoarg, *p, buf[8 * 1024]; 64 65 infoarg = NULL; 66 while ((ch = getopt(argc, argv, "i:o:")) != EOF) 67 switch(ch) { 68 case 'i': 69 infoarg = optarg; 70 break; 71 case 'o': 72 if ((ofd = open(optarg, 73 O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 74 err("%s: %s", optarg, strerror(errno)); 75 break; 76 case '?': 77 default: 78 usage(); 79 } 80 argc -= optind; 81 argv += optind; 82 83 if (argc != 2) 84 usage(); 85 86 /* Set the type. */ 87 type = dbtype(*argv++); 88 89 /* Open the descriptor file. */ 90 if (freopen(*argv, "r", stdin) == NULL) 91 err("%s: %s", *argv, strerror(errno)); 92 93 /* Set up the db structure as necessary. */ 94 if (infoarg == NULL) 95 infop = NULL; 96 else 97 while ((p = strsep(&infoarg, ",\t ")) != NULL) 98 if (*p != '\0') 99 infop = setinfo(type, p); 100 101 #define BACKINGFILE "/tmp/__dbtest" 102 /* Open the DB. */ 103 (void)unlink(BACKINGFILE); 104 if ((dbp = dbopen(BACKINGFILE, 105 O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, type, infop)) == NULL) 106 err("dbopen: %s", strerror(errno)); 107 108 state = COMMAND; 109 for (lineno = 1; 110 (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) { 111 len = strlen(buf); 112 switch(*p) { 113 case 'c': /* compare */ 114 if (state != COMMAND) 115 err("line %lu: not expecting command", lineno); 116 state = KEY; 117 command = COMPARE; 118 break; 119 case 'e': /* echo */ 120 if (state != COMMAND) 121 err("line %lu: not expecting command", lineno); 122 /* Don't display the newline, if CR at EOL. */ 123 if (p[len - 2] == '\r') 124 --len; 125 if (write(ofd, p + 1, len - 1) != len - 1) 126 err("write: %s", strerror(errno)); 127 break; 128 case 'g': /* get */ 129 if (state != COMMAND) 130 err("line %lu: not expecting command", lineno); 131 state = KEY; 132 command = GET; 133 break; 134 case 'p': /* put */ 135 if (state != COMMAND) 136 err("line %lu: not expecting command", lineno); 137 state = KEY; 138 command = PUT; 139 break; 140 case 'r': /* remove */ 141 if (state != COMMAND) 142 err("line %lu: not expecting command", lineno); 143 state = KEY; 144 command = REMOVE; 145 break; 146 case 's': /* seq */ 147 if (state != COMMAND) 148 err("line %lu: not expecting command", lineno); 149 if (flags == R_CURSOR) { 150 state = KEY; 151 command = SEQ; 152 } else 153 seq(dbp, &key); 154 break; 155 case 'f': 156 flags = setflags(p + 1); 157 break; 158 case 'D': /* data file */ 159 if (state != DATA) 160 err("line %lu: not expecting data", lineno); 161 data.data = rfile(p + 1, &data.size); 162 goto data; 163 case 'd': /* data */ 164 if (state != DATA) 165 err("line %lu: not expecting data", lineno); 166 data.data = xmalloc(p + 1, len - 1); 167 data.size = len - 1; 168 data: switch(command) { 169 case COMPARE: 170 compare(&keydata, &data); 171 break; 172 case PUT: 173 put(dbp, &key, &data); 174 break; 175 default: 176 err("line %lu: command doesn't take data", 177 lineno); 178 } 179 free(key.data); 180 free(data.data); 181 state = COMMAND; 182 break; 183 case 'K': /* key file */ 184 if (state != KEY) 185 err("line %lu: not expecting a key", lineno); 186 if (type == DB_RECNO) 187 err("line %lu: 'K' not available for recno", 188 lineno); 189 key.data = rfile(p + 1, &key.size); 190 goto key; 191 case 'k': /* key */ 192 if (state != KEY) 193 err("line %lu: not expecting a key", lineno); 194 if (type == DB_RECNO) { 195 static recno_t recno; 196 recno = strtol(p + 1, NULL, 0); 197 key.data = &recno; 198 key.size = sizeof(recno); 199 } else { 200 key.data = xmalloc(p + 1, len - 1); 201 key.size = len - 1; 202 } 203 key: switch(command) { 204 case COMPARE: 205 getdata(dbp, &key, &keydata); 206 state = DATA; 207 break; 208 case GET: 209 get(dbp, &key); 210 if (type != DB_RECNO) 211 free(key.data); 212 state = COMMAND; 213 break; 214 case PUT: 215 state = DATA; 216 break; 217 case REMOVE: 218 rem(dbp, &key); 219 if (type != DB_RECNO) 220 free(key.data); 221 state = COMMAND; 222 break; 223 case SEQ: 224 seq(dbp, &key); 225 if (type != DB_RECNO) 226 free(key.data); 227 state = COMMAND; 228 break; 229 default: 230 err("line %lu: command doesn't take a key", 231 lineno); 232 } 233 break; 234 default: 235 err("line %lu: %s: unknown command character", 236 p, lineno); 237 } 238 } 239 (void)close(ofd); 240 exit(0); 241 } 242 243 #define NOOVERWRITE "put failed, would overwrite key\n" 244 #define NOSUCHKEY "get failed, no such key\n" 245 246 void 247 compare(db1, db2) 248 DBT *db1, *db2; 249 { 250 register size_t len; 251 register u_char *p1, *p2; 252 253 if (db1->size != db2->size) 254 printf("compare failed: key->data len %lu != data len %lu\n", 255 db1->size, db2->size); 256 257 len = MIN(db1->size, db2->size); 258 for (p1 = db1->data, p2 = db2->data; len--;) 259 if (*p1++ != *p2++) { 260 printf("compare failed at offset %d\n", 261 p1 - (u_char *)db1->data); 262 break; 263 } 264 } 265 266 void 267 get(dbp, kp) 268 DB *dbp; 269 DBT *kp; 270 { 271 DBT data; 272 273 switch(dbp->get(dbp, kp, &data, flags)) { 274 case 0: 275 (void)write(ofd, data.data, data.size); 276 break; 277 case -1: 278 err("line %lu: get: %s", lineno, strerror(errno)); 279 /* NOTREACHED */ 280 case 1: 281 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 282 break; 283 } 284 } 285 286 void 287 getdata(dbp, kp, dp) 288 DB *dbp; 289 DBT *kp, *dp; 290 { 291 switch(dbp->get(dbp, kp, dp, flags)) { 292 case 0: 293 return; 294 case -1: 295 err("line %lu: getdata: %s", lineno, strerror(errno)); 296 /* NOTREACHED */ 297 case 1: 298 err("line %lu: get failed, no such key", lineno); 299 /* NOTREACHED */ 300 } 301 } 302 303 void 304 put(dbp, kp, dp) 305 DB *dbp; 306 DBT *kp, *dp; 307 { 308 switch(dbp->put(dbp, kp, dp, flags)) { 309 case 0: 310 break; 311 case -1: 312 err("line %lu: put: %s", lineno, strerror(errno)); 313 /* NOTREACHED */ 314 case 1: 315 (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1); 316 break; 317 } 318 } 319 320 void 321 rem(dbp, kp) 322 DB *dbp; 323 DBT *kp; 324 { 325 switch(dbp->del(dbp, kp, flags)) { 326 case 0: 327 break; 328 case -1: 329 err("line %lu: get: %s", lineno, strerror(errno)); 330 /* NOTREACHED */ 331 case 1: 332 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 333 break; 334 } 335 } 336 337 void 338 seq(dbp, kp) 339 DB *dbp; 340 DBT *kp; 341 { 342 DBT data; 343 344 switch(dbp->seq(dbp, kp, &data, flags)) { 345 case 0: 346 (void)write(ofd, data.data, data.size); 347 break; 348 case -1: 349 err("line %lu: seq: %s", lineno, strerror(errno)); 350 /* NOTREACHED */ 351 case 1: 352 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 353 break; 354 } 355 } 356 357 u_int 358 setflags(s) 359 char *s; 360 { 361 char *p; 362 363 for (; isspace(*s); ++s); 364 if (*s == '\n') 365 return (0); 366 if ((p = index(s, '\n')) != NULL) 367 *p = '\0'; 368 if (!strcmp(s, "R_CURSOR")) 369 return (R_CURSOR); 370 if (!strcmp(s, "R_CURSORLOG")) 371 return (R_CURSORLOG); 372 if (!strcmp(s, "R_FIRST")) 373 return (R_FIRST); 374 if (!strcmp(s, "R_IAFTER")) 375 return (R_IAFTER); 376 if (!strcmp(s, "R_IBEFORE")) 377 return (R_IBEFORE); 378 if (!strcmp(s, "R_LAST")) 379 return (R_LAST); 380 if (!strcmp(s, "R_NEXT")) 381 return (R_NEXT); 382 if (!strcmp(s, "R_NOOVERWRITE")) 383 return (R_NOOVERWRITE); 384 if (!strcmp(s, "R_PREV")) 385 return (R_PREV); 386 if (!strcmp(s, "R_SETCURSOR")) 387 return (R_SETCURSOR); 388 err("line %lu: %s: unknown flag", lineno, s); 389 /* NOTREACHED */ 390 } 391 392 DBTYPE 393 dbtype(s) 394 char *s; 395 { 396 if (!strcmp(s, "btree")) 397 return (DB_BTREE); 398 if (!strcmp(s, "hash")) 399 return (DB_HASH); 400 if (!strcmp(s, "recno")) 401 return (DB_RECNO); 402 err("%s: unknown type (use btree, hash or recno)", s); 403 /* NOTREACHED */ 404 } 405 406 void * 407 setinfo(type, s) 408 DBTYPE type; 409 char *s; 410 { 411 static BTREEINFO ib; 412 static HASHINFO ih; 413 static RECNOINFO rh; 414 char *eq; 415 416 if ((eq = index(s, '=')) == NULL) 417 err("%s: illegal structure set statement", s); 418 *eq++ = '\0'; 419 if (!isdigit(*eq)) 420 err("%s: structure set statement must be a number", s); 421 422 switch(type) { 423 case DB_BTREE: 424 if (!strcmp("flags", s)) { 425 ib.flags = strtoul(eq, NULL, 0); 426 return (&ib); 427 } 428 if (!strcmp("cachesize", s)) { 429 ib.cachesize = strtoul(eq, NULL, 0); 430 return (&ib); 431 } 432 if (!strcmp("maxkeypage", s)) { 433 ib.maxkeypage = strtoul(eq, NULL, 0); 434 return (&ib); 435 } 436 if (!strcmp("minkeypage", s)) { 437 ib.minkeypage = strtoul(eq, NULL, 0); 438 return (&ib); 439 } 440 if (!strcmp("lorder", s)) { 441 ib.lorder = strtoul(eq, NULL, 0); 442 return (&ib); 443 } 444 break; 445 case DB_HASH: 446 if (!strcmp("bsize", s)) { 447 ih.bsize = strtoul(eq, NULL, 0); 448 return (&ib); 449 } 450 if (!strcmp("ffactor", s)) { 451 ih.ffactor = strtoul(eq, NULL, 0); 452 return (&ib); 453 } 454 if (!strcmp("nelem", s)) { 455 ih.nelem = strtoul(eq, NULL, 0); 456 return (&ib); 457 } 458 if (!strcmp("cachesize", s)) { 459 ih.cachesize = strtoul(eq, NULL, 0); 460 return (&ib); 461 } 462 if (!strcmp("lorder", s)) { 463 ih.lorder = strtoul(eq, NULL, 0); 464 return (&ib); 465 } 466 break; 467 case DB_RECNO: 468 if (!strcmp("flags", s)) { 469 rh.flags = strtoul(eq, NULL, 0); 470 return (&ib); 471 } 472 if (!strcmp("cachesize", s)) { 473 rh.cachesize = strtoul(eq, NULL, 0); 474 return (&ib); 475 } 476 if (!strcmp("lorder", s)) { 477 rh.lorder = strtoul(eq, NULL, 0); 478 return (&ib); 479 } 480 if (!strcmp("reclen", s)) { 481 rh.reclen = strtoul(eq, NULL, 0); 482 return (&ib); 483 } 484 if (!strcmp("bval", s)) { 485 rh.bval = strtoul(eq, NULL, 0); 486 return (&ib); 487 } 488 break; 489 } 490 err("%s: unknown structure value", s); 491 /* NOTREACHED */ 492 } 493 494 void * 495 rfile(name, lenp) 496 char *name; 497 size_t *lenp; 498 { 499 struct stat sb; 500 void *p; 501 int fd; 502 char *np; 503 504 for (; isspace(*name); ++name); 505 if ((np = index(name, '\n')) != NULL) 506 *np = '\0'; 507 if ((fd = open(name, O_RDONLY, 0)) < 0 || 508 fstat(fd, &sb)) 509 err("%s: %s\n", name, strerror(errno)); 510 if (sb.st_size > SIZE_T_MAX) 511 err("%s: %s\n", name, strerror(E2BIG)); 512 if ((p = malloc((u_int)sb.st_size)) == NULL) 513 err("%s", strerror(errno)); 514 (void)read(fd, p, (int)sb.st_size); 515 *lenp = sb.st_size; 516 (void)close(fd); 517 return (p); 518 } 519 520 void * 521 xmalloc(text, len) 522 char *text; 523 size_t len; 524 { 525 void *p; 526 527 if ((p = malloc(len)) == NULL) 528 err("%s", strerror(errno)); 529 bcopy(text, p, len); 530 return (p); 531 } 532 533 void 534 usage() 535 { 536 (void)fprintf(stderr, 537 "usage: dbtest [-i info] [-o file] type script\n"); 538 exit(1); 539 } 540 541 #if __STDC__ 542 #include <stdarg.h> 543 #else 544 #include <varargs.h> 545 #endif 546 547 void 548 #if __STDC__ 549 err(const char *fmt, ...) 550 #else 551 err(fmt, va_alist) 552 char *fmt; 553 va_dcl 554 #endif 555 { 556 va_list ap; 557 #if __STDC__ 558 va_start(ap, fmt); 559 #else 560 va_start(ap); 561 #endif 562 (void)fprintf(stderr, "dbtest: "); 563 (void)vfprintf(stderr, fmt, ap); 564 va_end(ap); 565 (void)fprintf(stderr, "\n"); 566 exit(1); 567 /* NOTREACHED */ 568 } 569