156039Sbostic /*- 256039Sbostic * Copyright (c) 1992 The Regents of the University of California. 356039Sbostic * All rights reserved. 456039Sbostic * 556039Sbostic * %sccs.include.redist.c% 656039Sbostic */ 756039Sbostic 856039Sbostic #ifndef lint 956039Sbostic char copyright[] = 1056039Sbostic "@(#) Copyright (c) 1992 The Regents of the University of California.\n\ 1156039Sbostic All rights reserved.\n"; 1256039Sbostic #endif /* not lint */ 1356039Sbostic 1456039Sbostic #ifndef lint 15*56489Sbostic static char sccsid[] = "@(#)dbtest.c 5.3 (Berkeley) 10/09/92"; 1656039Sbostic #endif /* not lint */ 1756039Sbostic 1856039Sbostic #include <sys/param.h> 1956039Sbostic #include <sys/stat.h> 2056039Sbostic 2156039Sbostic #include <ctype.h> 2256039Sbostic #include <db.h> 2356039Sbostic #include <errno.h> 2456039Sbostic #include <fcntl.h> 2556039Sbostic #include <limits.h> 2656039Sbostic #include <stdio.h> 2756039Sbostic #include <stdlib.h> 2856039Sbostic #include <string.h> 2956039Sbostic #include <unistd.h> 3056039Sbostic 3156039Sbostic enum S { COMMAND, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA }; 3256039Sbostic 3356039Sbostic DBTYPE dbtype __P((char *)); 3456039Sbostic void err __P((const char *, ...)); 3556039Sbostic void get __P((DB *, DBT *)); 3656039Sbostic void put __P((DB *, DBT *, DBT *)); 3756039Sbostic void rem __P((DB *, DBT *)); 3856039Sbostic void *rfile __P((char *, size_t *)); 3956059Sbostic void seq __P((DB *, DBT *)); 4056039Sbostic u_int setflags __P((char *)); 4156039Sbostic void *setinfo __P((DBTYPE, char *)); 4256039Sbostic void usage __P((void)); 4356039Sbostic void *xmalloc __P((char *, size_t)); 4456039Sbostic 4556039Sbostic DBTYPE type; 4656039Sbostic void *infop; 4756039Sbostic u_long lineno; 4856039Sbostic u_int flags; 4956039Sbostic int ofd = STDOUT_FILENO; 5056039Sbostic 5156039Sbostic int 5256039Sbostic main(argc, argv) 5356039Sbostic int argc; 5456039Sbostic char *argv[]; 5556039Sbostic { 5656039Sbostic enum S command, state; 5756039Sbostic DB *dbp; 5856039Sbostic DBT data, key; 5956039Sbostic size_t len; 6056039Sbostic int ch; 6156039Sbostic char *infoarg, *p, buf[8 * 1024]; 6256039Sbostic 6356039Sbostic infoarg = NULL; 6456039Sbostic while ((ch = getopt(argc, argv, "i:o:")) != EOF) 6556039Sbostic switch(ch) { 6656039Sbostic case 'i': 6756039Sbostic infoarg = optarg; 6856039Sbostic break; 6956039Sbostic case 'o': 7056039Sbostic if ((ofd = open(optarg, 7156039Sbostic O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 7256039Sbostic err("%s: %s", optarg, strerror(errno)); 7356039Sbostic break; 7456039Sbostic case '?': 7556039Sbostic default: 7656039Sbostic usage(); 7756039Sbostic } 7856039Sbostic argc -= optind; 7956039Sbostic argv += optind; 8056039Sbostic 8156039Sbostic if (argc != 2) 8256039Sbostic usage(); 8356039Sbostic 8456039Sbostic /* Set the type. */ 8556039Sbostic type = dbtype(*argv++); 8656039Sbostic 8756039Sbostic /* Open the descriptor file. */ 8856039Sbostic if (freopen(*argv, "r", stdin) == NULL) 8956039Sbostic err("%s: %s", *argv, strerror(errno)); 9056039Sbostic 9156039Sbostic /* Set up the db structure as necessary. */ 9256039Sbostic if (infoarg == NULL) 9356039Sbostic infop = NULL; 9456039Sbostic else 9556039Sbostic while ((p = strsep(&infoarg, ",\t ")) != NULL) 9656039Sbostic if (*p != '\0') 9756039Sbostic infop = setinfo(type, p); 9856039Sbostic 9956039Sbostic #define BACKINGFILE "/tmp/__dbtest" 10056039Sbostic /* Open the DB. */ 10156039Sbostic (void)unlink(BACKINGFILE); 10256039Sbostic if ((dbp = dbopen(BACKINGFILE, 10356039Sbostic O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, type, infop)) == NULL) 10456039Sbostic err("dbopen: %s", strerror(errno)); 10556039Sbostic 10656039Sbostic state = COMMAND; 10756039Sbostic for (lineno = 1; 10856039Sbostic (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) { 10956039Sbostic len = strlen(buf); 11056039Sbostic switch(*p) { 11156059Sbostic case 'e': /* echo */ 11256059Sbostic if (state != COMMAND) 11356059Sbostic err("line %lu: not expecting command", lineno); 11456059Sbostic (void)write(ofd, p + 1, len - 1); 11556059Sbostic break; 11656039Sbostic case 'g': /* get */ 11756039Sbostic if (state != COMMAND) 11856039Sbostic err("line %lu: not expecting command", lineno); 11956039Sbostic state = KEY; 12056039Sbostic command = GET; 12156039Sbostic break; 12256039Sbostic case 'p': /* put */ 12356039Sbostic if (state != COMMAND) 12456039Sbostic err("line %lu: not expecting command", lineno); 12556039Sbostic state = KEY; 12656039Sbostic command = PUT; 12756039Sbostic break; 12856039Sbostic case 'r': /* remove */ 12956039Sbostic if (state != COMMAND) 13056039Sbostic err("line %lu: not expecting command", lineno); 13156039Sbostic state = KEY; 13256039Sbostic command = REMOVE; 13356039Sbostic break; 13456039Sbostic case 's': /* seq */ 13556039Sbostic if (state != COMMAND) 13656039Sbostic err("line %lu: not expecting command", lineno); 13756059Sbostic if (flags == R_CURSOR) { 13856059Sbostic state = KEY; 13956059Sbostic command = SEQ; 14056059Sbostic } else 14156059Sbostic seq(dbp, &key); 14256039Sbostic break; 14356039Sbostic case 'f': 14456059Sbostic flags = setflags(p + 1); 14556039Sbostic break; 14656039Sbostic case 'D': /* data file */ 14756039Sbostic if (state != DATA) 14856039Sbostic err("line %lu: not expecting data", lineno); 14956039Sbostic if (command != PUT) 15056039Sbostic err("line %lu: command doesn't take data", 15156039Sbostic lineno); 15256039Sbostic data.data = rfile(p + 1, &data.size); 15356039Sbostic put(dbp, &key, &data); 15456039Sbostic free(key.data); 15556039Sbostic free(data.data); 15656039Sbostic state = COMMAND; 15756039Sbostic break; 15856039Sbostic case 'd': /* data */ 15956039Sbostic if (state != DATA) 16056039Sbostic err("line %lu: not expecting data", lineno); 16156039Sbostic if (command != PUT) 16256039Sbostic err("line %lu: command doesn't take data", 16356039Sbostic lineno); 16456039Sbostic data.data = xmalloc(p + 1, len - 1); 16556039Sbostic data.size = len - 1; 16656039Sbostic put(dbp, &key, &data); 16756039Sbostic free(key.data); 16856039Sbostic free(data.data); 16956039Sbostic state = COMMAND; 17056039Sbostic break; 17156039Sbostic case 'K': /* key file */ 17256039Sbostic if (state != KEY) 17356039Sbostic err("line %lu: not expecting a key", lineno); 17456039Sbostic if (type == DB_RECNO) 17556039Sbostic err("line %lu: 'K' not available for recno", 17656039Sbostic lineno); 17756039Sbostic key.data = rfile(p + 1, &key.size); 17856059Sbostic goto key; 17956039Sbostic case 'k': /* key */ 18056039Sbostic if (state != KEY) 18156039Sbostic err("line %lu: not expecting a key", lineno); 18256039Sbostic if (type == DB_RECNO) { 18356039Sbostic static recno_t recno; 18456039Sbostic recno = strtol(p + 1, NULL, 0); 18556039Sbostic key.data = &recno; 18656039Sbostic key.size = sizeof(recno); 18756039Sbostic } else { 18856039Sbostic key.data = xmalloc(p + 1, len - 1); 18956039Sbostic key.size = len - 1; 19056039Sbostic } 19156059Sbostic key: switch(command) { 19256039Sbostic case GET: 19356039Sbostic get(dbp, &key); 19456039Sbostic if (type != DB_RECNO) 19556039Sbostic free(key.data); 19656039Sbostic state = COMMAND; 19756039Sbostic break; 19856039Sbostic case PUT: 19956039Sbostic state = DATA; 20056039Sbostic break; 20156039Sbostic case REMOVE: 20256039Sbostic rem(dbp, &key); 20356039Sbostic if (type != DB_RECNO) 20456039Sbostic free(key.data); 20556039Sbostic state = COMMAND; 20656039Sbostic break; 20756059Sbostic case SEQ: 20856059Sbostic seq(dbp, &key); 20956059Sbostic if (type != DB_RECNO) 21056059Sbostic free(key.data); 21156059Sbostic state = COMMAND; 21256059Sbostic break; 21356039Sbostic default: 21456039Sbostic err("line %lu: command doesn't take a key", 21556039Sbostic lineno); 21656039Sbostic } 21756039Sbostic break; 21856039Sbostic default: 21956039Sbostic err("line %lu: %s: unknown command character", 22056059Sbostic p, lineno); 22156039Sbostic } 22256039Sbostic } 22356039Sbostic (void)close(ofd); 22456039Sbostic exit(0); 22556039Sbostic } 22656039Sbostic 22756059Sbostic #define NOOVERWRITE "put failed, would overwrite key\n" 22856059Sbostic #define NOSUCHKEY "get failed, no such key\n" 22956059Sbostic 23056039Sbostic void 23156039Sbostic get(dbp, kp) 23256039Sbostic DB *dbp; 23356039Sbostic DBT *kp; 23456039Sbostic { 23556039Sbostic DBT data; 23656039Sbostic 23756059Sbostic switch(dbp->get(dbp, kp, &data, flags)) { 23856059Sbostic case 0: 23956059Sbostic (void)write(ofd, data.data, data.size); 24056059Sbostic break; 24156059Sbostic case -1: 24256039Sbostic err("line %lu: get: %s", lineno, strerror(errno)); 24356059Sbostic /* NOTREACHED */ 24456059Sbostic case 1: 24556059Sbostic (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 24656059Sbostic break; 24756059Sbostic } 24856039Sbostic } 24956039Sbostic 25056039Sbostic void 25156039Sbostic put(dbp, kp, dp) 25256039Sbostic DB *dbp; 25356039Sbostic DBT *kp, *dp; 25456039Sbostic { 25556059Sbostic switch(dbp->put(dbp, kp, dp, flags)) { 25656059Sbostic case 0: 25756059Sbostic break; 25856059Sbostic case -1: 25956039Sbostic err("line %lu: put: %s", lineno, strerror(errno)); 26056059Sbostic /* NOTREACHED */ 26156059Sbostic case 1: 26256059Sbostic (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1); 26356059Sbostic break; 26456059Sbostic } 26556039Sbostic } 26656039Sbostic 26756039Sbostic void 26856039Sbostic rem(dbp, kp) 26956039Sbostic DB *dbp; 27056039Sbostic DBT *kp; 27156039Sbostic { 27256059Sbostic switch(dbp->del(dbp, kp, flags)) { 27356059Sbostic case 0: 27456059Sbostic break; 27556059Sbostic case -1: 27656039Sbostic err("line %lu: get: %s", lineno, strerror(errno)); 27756059Sbostic /* NOTREACHED */ 27856059Sbostic case 1: 27956059Sbostic (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 28056059Sbostic break; 28156059Sbostic } 28256039Sbostic } 28356039Sbostic 28456039Sbostic void 28556059Sbostic seq(dbp, kp) 28656039Sbostic DB *dbp; 28756059Sbostic DBT *kp; 28856039Sbostic { 28956059Sbostic DBT data; 29056039Sbostic 29156059Sbostic switch(dbp->seq(dbp, kp, &data, flags)) { 29256059Sbostic case 0: 29356059Sbostic (void)write(ofd, data.data, data.size); 29456059Sbostic break; 29556059Sbostic case -1: 29656039Sbostic err("line %lu: seq: %s", lineno, strerror(errno)); 29756059Sbostic /* NOTREACHED */ 29856059Sbostic case 1: 29956059Sbostic (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 30056059Sbostic break; 30156059Sbostic } 30256039Sbostic } 30356039Sbostic 30456039Sbostic u_int 30556039Sbostic setflags(s) 30656039Sbostic char *s; 30756039Sbostic { 30856039Sbostic char *p; 30956039Sbostic 31056039Sbostic for (; isspace(*s); ++s); 31156039Sbostic if (*s == '\n') 31256039Sbostic return (0); 31356039Sbostic if ((p = index(s, '\n')) != NULL) 31456039Sbostic *p = '\0'; 31556039Sbostic if (!strcmp(s, "R_APPEND")) 31656039Sbostic return (R_APPEND); 31756039Sbostic if (!strcmp(s, "R_CURSOR")) 31856039Sbostic return (R_CURSOR); 31956039Sbostic if (!strcmp(s, "R_IAFTER")) 32056039Sbostic return (R_IAFTER); 32156039Sbostic if (!strcmp(s, "R_IBEFORE")) 32256039Sbostic return (R_IBEFORE); 32356039Sbostic if (!strcmp(s, "R_NOOVERWRITE")) 32456039Sbostic return (R_NOOVERWRITE); 32556039Sbostic if (!strcmp(s, "R_FIRST")) 32656039Sbostic return (R_FIRST); 32756039Sbostic if (!strcmp(s, "R_LAST")) 32856039Sbostic return (R_LAST); 32956039Sbostic if (!strcmp(s, "R_NEXT")) 33056039Sbostic return (R_NEXT); 33156039Sbostic if (!strcmp(s, "R_PREV")) 33256039Sbostic return (R_PREV); 33356039Sbostic err("line %lu: %s: unknown flag", lineno, s); 33456039Sbostic /* NOTREACHED */ 33556039Sbostic } 33656039Sbostic 33756039Sbostic DBTYPE 33856039Sbostic dbtype(s) 33956039Sbostic char *s; 34056039Sbostic { 34156039Sbostic if (!strcmp(s, "btree")) 34256039Sbostic return (DB_BTREE); 34356039Sbostic if (!strcmp(s, "hash")) 34456039Sbostic return (DB_HASH); 34556039Sbostic if (!strcmp(s, "recno")) 34656039Sbostic return (DB_RECNO); 34756039Sbostic err("%s: unknown type (use btree, hash or recno)", s); 34856039Sbostic /* NOTREACHED */ 34956039Sbostic } 35056039Sbostic 35156039Sbostic void * 35256039Sbostic setinfo(type, s) 35356039Sbostic DBTYPE type; 35456039Sbostic char *s; 35556039Sbostic { 35656039Sbostic static BTREEINFO ib; 35756039Sbostic static HASHINFO ih; 35856039Sbostic static RECNOINFO rh; 35956039Sbostic char *eq; 36056039Sbostic 36156039Sbostic if ((eq = index(s, '=')) == NULL) 36256039Sbostic err("%s: illegal structure set statement", s); 36356039Sbostic *eq++ = '\0'; 36456039Sbostic if (!isdigit(*eq)) 36556039Sbostic err("%s: structure set statement must be a number", s); 36656039Sbostic 36756039Sbostic switch(type) { 36856039Sbostic case DB_BTREE: 36956039Sbostic if (!strcmp("flags", s)) { 37056039Sbostic ib.flags = strtoul(eq, NULL, 0); 37156039Sbostic return (&ib); 37256039Sbostic } 37356039Sbostic if (!strcmp("cachesize", s)) { 37456039Sbostic ib.cachesize = strtoul(eq, NULL, 0); 37556039Sbostic return (&ib); 37656039Sbostic } 37756039Sbostic if (!strcmp("maxkeypage", s)) { 37856039Sbostic ib.maxkeypage = strtoul(eq, NULL, 0); 37956039Sbostic return (&ib); 38056039Sbostic } 38156039Sbostic if (!strcmp("minkeypage", s)) { 38256039Sbostic ib.minkeypage = strtoul(eq, NULL, 0); 38356039Sbostic return (&ib); 38456039Sbostic } 38556039Sbostic if (!strcmp("lorder", s)) { 38656039Sbostic ib.lorder = strtoul(eq, NULL, 0); 38756039Sbostic return (&ib); 38856039Sbostic } 38956039Sbostic break; 39056039Sbostic case DB_HASH: 39156039Sbostic if (!strcmp("bsize", s)) { 39256039Sbostic ih.bsize = strtoul(eq, NULL, 0); 39356039Sbostic return (&ib); 39456039Sbostic } 39556039Sbostic if (!strcmp("ffactor", s)) { 39656039Sbostic ih.ffactor = strtoul(eq, NULL, 0); 39756039Sbostic return (&ib); 39856039Sbostic } 39956039Sbostic if (!strcmp("nelem", s)) { 40056039Sbostic ih.nelem = strtoul(eq, NULL, 0); 40156039Sbostic return (&ib); 40256039Sbostic } 40356039Sbostic if (!strcmp("cachesize", s)) { 40456039Sbostic ih.cachesize = strtoul(eq, NULL, 0); 40556039Sbostic return (&ib); 40656039Sbostic } 40756039Sbostic if (!strcmp("lorder", s)) { 40856039Sbostic ih.lorder = strtoul(eq, NULL, 0); 40956039Sbostic return (&ib); 41056039Sbostic } 41156039Sbostic break; 41256039Sbostic case DB_RECNO: 41356039Sbostic if (!strcmp("flags", s)) { 41456039Sbostic rh.flags = strtoul(eq, NULL, 0); 41556039Sbostic return (&ib); 41656039Sbostic } 41756039Sbostic if (!strcmp("cachesize", s)) { 41856039Sbostic rh.cachesize = strtoul(eq, NULL, 0); 41956039Sbostic return (&ib); 42056039Sbostic } 42156039Sbostic if (!strcmp("lorder", s)) { 42256039Sbostic rh.lorder = strtoul(eq, NULL, 0); 42356039Sbostic return (&ib); 42456039Sbostic } 42556039Sbostic if (!strcmp("reclen", s)) { 42656039Sbostic rh.reclen = strtoul(eq, NULL, 0); 42756039Sbostic return (&ib); 42856039Sbostic } 42956039Sbostic if (!strcmp("bval", s)) { 43056039Sbostic rh.bval = strtoul(eq, NULL, 0); 43156039Sbostic return (&ib); 43256039Sbostic } 43356039Sbostic break; 43456039Sbostic } 43556039Sbostic err("%s: unknown structure value", s); 43656039Sbostic /* NOTREACHED */ 43756039Sbostic } 43856039Sbostic 43956039Sbostic void * 44056039Sbostic rfile(name, lenp) 44156039Sbostic char *name; 44256039Sbostic size_t *lenp; 44356039Sbostic { 44456039Sbostic struct stat sb; 44556039Sbostic void *p; 44656039Sbostic int fd; 44756039Sbostic char *np; 44856039Sbostic 44956039Sbostic for (; isspace(*name); ++name); 45056039Sbostic if ((np = index(name, '\n')) != NULL) 45156039Sbostic *np = '\0'; 45256039Sbostic if ((fd = open(name, O_RDONLY, 0)) < 0 || 45356039Sbostic fstat(fd, &sb)) 45456039Sbostic err("%s: %s\n", name, strerror(errno)); 45556039Sbostic if (sb.st_size > SIZE_T_MAX) 45656039Sbostic err("%s: %s\n", name, strerror(E2BIG)); 45756039Sbostic if ((p = malloc((u_int)sb.st_size)) == NULL) 45856039Sbostic err("%s", strerror(errno)); 45956039Sbostic (void)read(fd, p, (int)sb.st_size); 46056039Sbostic *lenp = sb.st_size; 461*56489Sbostic (void)close(fd); 46256039Sbostic return (p); 46356039Sbostic } 46456039Sbostic 46556039Sbostic void * 46656039Sbostic xmalloc(text, len) 46756039Sbostic char *text; 46856039Sbostic size_t len; 46956039Sbostic { 47056039Sbostic void *p; 47156039Sbostic 47256039Sbostic if ((p = malloc(len)) == NULL) 47356039Sbostic err("%s", strerror(errno)); 47456039Sbostic bcopy(text, p, len); 47556039Sbostic return (p); 47656039Sbostic } 47756039Sbostic 47856039Sbostic void 47956039Sbostic usage() 48056039Sbostic { 48156039Sbostic (void)fprintf(stderr, 48256039Sbostic "usage: dbtest [-i info] [-o file] type script\n"); 48356039Sbostic exit(1); 48456039Sbostic } 48556039Sbostic 48656039Sbostic #if __STDC__ 48756039Sbostic #include <stdarg.h> 48856039Sbostic #else 48956039Sbostic #include <varargs.h> 49056039Sbostic #endif 49156039Sbostic 49256039Sbostic void 49356039Sbostic #if __STDC__ 49456039Sbostic err(const char *fmt, ...) 49556039Sbostic #else 49656039Sbostic err(fmt, va_alist) 49756039Sbostic char *fmt; 49856039Sbostic va_dcl 49956039Sbostic #endif 50056039Sbostic { 50156039Sbostic va_list ap; 50256039Sbostic #if __STDC__ 50356039Sbostic va_start(ap, fmt); 50456039Sbostic #else 50556039Sbostic va_start(ap); 50656039Sbostic #endif 50756039Sbostic (void)fprintf(stderr, "dbtest: "); 50856039Sbostic (void)vfprintf(stderr, fmt, ap); 50956039Sbostic va_end(ap); 51056039Sbostic (void)fprintf(stderr, "\n"); 51156039Sbostic exit(1); 51256039Sbostic /* NOTREACHED */ 51356039Sbostic } 514