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