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.1 (Berkeley) 08/26/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 *)); 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 'g': /* get */ 112 if (state != COMMAND) 113 err("line %lu: not expecting command", lineno); 114 state = KEY; 115 command = GET; 116 break; 117 case 'p': /* put */ 118 if (state != COMMAND) 119 err("line %lu: not expecting command", lineno); 120 state = KEY; 121 command = PUT; 122 break; 123 case 'r': /* remove */ 124 if (state != COMMAND) 125 err("line %lu: not expecting command", lineno); 126 state = KEY; 127 command = REMOVE; 128 break; 129 case 's': /* seq */ 130 if (state != COMMAND) 131 err("line %lu: not expecting command", lineno); 132 seq(dbp); 133 break; 134 case 'f': 135 flags |= setflags(p + 1); 136 break; 137 case 'D': /* data file */ 138 if (state != DATA) 139 err("line %lu: not expecting data", lineno); 140 if (command != PUT) 141 err("line %lu: command doesn't take data", 142 lineno); 143 data.data = rfile(p + 1, &data.size); 144 put(dbp, &key, &data); 145 free(key.data); 146 free(data.data); 147 state = COMMAND; 148 break; 149 case 'd': /* data */ 150 if (state != DATA) 151 err("line %lu: not expecting data", lineno); 152 if (command != PUT) 153 err("line %lu: command doesn't take data", 154 lineno); 155 data.data = xmalloc(p + 1, len - 1); 156 data.size = len - 1; 157 put(dbp, &key, &data); 158 free(key.data); 159 free(data.data); 160 state = COMMAND; 161 break; 162 case 'K': /* key file */ 163 if (state != KEY) 164 err("line %lu: not expecting a key", lineno); 165 if (type == DB_RECNO) 166 err("line %lu: 'K' not available for recno", 167 lineno); 168 key.data = rfile(p + 1, &key.size); 169 switch(command) { 170 case GET: 171 get(dbp, &key); 172 free(key.data); 173 state = COMMAND; 174 break; 175 case PUT: 176 state = DATA; 177 break; 178 case REMOVE: 179 rem(dbp, &key); 180 free(key.data); 181 state = COMMAND; 182 break; 183 default: 184 err("line %lu: command doesn't take a key", 185 lineno); 186 } 187 break; 188 case 'k': /* key */ 189 if (state != KEY) 190 err("line %lu: not expecting a key", lineno); 191 if (type == DB_RECNO) { 192 static recno_t recno; 193 recno = strtol(p + 1, NULL, 0); 194 key.data = &recno; 195 key.size = sizeof(recno); 196 } else { 197 key.data = xmalloc(p + 1, len - 1); 198 key.size = len - 1; 199 } 200 switch(command) { 201 case GET: 202 get(dbp, &key); 203 if (type != DB_RECNO) 204 free(key.data); 205 state = COMMAND; 206 break; 207 case PUT: 208 state = DATA; 209 break; 210 case REMOVE: 211 rem(dbp, &key); 212 if (type != DB_RECNO) 213 free(key.data); 214 state = COMMAND; 215 break; 216 default: 217 err("line %lu: command doesn't take a key", 218 lineno); 219 } 220 break; 221 default: 222 err("line %lu: %s: unknown command character", 223 *p, lineno); 224 } 225 } 226 (void)close(ofd); 227 exit(0); 228 } 229 230 void 231 get(dbp, kp) 232 DB *dbp; 233 DBT *kp; 234 { 235 DBT data; 236 237 if (dbp->get(dbp, kp, &data, flags) == -1) 238 err("line %lu: get: %s", lineno, strerror(errno)); 239 (void)write(ofd, data.data, data.size); 240 } 241 242 void 243 put(dbp, kp, dp) 244 DB *dbp; 245 DBT *kp, *dp; 246 { 247 if (dbp->put(dbp, kp, dp, flags) == -1) 248 err("line %lu: put: %s", lineno, strerror(errno)); 249 } 250 251 void 252 rem(dbp, kp) 253 DB *dbp; 254 DBT *kp; 255 { 256 if (dbp->del(dbp, kp, flags) == -1) 257 err("line %lu: get: %s", lineno, strerror(errno)); 258 } 259 260 void 261 seq(dbp) 262 DB *dbp; 263 { 264 DBT key, data; 265 size_t len; 266 char nbuf[20]; 267 268 if (dbp->seq(dbp, &key, &data, flags) == -1) 269 err("line %lu: seq: %s", lineno, strerror(errno)); 270 if (type == DB_RECNO) { 271 len = sprintf(nbuf, "%lu\n", *(u_long *)key.data); 272 (void)write(ofd, nbuf, len); 273 } else 274 (void)write(ofd, key.data, key.size); 275 (void)write(ofd, data.data, data.size); 276 } 277 278 u_int 279 setflags(s) 280 char *s; 281 { 282 char *p; 283 284 for (; isspace(*s); ++s); 285 if (*s == '\n') 286 return (0); 287 if ((p = index(s, '\n')) != NULL) 288 *p = '\0'; 289 if (!strcmp(s, "R_APPEND")) 290 return (R_APPEND); 291 if (!strcmp(s, "R_CURSOR")) 292 return (R_CURSOR); 293 if (!strcmp(s, "R_IAFTER")) 294 return (R_IAFTER); 295 if (!strcmp(s, "R_IBEFORE")) 296 return (R_IBEFORE); 297 if (!strcmp(s, "R_NOOVERWRITE")) 298 return (R_NOOVERWRITE); 299 if (!strcmp(s, "R_FIRST")) 300 return (R_FIRST); 301 if (!strcmp(s, "R_LAST")) 302 return (R_LAST); 303 if (!strcmp(s, "R_NEXT")) 304 return (R_NEXT); 305 if (!strcmp(s, "R_PREV")) 306 return (R_PREV); 307 err("line %lu: %s: unknown flag", lineno, s); 308 /* NOTREACHED */ 309 } 310 311 DBTYPE 312 dbtype(s) 313 char *s; 314 { 315 if (!strcmp(s, "btree")) 316 return (DB_BTREE); 317 if (!strcmp(s, "hash")) 318 return (DB_HASH); 319 if (!strcmp(s, "recno")) 320 return (DB_RECNO); 321 err("%s: unknown type (use btree, hash or recno)", s); 322 /* NOTREACHED */ 323 } 324 325 void * 326 setinfo(type, s) 327 DBTYPE type; 328 char *s; 329 { 330 static BTREEINFO ib; 331 static HASHINFO ih; 332 static RECNOINFO rh; 333 char *eq; 334 335 if ((eq = index(s, '=')) == NULL) 336 err("%s: illegal structure set statement", s); 337 *eq++ = '\0'; 338 if (!isdigit(*eq)) 339 err("%s: structure set statement must be a number", s); 340 341 switch(type) { 342 case DB_BTREE: 343 if (!strcmp("flags", s)) { 344 ib.flags = strtoul(eq, NULL, 0); 345 return (&ib); 346 } 347 if (!strcmp("cachesize", s)) { 348 ib.cachesize = strtoul(eq, NULL, 0); 349 return (&ib); 350 } 351 if (!strcmp("maxkeypage", s)) { 352 ib.maxkeypage = strtoul(eq, NULL, 0); 353 return (&ib); 354 } 355 if (!strcmp("minkeypage", s)) { 356 ib.minkeypage = strtoul(eq, NULL, 0); 357 return (&ib); 358 } 359 if (!strcmp("lorder", s)) { 360 ib.lorder = strtoul(eq, NULL, 0); 361 return (&ib); 362 } 363 break; 364 case DB_HASH: 365 if (!strcmp("bsize", s)) { 366 ih.bsize = strtoul(eq, NULL, 0); 367 return (&ib); 368 } 369 if (!strcmp("ffactor", s)) { 370 ih.ffactor = strtoul(eq, NULL, 0); 371 return (&ib); 372 } 373 if (!strcmp("nelem", s)) { 374 ih.nelem = strtoul(eq, NULL, 0); 375 return (&ib); 376 } 377 if (!strcmp("cachesize", s)) { 378 ih.cachesize = strtoul(eq, NULL, 0); 379 return (&ib); 380 } 381 if (!strcmp("lorder", s)) { 382 ih.lorder = strtoul(eq, NULL, 0); 383 return (&ib); 384 } 385 break; 386 case DB_RECNO: 387 if (!strcmp("flags", s)) { 388 rh.flags = strtoul(eq, NULL, 0); 389 return (&ib); 390 } 391 if (!strcmp("cachesize", s)) { 392 rh.cachesize = strtoul(eq, NULL, 0); 393 return (&ib); 394 } 395 if (!strcmp("lorder", s)) { 396 rh.lorder = strtoul(eq, NULL, 0); 397 return (&ib); 398 } 399 if (!strcmp("reclen", s)) { 400 rh.reclen = strtoul(eq, NULL, 0); 401 return (&ib); 402 } 403 if (!strcmp("bval", s)) { 404 rh.bval = strtoul(eq, NULL, 0); 405 return (&ib); 406 } 407 break; 408 } 409 err("%s: unknown structure value", s); 410 /* NOTREACHED */ 411 } 412 413 void * 414 rfile(name, lenp) 415 char *name; 416 size_t *lenp; 417 { 418 struct stat sb; 419 void *p; 420 int fd; 421 char *np; 422 423 for (; isspace(*name); ++name); 424 if ((np = index(name, '\n')) != NULL) 425 *np = '\0'; 426 if ((fd = open(name, O_RDONLY, 0)) < 0 || 427 fstat(fd, &sb)) 428 err("%s: %s\n", name, strerror(errno)); 429 if (sb.st_size > SIZE_T_MAX) 430 err("%s: %s\n", name, strerror(E2BIG)); 431 if ((p = malloc((u_int)sb.st_size)) == NULL) 432 err("%s", strerror(errno)); 433 (void)read(fd, p, (int)sb.st_size); 434 *lenp = sb.st_size; 435 return (p); 436 } 437 438 void * 439 xmalloc(text, len) 440 char *text; 441 size_t len; 442 { 443 void *p; 444 445 if ((p = malloc(len)) == NULL) 446 err("%s", strerror(errno)); 447 bcopy(text, p, len); 448 return (p); 449 } 450 451 void 452 usage() 453 { 454 (void)fprintf(stderr, 455 "usage: dbtest [-i info] [-o file] type script\n"); 456 exit(1); 457 } 458 459 #if __STDC__ 460 #include <stdarg.h> 461 #else 462 #include <varargs.h> 463 #endif 464 465 void 466 #if __STDC__ 467 err(const char *fmt, ...) 468 #else 469 err(fmt, va_alist) 470 char *fmt; 471 va_dcl 472 #endif 473 { 474 va_list ap; 475 #if __STDC__ 476 va_start(ap, fmt); 477 #else 478 va_start(ap); 479 #endif 480 (void)fprintf(stderr, "dbtest: "); 481 (void)vfprintf(stderr, fmt, ap); 482 va_end(ap); 483 (void)fprintf(stderr, "\n"); 484 exit(1); 485 /* NOTREACHED */ 486 } 487