xref: /original-bsd/lib/libc/db/test/dbtest.c (revision be1f24e8)
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