1 /* $NetBSD: h_db.c,v 1.1 2011/01/07 15:05:58 pgoyette Exp $ */
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";
42 __RCSID("$NetBSD: h_db.c,v 1.1 2011/01/07 15:05:58 pgoyette Exp $");
46 #include <sys/param.h>
61 enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
63 static void compare(DBT *, DBT *);
64 static DBTYPE dbtype(const char *);
65 static void dump(DB *, int);
66 static void get(DB *, DBT *);
67 static void getdata(DB *, DBT *, DBT *);
68 static void put(DB *, DBT *, DBT *);
69 static void rem(DB *, DBT *);
70 static const char *sflags(int);
71 static void synk(DB *);
72 static void *rfile(char *, size_t *);
73 static void seq(DB *, DBT *);
74 static u_int setflags(char *);
75 static void *setinfo(DBTYPE, char *);
76 static void usage(void) __attribute__((__noreturn__));
77 static void *xcopy(void *, size_t);
78 static void chkcmd(enum S);
79 static void chkdata(enum S);
80 static void chkkey(enum S);
83 extern void __bt_stat(DB *);
86 static DBTYPE type; /* Database type. */
87 static void *infop; /* Iflags. */
88 static size_t lineno; /* Current line in test script. */
89 static u_int flags; /* Current DB flags. */
90 static int ofd = STDOUT_FILENO; /* Standard output fd. */
92 static DB *XXdbp; /* Global for gdb. */
93 static size_t XXlineno; /* Fast breakpoint for gdb. */
96 main(int argc, char *argv[])
100 enum S command = COMMAND, state;
102 DBT data, key, keydata;
104 int ch, oflags, sflag;
105 char *fname, *infoarg, *p, *t, buf[8 * 1024];
110 unlink_dbfile = false;
111 oflags = O_CREAT | O_RDWR;
113 while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
125 if ((ofd = open(optarg,
126 O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
127 err(1, "Cannot create `%s'", optarg);
143 type = dbtype(*argv++);
145 /* Open the descriptor file. */
146 if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
147 err(1, "Cannot reopen `%s'", *argv);
149 /* Set up the db structure as necessary. */
153 for (p = strtok(infoarg, ",\t "); p != NULL;
154 p = strtok(0, ",\t "))
156 infop = setinfo(type, p);
159 * Open the DB. Delete any preexisting copy, you almost never
160 * want it around, and it often screws up tests.
163 const char *q = getenv("TMPDIR");
166 (void)snprintf(buf, sizeof(buf), "%s/__dbtest", q);
169 unlink_dbfile = true;
173 if ((dbp = dbopen(fname,
174 oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
175 err(1, "Cannot dbopen `%s'", fname);
182 (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
183 /* Delete the newline, displaying the key/data is easier. */
184 if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
186 if ((len = strlen(buf)) == 0 || isspace((unsigned char)*p) ||
190 /* Convenient gdb break point. */
191 if (XXlineno == lineno)
194 case 'c': /* compare */
201 /* Don't display the newline, if CR at EOL. */
202 if (p[len - 2] == '\r')
204 if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 ||
205 write(ofd, "\n", 1) != 1)
206 err(1, "write failed");
218 case 'r': /* remove */
220 if (flags == R_CURSOR) {
235 if (flags == R_CURSOR) {
242 flags = setflags(p + 1);
244 case 'D': /* data file */
246 data.data = rfile(p + 1, &data.size);
250 data.data = xcopy(p + 1, len - 1);
252 ldata: switch (command) {
254 compare(&keydata, &data);
257 put(dbp, &key, &data);
260 errx(1, "line %zu: command doesn't take data",
263 if (type != DB_RECNO)
268 case 'K': /* key file */
270 if (type == DB_RECNO)
271 errx(1, "line %zu: 'K' not available for recno",
273 key.data = rfile(p + 1, &key.size);
277 if (type == DB_RECNO) {
278 static recno_t recno;
281 key.size = sizeof(recno);
283 key.data = xcopy(p + 1, len - 1);
286 lkey: switch (command) {
288 getdata(dbp, &key, &keydata);
293 if (type != DB_RECNO)
302 if ((type != DB_RECNO) && (flags != R_CURSOR))
308 if ((type != DB_RECNO) && (flags != R_CURSOR))
313 errx(1, "line %zu: command doesn't take a key",
318 dump(dbp, p[1] == 'r');
321 errx(1, "line %zu: %s: unknown command character",
327 * -l must be used (DB_LOCK must be set) for this to be
328 * used, otherwise a page will be locked and it will fail.
330 if (type == DB_BTREE && oflags & DB_LOCK)
333 if ((*dbp->close)(dbp))
334 err(1, "db->close failed");
339 #define NOOVERWRITE "put failed, would overwrite key\n"
342 compare(DBT *db1, DBT *db2)
347 if (db1->size != db2->size)
348 printf("compare failed: key->data len %zu != data len %zu\n",
349 db1->size, db2->size);
351 len = MIN(db1->size, db2->size);
352 for (p1 = db1->data, p2 = db2->data; len--;)
353 if (*p1++ != *p2++) {
354 printf("compare failed at offset %lu\n",
355 (unsigned long)(p1 - (u_char *)db1->data));
361 get(DB *dbp, DBT *kp)
365 switch ((*dbp->get)(dbp, kp, &data, flags)) {
367 (void)write(ofd, data.data, data.size);
368 if (ofd == STDOUT_FILENO)
369 (void)write(ofd, "\n", 1);
372 err(1, "line %zu: get failed", lineno);
375 #define NOSUCHKEY "get failed, no such key\n"
376 if (ofd != STDOUT_FILENO)
377 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
379 (void)fprintf(stderr, "%zu: %.*s: %s",
380 lineno, (int)MIN(kp->size, 20),
381 (const char *)kp->data,
389 getdata(DB *dbp, DBT *kp, DBT *dp)
391 switch ((*dbp->get)(dbp, kp, dp, flags)) {
395 err(1, "line %zu: getdata failed", lineno);
398 errx(1, "line %zu: getdata failed, no such key", lineno);
404 put(DB *dbp, DBT *kp, DBT *dp)
406 switch ((*dbp->put)(dbp, kp, dp, flags)) {
410 err(1, "line %zu: put failed", lineno);
413 (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
419 rem(DB *dbp, DBT *kp)
421 switch ((*dbp->del)(dbp, kp, flags)) {
425 err(1, "line %zu: rem failed", lineno);
428 #define NOSUCHKEY "rem failed, no such key\n"
429 if (ofd != STDOUT_FILENO)
430 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
431 else if (flags != R_CURSOR)
432 (void)fprintf(stderr, "%zu: %.*s: %s",
433 lineno, (int)MIN(kp->size, 20),
434 (const char *)kp->data, NOSUCHKEY);
436 (void)fprintf(stderr,
437 "%zu: rem of cursor failed\n", lineno);
446 switch ((*dbp->sync)(dbp, flags)) {
450 err(1, "line %zu: synk failed", lineno);
456 seq(DB *dbp, DBT *kp)
460 switch (dbp->seq(dbp, kp, &data, flags)) {
462 (void)write(ofd, data.data, data.size);
463 if (ofd == STDOUT_FILENO)
464 (void)write(ofd, "\n", 1);
467 err(1, "line %zu: seq failed", lineno);
470 #define NOSUCHKEY "seq failed, no such key\n"
471 if (ofd != STDOUT_FILENO)
472 (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
473 else if (flags == R_CURSOR)
474 (void)fprintf(stderr, "%zu: %.*s: %s",
475 lineno, (int)MIN(kp->size, 20),
476 (const char *)kp->data, NOSUCHKEY);
478 (void)fprintf(stderr,
479 "%zu: seq (%s) failed\n", lineno, sflags(flags));
486 dump(DB *dbp, int rev)
498 for (;; xflags = nflags)
499 switch (dbp->seq(dbp, &key, &data, xflags)) {
501 (void)write(ofd, data.data, data.size);
502 if (ofd == STDOUT_FILENO)
503 (void)write(ofd, "\n", 1);
508 err(1, "line %zu: (dump) seq failed", lineno);
519 for (; isspace((unsigned char)*s); ++s);
520 if (*s == '\n' || *s == '\0')
522 if ((p = strchr(s, '\n')) != NULL)
524 if (!strcmp(s, "R_CURSOR")) return R_CURSOR;
525 if (!strcmp(s, "R_FIRST")) return R_FIRST;
526 if (!strcmp(s, "R_IAFTER")) return R_IAFTER;
527 if (!strcmp(s, "R_IBEFORE")) return R_IBEFORE;
528 if (!strcmp(s, "R_LAST")) return R_LAST;
529 if (!strcmp(s, "R_NEXT")) return R_NEXT;
530 if (!strcmp(s, "R_NOOVERWRITE")) return R_NOOVERWRITE;
531 if (!strcmp(s, "R_PREV")) return R_PREV;
532 if (!strcmp(s, "R_SETCURSOR")) return R_SETCURSOR;
534 errx(1, "line %zu: %s: unknown flag", lineno, s);
542 case R_CURSOR: return "R_CURSOR";
543 case R_FIRST: return "R_FIRST";
544 case R_IAFTER: return "R_IAFTER";
545 case R_IBEFORE: return "R_IBEFORE";
546 case R_LAST: return "R_LAST";
547 case R_NEXT: return "R_NEXT";
548 case R_NOOVERWRITE: return "R_NOOVERWRITE";
549 case R_PREV: return "R_PREV";
550 case R_SETCURSOR: return "R_SETCURSOR";
557 dbtype(const char *s)
559 if (!strcmp(s, "btree"))
561 if (!strcmp(s, "hash"))
563 if (!strcmp(s, "recno"))
565 errx(1, "%s: unknown type (use btree, hash or recno)", s);
570 setinfo(DBTYPE dtype, char *s)
577 if ((eq = strchr(s, '=')) == NULL)
578 errx(1, "%s: illegal structure set statement", s);
580 if (!isdigit((unsigned char)*eq))
581 errx(1, "%s: structure set statement must be a number", s);
585 if (!strcmp("flags", s)) {
589 if (!strcmp("cachesize", s)) {
590 ib.cachesize = atoi(eq);
593 if (!strcmp("maxkeypage", s)) {
594 ib.maxkeypage = atoi(eq);
597 if (!strcmp("minkeypage", s)) {
598 ib.minkeypage = atoi(eq);
601 if (!strcmp("lorder", s)) {
602 ib.lorder = atoi(eq);
605 if (!strcmp("psize", s)) {
611 if (!strcmp("bsize", s)) {
615 if (!strcmp("ffactor", s)) {
616 ih.ffactor = atoi(eq);
619 if (!strcmp("nelem", s)) {
623 if (!strcmp("cachesize", s)) {
624 ih.cachesize = atoi(eq);
627 if (!strcmp("lorder", s)) {
628 ih.lorder = atoi(eq);
633 if (!strcmp("flags", s)) {
637 if (!strcmp("cachesize", s)) {
638 rh.cachesize = atoi(eq);
641 if (!strcmp("lorder", s)) {
642 rh.lorder = atoi(eq);
645 if (!strcmp("reclen", s)) {
646 rh.reclen = atoi(eq);
649 if (!strcmp("bval", s)) {
653 if (!strcmp("psize", s)) {
659 errx(1, "%s: unknown structure value", s);
664 rfile(char *name, size_t *lenp)
671 for (; isspace((unsigned char)*name); ++name)
673 if ((np = strchr(name, '\n')) != NULL)
675 if ((fd = open(name, O_RDONLY, 0)) == -1 || fstat(fd, &sb) == -1)
676 err(1, "Cannot open `%s'", name);
678 if (sb.st_size > (off_t)SIZE_T_MAX) {
680 err("Cannot process `%s'", name);
683 if ((p = malloc((size_t)sb.st_size)) == NULL)
684 err(1, "Cannot allocate %zu bytes", (size_t)sb.st_size);
685 if (read(fd, p, (ssize_t)sb.st_size) != (ssize_t)sb.st_size)
686 err(1, "read failed");
687 *lenp = (size_t)sb.st_size;
693 xcopy(void *text, size_t len)
697 if ((p = malloc(len)) == NULL)
698 err(1, "Cannot allocate %zu bytes", len);
699 (void)memmove(p, text, len);
706 if (state != COMMAND)
707 errx(1, "line %zu: not expecting command", lineno);
711 chkdata(enum S state)
714 errx(1, "line %zu: not expecting data", lineno);
721 errx(1, "line %zu: not expecting a key", lineno);
727 (void)fprintf(stderr,
728 "Usage: %s [-l] [-f file] [-i info] [-o file] type script\n",