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