1*cdebaff8SEnji Cooper /* $NetBSD: h_db.c,v 1.3 2016/09/24 21:18:22 christos Exp $ */
257718be8SEnji Cooper
357718be8SEnji Cooper /*-
457718be8SEnji Cooper * Copyright (c) 1992, 1993, 1994
557718be8SEnji Cooper * The Regents of the University of California. All rights reserved.
657718be8SEnji Cooper *
757718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without
857718be8SEnji Cooper * modification, are permitted provided that the following conditions
957718be8SEnji Cooper * are met:
1057718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright
1157718be8SEnji Cooper * notice, this list of conditions and the following disclaimer.
1257718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
1357718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the
1457718be8SEnji Cooper * documentation and/or other materials provided with the distribution.
1557718be8SEnji Cooper * 3. Neither the name of the University nor the names of its contributors
1657718be8SEnji Cooper * may be used to endorse or promote products derived from this software
1757718be8SEnji Cooper * without specific prior written permission.
1857718be8SEnji Cooper *
1957718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2057718be8SEnji Cooper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2157718be8SEnji Cooper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2257718be8SEnji Cooper * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2357718be8SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2457718be8SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2557718be8SEnji Cooper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2657718be8SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2757718be8SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2857718be8SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2957718be8SEnji Cooper * SUCH DAMAGE.
3057718be8SEnji Cooper */
3157718be8SEnji Cooper
3257718be8SEnji Cooper #include <sys/cdefs.h>
3357718be8SEnji Cooper #ifndef lint
3457718be8SEnji Cooper __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
3557718be8SEnji Cooper The Regents of the University of California. All rights reserved.");
3657718be8SEnji Cooper #endif /* not lint */
3757718be8SEnji Cooper
3857718be8SEnji Cooper #ifndef lint
3957718be8SEnji Cooper #if 0
4057718be8SEnji Cooper static char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";
4157718be8SEnji Cooper #else
42*cdebaff8SEnji Cooper __RCSID("$NetBSD: h_db.c,v 1.3 2016/09/24 21:18:22 christos Exp $");
4357718be8SEnji Cooper #endif
4457718be8SEnji Cooper #endif /* not lint */
4557718be8SEnji Cooper
4657718be8SEnji Cooper #include <sys/param.h>
4757718be8SEnji Cooper #include <sys/stat.h>
4857718be8SEnji Cooper
4957718be8SEnji Cooper #include <ctype.h>
5057718be8SEnji Cooper #include <errno.h>
5157718be8SEnji Cooper #include <fcntl.h>
5257718be8SEnji Cooper #include <limits.h>
5357718be8SEnji Cooper #include <stdio.h>
5457718be8SEnji Cooper #include <stdlib.h>
5557718be8SEnji Cooper #include <string.h>
5657718be8SEnji Cooper #include <stdbool.h>
5757718be8SEnji Cooper #include <unistd.h>
5857718be8SEnji Cooper #include <err.h>
5957718be8SEnji Cooper #include <db.h>
60*cdebaff8SEnji Cooper #include "btree.h"
6157718be8SEnji Cooper
6257718be8SEnji Cooper enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
6357718be8SEnji Cooper
6457718be8SEnji Cooper static void compare(DBT *, DBT *);
6557718be8SEnji Cooper static DBTYPE dbtype(const char *);
66*cdebaff8SEnji Cooper static void dump(DB *, int, int);
6757718be8SEnji Cooper static void get(DB *, DBT *);
6857718be8SEnji Cooper static void getdata(DB *, DBT *, DBT *);
6957718be8SEnji Cooper static void put(DB *, DBT *, DBT *);
7057718be8SEnji Cooper static void rem(DB *, DBT *);
7157718be8SEnji Cooper static const char *sflags(int);
7257718be8SEnji Cooper static void synk(DB *);
7357718be8SEnji Cooper static void *rfile(char *, size_t *);
7457718be8SEnji Cooper static void seq(DB *, DBT *);
7557718be8SEnji Cooper static u_int setflags(char *);
7657718be8SEnji Cooper static void *setinfo(DBTYPE, char *);
77*cdebaff8SEnji Cooper #ifdef __NetBSD__
78*cdebaff8SEnji Cooper static void unlinkpg(DB *);
79*cdebaff8SEnji Cooper #endif
8057718be8SEnji Cooper static void usage(void) __attribute__((__noreturn__));
8157718be8SEnji Cooper static void *xcopy(void *, size_t);
8257718be8SEnji Cooper static void chkcmd(enum S);
8357718be8SEnji Cooper static void chkdata(enum S);
8457718be8SEnji Cooper static void chkkey(enum S);
8557718be8SEnji Cooper
8657718be8SEnji Cooper #ifdef STATISTICS
8757718be8SEnji Cooper extern void __bt_stat(DB *);
8857718be8SEnji Cooper #endif
89*cdebaff8SEnji Cooper #ifdef __NetBSD__
90*cdebaff8SEnji Cooper extern int __bt_relink(BTREE *, PAGE *);
91*cdebaff8SEnji Cooper #endif
9257718be8SEnji Cooper
9357718be8SEnji Cooper static DBTYPE type; /* Database type. */
9457718be8SEnji Cooper static void *infop; /* Iflags. */
9557718be8SEnji Cooper static size_t lineno; /* Current line in test script. */
9657718be8SEnji Cooper static u_int flags; /* Current DB flags. */
9757718be8SEnji Cooper static int ofd = STDOUT_FILENO; /* Standard output fd. */
9857718be8SEnji Cooper
9957718be8SEnji Cooper static DB *XXdbp; /* Global for gdb. */
10057718be8SEnji Cooper static size_t XXlineno; /* Fast breakpoint for gdb. */
10157718be8SEnji Cooper
10257718be8SEnji Cooper int
main(int argc,char * argv[])10357718be8SEnji Cooper main(int argc, char *argv[])
10457718be8SEnji Cooper {
10557718be8SEnji Cooper extern int optind;
10657718be8SEnji Cooper extern char *optarg;
10757718be8SEnji Cooper enum S command = COMMAND, state;
10857718be8SEnji Cooper DB *dbp;
10957718be8SEnji Cooper DBT data, key, keydata;
11057718be8SEnji Cooper size_t len;
11157718be8SEnji Cooper int ch, oflags, sflag;
11257718be8SEnji Cooper char *fname, *infoarg, *p, *t, buf[8 * 1024];
11357718be8SEnji Cooper bool unlink_dbfile;
11457718be8SEnji Cooper
11557718be8SEnji Cooper infoarg = NULL;
11657718be8SEnji Cooper fname = NULL;
11757718be8SEnji Cooper unlink_dbfile = false;
11857718be8SEnji Cooper oflags = O_CREAT | O_RDWR;
11957718be8SEnji Cooper sflag = 0;
12057718be8SEnji Cooper while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
12157718be8SEnji Cooper switch (ch) {
12257718be8SEnji Cooper case 'f':
12357718be8SEnji Cooper fname = optarg;
12457718be8SEnji Cooper break;
12557718be8SEnji Cooper case 'i':
12657718be8SEnji Cooper infoarg = optarg;
12757718be8SEnji Cooper break;
12857718be8SEnji Cooper case 'l':
12957718be8SEnji Cooper oflags |= DB_LOCK;
13057718be8SEnji Cooper break;
13157718be8SEnji Cooper case 'o':
13257718be8SEnji Cooper if ((ofd = open(optarg,
13357718be8SEnji Cooper O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
13457718be8SEnji Cooper err(1, "Cannot create `%s'", optarg);
13557718be8SEnji Cooper break;
13657718be8SEnji Cooper case 's':
13757718be8SEnji Cooper sflag = 1;
13857718be8SEnji Cooper break;
13957718be8SEnji Cooper case '?':
14057718be8SEnji Cooper default:
14157718be8SEnji Cooper usage();
14257718be8SEnji Cooper }
14357718be8SEnji Cooper argc -= optind;
14457718be8SEnji Cooper argv += optind;
14557718be8SEnji Cooper
14657718be8SEnji Cooper if (argc != 2)
14757718be8SEnji Cooper usage();
14857718be8SEnji Cooper
14957718be8SEnji Cooper /* Set the type. */
15057718be8SEnji Cooper type = dbtype(*argv++);
15157718be8SEnji Cooper
15257718be8SEnji Cooper /* Open the descriptor file. */
15357718be8SEnji Cooper if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
15457718be8SEnji Cooper err(1, "Cannot reopen `%s'", *argv);
15557718be8SEnji Cooper
15657718be8SEnji Cooper /* Set up the db structure as necessary. */
15757718be8SEnji Cooper if (infoarg == NULL)
15857718be8SEnji Cooper infop = NULL;
15957718be8SEnji Cooper else
16057718be8SEnji Cooper for (p = strtok(infoarg, ",\t "); p != NULL;
16157718be8SEnji Cooper p = strtok(0, ",\t "))
16257718be8SEnji Cooper if (*p != '\0')
16357718be8SEnji Cooper infop = setinfo(type, p);
16457718be8SEnji Cooper
16557718be8SEnji Cooper /*
16657718be8SEnji Cooper * Open the DB. Delete any preexisting copy, you almost never
16757718be8SEnji Cooper * want it around, and it often screws up tests.
16857718be8SEnji Cooper */
16957718be8SEnji Cooper if (fname == NULL) {
17057718be8SEnji Cooper const char *q = getenv("TMPDIR");
17157718be8SEnji Cooper if (q == NULL)
17257718be8SEnji Cooper q = "/var/tmp";
17357718be8SEnji Cooper (void)snprintf(buf, sizeof(buf), "%s/__dbtest", q);
17457718be8SEnji Cooper fname = buf;
17557718be8SEnji Cooper (void)unlink(buf);
17657718be8SEnji Cooper unlink_dbfile = true;
17757718be8SEnji Cooper } else if (!sflag)
17857718be8SEnji Cooper (void)unlink(fname);
17957718be8SEnji Cooper
18057718be8SEnji Cooper if ((dbp = dbopen(fname,
18157718be8SEnji Cooper oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
18257718be8SEnji Cooper err(1, "Cannot dbopen `%s'", fname);
18357718be8SEnji Cooper XXdbp = dbp;
18457718be8SEnji Cooper if (unlink_dbfile)
18557718be8SEnji Cooper (void)unlink(fname);
18657718be8SEnji Cooper
18757718be8SEnji Cooper state = COMMAND;
18857718be8SEnji Cooper for (lineno = 1;
18957718be8SEnji Cooper (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
19057718be8SEnji Cooper /* Delete the newline, displaying the key/data is easier. */
19157718be8SEnji Cooper if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
19257718be8SEnji Cooper *t = '\0';
19357718be8SEnji Cooper if ((len = strlen(buf)) == 0 || isspace((unsigned char)*p) ||
19457718be8SEnji Cooper *p == '#')
19557718be8SEnji Cooper continue;
19657718be8SEnji Cooper
19757718be8SEnji Cooper /* Convenient gdb break point. */
19857718be8SEnji Cooper if (XXlineno == lineno)
19957718be8SEnji Cooper XXlineno = 1;
20057718be8SEnji Cooper switch (*p) {
20157718be8SEnji Cooper case 'c': /* compare */
20257718be8SEnji Cooper chkcmd(state);
20357718be8SEnji Cooper state = KEY;
20457718be8SEnji Cooper command = COMPARE;
20557718be8SEnji Cooper break;
20657718be8SEnji Cooper case 'e': /* echo */
20757718be8SEnji Cooper chkcmd(state);
20857718be8SEnji Cooper /* Don't display the newline, if CR at EOL. */
20957718be8SEnji Cooper if (p[len - 2] == '\r')
21057718be8SEnji Cooper --len;
21157718be8SEnji Cooper if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 ||
21257718be8SEnji Cooper write(ofd, "\n", 1) != 1)
21357718be8SEnji Cooper err(1, "write failed");
21457718be8SEnji Cooper break;
21557718be8SEnji Cooper case 'g': /* get */
21657718be8SEnji Cooper chkcmd(state);
21757718be8SEnji Cooper state = KEY;
21857718be8SEnji Cooper command = GET;
21957718be8SEnji Cooper break;
22057718be8SEnji Cooper case 'p': /* put */
22157718be8SEnji Cooper chkcmd(state);
22257718be8SEnji Cooper state = KEY;
22357718be8SEnji Cooper command = PUT;
22457718be8SEnji Cooper break;
22557718be8SEnji Cooper case 'r': /* remove */
22657718be8SEnji Cooper chkcmd(state);
22757718be8SEnji Cooper if (flags == R_CURSOR) {
22857718be8SEnji Cooper rem(dbp, &key);
22957718be8SEnji Cooper state = COMMAND;
23057718be8SEnji Cooper } else {
23157718be8SEnji Cooper state = KEY;
23257718be8SEnji Cooper command = REMOVE;
23357718be8SEnji Cooper }
23457718be8SEnji Cooper break;
23557718be8SEnji Cooper case 'S': /* sync */
23657718be8SEnji Cooper chkcmd(state);
23757718be8SEnji Cooper synk(dbp);
23857718be8SEnji Cooper state = COMMAND;
23957718be8SEnji Cooper break;
24057718be8SEnji Cooper case 's': /* seq */
24157718be8SEnji Cooper chkcmd(state);
24257718be8SEnji Cooper if (flags == R_CURSOR) {
24357718be8SEnji Cooper state = KEY;
24457718be8SEnji Cooper command = SEQ;
24557718be8SEnji Cooper } else
24657718be8SEnji Cooper seq(dbp, &key);
24757718be8SEnji Cooper break;
24857718be8SEnji Cooper case 'f':
24957718be8SEnji Cooper flags = setflags(p + 1);
25057718be8SEnji Cooper break;
25157718be8SEnji Cooper case 'D': /* data file */
25257718be8SEnji Cooper chkdata(state);
25357718be8SEnji Cooper data.data = rfile(p + 1, &data.size);
25457718be8SEnji Cooper goto ldata;
25557718be8SEnji Cooper case 'd': /* data */
25657718be8SEnji Cooper chkdata(state);
25757718be8SEnji Cooper data.data = xcopy(p + 1, len - 1);
25857718be8SEnji Cooper data.size = len - 1;
25957718be8SEnji Cooper ldata: switch (command) {
26057718be8SEnji Cooper case COMPARE:
26157718be8SEnji Cooper compare(&keydata, &data);
26257718be8SEnji Cooper break;
26357718be8SEnji Cooper case PUT:
26457718be8SEnji Cooper put(dbp, &key, &data);
26557718be8SEnji Cooper break;
26657718be8SEnji Cooper default:
26757718be8SEnji Cooper errx(1, "line %zu: command doesn't take data",
26857718be8SEnji Cooper lineno);
26957718be8SEnji Cooper }
27057718be8SEnji Cooper if (type != DB_RECNO)
27157718be8SEnji Cooper free(key.data);
27257718be8SEnji Cooper free(data.data);
27357718be8SEnji Cooper state = COMMAND;
27457718be8SEnji Cooper break;
27557718be8SEnji Cooper case 'K': /* key file */
27657718be8SEnji Cooper chkkey(state);
27757718be8SEnji Cooper if (type == DB_RECNO)
27857718be8SEnji Cooper errx(1, "line %zu: 'K' not available for recno",
27957718be8SEnji Cooper lineno);
28057718be8SEnji Cooper key.data = rfile(p + 1, &key.size);
28157718be8SEnji Cooper goto lkey;
28257718be8SEnji Cooper case 'k': /* key */
28357718be8SEnji Cooper chkkey(state);
28457718be8SEnji Cooper if (type == DB_RECNO) {
28557718be8SEnji Cooper static recno_t recno;
28657718be8SEnji Cooper recno = atoi(p + 1);
28757718be8SEnji Cooper key.data = &recno;
28857718be8SEnji Cooper key.size = sizeof(recno);
28957718be8SEnji Cooper } else {
29057718be8SEnji Cooper key.data = xcopy(p + 1, len - 1);
29157718be8SEnji Cooper key.size = len - 1;
29257718be8SEnji Cooper }
29357718be8SEnji Cooper lkey: switch (command) {
29457718be8SEnji Cooper case COMPARE:
29557718be8SEnji Cooper getdata(dbp, &key, &keydata);
29657718be8SEnji Cooper state = DATA;
29757718be8SEnji Cooper break;
29857718be8SEnji Cooper case GET:
29957718be8SEnji Cooper get(dbp, &key);
30057718be8SEnji Cooper if (type != DB_RECNO)
30157718be8SEnji Cooper free(key.data);
30257718be8SEnji Cooper state = COMMAND;
30357718be8SEnji Cooper break;
30457718be8SEnji Cooper case PUT:
30557718be8SEnji Cooper state = DATA;
30657718be8SEnji Cooper break;
30757718be8SEnji Cooper case REMOVE:
30857718be8SEnji Cooper rem(dbp, &key);
30957718be8SEnji Cooper if ((type != DB_RECNO) && (flags != R_CURSOR))
31057718be8SEnji Cooper free(key.data);
31157718be8SEnji Cooper state = COMMAND;
31257718be8SEnji Cooper break;
31357718be8SEnji Cooper case SEQ:
31457718be8SEnji Cooper seq(dbp, &key);
31557718be8SEnji Cooper if ((type != DB_RECNO) && (flags != R_CURSOR))
31657718be8SEnji Cooper free(key.data);
31757718be8SEnji Cooper state = COMMAND;
31857718be8SEnji Cooper break;
31957718be8SEnji Cooper default:
32057718be8SEnji Cooper errx(1, "line %zu: command doesn't take a key",
32157718be8SEnji Cooper lineno);
32257718be8SEnji Cooper }
32357718be8SEnji Cooper break;
32457718be8SEnji Cooper case 'o':
325*cdebaff8SEnji Cooper dump(dbp, p[1] == 'r', 0);
32657718be8SEnji Cooper break;
327*cdebaff8SEnji Cooper #ifdef __NetBSD__
328*cdebaff8SEnji Cooper case 'O':
329*cdebaff8SEnji Cooper dump(dbp, p[1] == 'r', 1);
330*cdebaff8SEnji Cooper break;
331*cdebaff8SEnji Cooper case 'u':
332*cdebaff8SEnji Cooper unlinkpg(dbp);
333*cdebaff8SEnji Cooper break;
334*cdebaff8SEnji Cooper #endif
33557718be8SEnji Cooper default:
33657718be8SEnji Cooper errx(1, "line %zu: %s: unknown command character",
33757718be8SEnji Cooper lineno, p);
33857718be8SEnji Cooper }
33957718be8SEnji Cooper }
34057718be8SEnji Cooper #ifdef STATISTICS
34157718be8SEnji Cooper /*
34257718be8SEnji Cooper * -l must be used (DB_LOCK must be set) for this to be
34357718be8SEnji Cooper * used, otherwise a page will be locked and it will fail.
34457718be8SEnji Cooper */
34557718be8SEnji Cooper if (type == DB_BTREE && oflags & DB_LOCK)
34657718be8SEnji Cooper __bt_stat(dbp);
34757718be8SEnji Cooper #endif
34857718be8SEnji Cooper if ((*dbp->close)(dbp))
34957718be8SEnji Cooper err(1, "db->close failed");
35057718be8SEnji Cooper (void)close(ofd);
35157718be8SEnji Cooper return 0;
35257718be8SEnji Cooper }
35357718be8SEnji Cooper
35457718be8SEnji Cooper #define NOOVERWRITE "put failed, would overwrite key\n"
35557718be8SEnji Cooper
35657718be8SEnji Cooper static void
compare(DBT * db1,DBT * db2)35757718be8SEnji Cooper compare(DBT *db1, DBT *db2)
35857718be8SEnji Cooper {
35957718be8SEnji Cooper size_t len;
36057718be8SEnji Cooper u_char *p1, *p2;
36157718be8SEnji Cooper
36257718be8SEnji Cooper if (db1->size != db2->size)
36357718be8SEnji Cooper printf("compare failed: key->data len %zu != data len %zu\n",
36457718be8SEnji Cooper db1->size, db2->size);
36557718be8SEnji Cooper
36657718be8SEnji Cooper len = MIN(db1->size, db2->size);
36757718be8SEnji Cooper for (p1 = db1->data, p2 = db2->data; len--;)
36857718be8SEnji Cooper if (*p1++ != *p2++) {
36957718be8SEnji Cooper printf("compare failed at offset %lu\n",
37057718be8SEnji Cooper (unsigned long)(p1 - (u_char *)db1->data));
37157718be8SEnji Cooper break;
37257718be8SEnji Cooper }
37357718be8SEnji Cooper }
37457718be8SEnji Cooper
37557718be8SEnji Cooper static void
get(DB * dbp,DBT * kp)37657718be8SEnji Cooper get(DB *dbp, DBT *kp)
37757718be8SEnji Cooper {
37857718be8SEnji Cooper DBT data;
37957718be8SEnji Cooper
38057718be8SEnji Cooper switch ((*dbp->get)(dbp, kp, &data, flags)) {
38157718be8SEnji Cooper case 0:
38257718be8SEnji Cooper (void)write(ofd, data.data, data.size);
38357718be8SEnji Cooper if (ofd == STDOUT_FILENO)
38457718be8SEnji Cooper (void)write(ofd, "\n", 1);
38557718be8SEnji Cooper break;
38657718be8SEnji Cooper case -1:
38757718be8SEnji Cooper err(1, "line %zu: get failed", lineno);
38857718be8SEnji Cooper /* NOTREACHED */
38957718be8SEnji Cooper case 1:
39057718be8SEnji Cooper #define NOSUCHKEY "get failed, no such key\n"
39157718be8SEnji Cooper if (ofd != STDOUT_FILENO)
39257718be8SEnji Cooper (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
39357718be8SEnji Cooper else
39457718be8SEnji Cooper (void)fprintf(stderr, "%zu: %.*s: %s",
39557718be8SEnji Cooper lineno, (int)MIN(kp->size, 20),
39657718be8SEnji Cooper (const char *)kp->data,
39757718be8SEnji Cooper NOSUCHKEY);
39857718be8SEnji Cooper #undef NOSUCHKEY
39957718be8SEnji Cooper break;
40057718be8SEnji Cooper }
40157718be8SEnji Cooper }
40257718be8SEnji Cooper
40357718be8SEnji Cooper static void
getdata(DB * dbp,DBT * kp,DBT * dp)40457718be8SEnji Cooper getdata(DB *dbp, DBT *kp, DBT *dp)
40557718be8SEnji Cooper {
40657718be8SEnji Cooper switch ((*dbp->get)(dbp, kp, dp, flags)) {
40757718be8SEnji Cooper case 0:
40857718be8SEnji Cooper return;
40957718be8SEnji Cooper case -1:
41057718be8SEnji Cooper err(1, "line %zu: getdata failed", lineno);
41157718be8SEnji Cooper /* NOTREACHED */
41257718be8SEnji Cooper case 1:
41357718be8SEnji Cooper errx(1, "line %zu: getdata failed, no such key", lineno);
41457718be8SEnji Cooper /* NOTREACHED */
41557718be8SEnji Cooper }
41657718be8SEnji Cooper }
41757718be8SEnji Cooper
41857718be8SEnji Cooper static void
put(DB * dbp,DBT * kp,DBT * dp)41957718be8SEnji Cooper put(DB *dbp, DBT *kp, DBT *dp)
42057718be8SEnji Cooper {
42157718be8SEnji Cooper switch ((*dbp->put)(dbp, kp, dp, flags)) {
42257718be8SEnji Cooper case 0:
42357718be8SEnji Cooper break;
42457718be8SEnji Cooper case -1:
42557718be8SEnji Cooper err(1, "line %zu: put failed", lineno);
42657718be8SEnji Cooper /* NOTREACHED */
42757718be8SEnji Cooper case 1:
42857718be8SEnji Cooper (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
42957718be8SEnji Cooper break;
43057718be8SEnji Cooper }
43157718be8SEnji Cooper }
43257718be8SEnji Cooper
43357718be8SEnji Cooper static void
rem(DB * dbp,DBT * kp)43457718be8SEnji Cooper rem(DB *dbp, DBT *kp)
43557718be8SEnji Cooper {
43657718be8SEnji Cooper switch ((*dbp->del)(dbp, kp, flags)) {
43757718be8SEnji Cooper case 0:
43857718be8SEnji Cooper break;
43957718be8SEnji Cooper case -1:
44057718be8SEnji Cooper err(1, "line %zu: rem failed", lineno);
44157718be8SEnji Cooper /* NOTREACHED */
44257718be8SEnji Cooper case 1:
44357718be8SEnji Cooper #define NOSUCHKEY "rem failed, no such key\n"
44457718be8SEnji Cooper if (ofd != STDOUT_FILENO)
44557718be8SEnji Cooper (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
44657718be8SEnji Cooper else if (flags != R_CURSOR)
44757718be8SEnji Cooper (void)fprintf(stderr, "%zu: %.*s: %s",
44857718be8SEnji Cooper lineno, (int)MIN(kp->size, 20),
44957718be8SEnji Cooper (const char *)kp->data, NOSUCHKEY);
45057718be8SEnji Cooper else
45157718be8SEnji Cooper (void)fprintf(stderr,
45257718be8SEnji Cooper "%zu: rem of cursor failed\n", lineno);
45357718be8SEnji Cooper #undef NOSUCHKEY
45457718be8SEnji Cooper break;
45557718be8SEnji Cooper }
45657718be8SEnji Cooper }
45757718be8SEnji Cooper
45857718be8SEnji Cooper static void
synk(DB * dbp)45957718be8SEnji Cooper synk(DB *dbp)
46057718be8SEnji Cooper {
46157718be8SEnji Cooper switch ((*dbp->sync)(dbp, flags)) {
46257718be8SEnji Cooper case 0:
46357718be8SEnji Cooper break;
46457718be8SEnji Cooper case -1:
46557718be8SEnji Cooper err(1, "line %zu: synk failed", lineno);
46657718be8SEnji Cooper /* NOTREACHED */
46757718be8SEnji Cooper }
46857718be8SEnji Cooper }
46957718be8SEnji Cooper
47057718be8SEnji Cooper static void
seq(DB * dbp,DBT * kp)47157718be8SEnji Cooper seq(DB *dbp, DBT *kp)
47257718be8SEnji Cooper {
47357718be8SEnji Cooper DBT data;
47457718be8SEnji Cooper
47557718be8SEnji Cooper switch (dbp->seq(dbp, kp, &data, flags)) {
47657718be8SEnji Cooper case 0:
47757718be8SEnji Cooper (void)write(ofd, data.data, data.size);
47857718be8SEnji Cooper if (ofd == STDOUT_FILENO)
47957718be8SEnji Cooper (void)write(ofd, "\n", 1);
48057718be8SEnji Cooper break;
48157718be8SEnji Cooper case -1:
48257718be8SEnji Cooper err(1, "line %zu: seq failed", lineno);
48357718be8SEnji Cooper /* NOTREACHED */
48457718be8SEnji Cooper case 1:
48557718be8SEnji Cooper #define NOSUCHKEY "seq failed, no such key\n"
48657718be8SEnji Cooper if (ofd != STDOUT_FILENO)
48757718be8SEnji Cooper (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
48857718be8SEnji Cooper else if (flags == R_CURSOR)
48957718be8SEnji Cooper (void)fprintf(stderr, "%zu: %.*s: %s",
49057718be8SEnji Cooper lineno, (int)MIN(kp->size, 20),
49157718be8SEnji Cooper (const char *)kp->data, NOSUCHKEY);
49257718be8SEnji Cooper else
49357718be8SEnji Cooper (void)fprintf(stderr,
49457718be8SEnji Cooper "%zu: seq (%s) failed\n", lineno, sflags(flags));
49557718be8SEnji Cooper #undef NOSUCHKEY
49657718be8SEnji Cooper break;
49757718be8SEnji Cooper }
49857718be8SEnji Cooper }
49957718be8SEnji Cooper
50057718be8SEnji Cooper static void
dump(DB * dbp,int rev,int recurse)501*cdebaff8SEnji Cooper dump(DB *dbp, int rev, int recurse)
50257718be8SEnji Cooper {
50357718be8SEnji Cooper DBT key, data;
50457718be8SEnji Cooper int xflags, nflags;
50557718be8SEnji Cooper
50657718be8SEnji Cooper if (rev) {
50757718be8SEnji Cooper xflags = R_LAST;
508*cdebaff8SEnji Cooper #ifdef __NetBSD__
509*cdebaff8SEnji Cooper nflags = recurse ? R_RPREV : R_PREV;
510*cdebaff8SEnji Cooper #else
51157718be8SEnji Cooper nflags = R_PREV;
512*cdebaff8SEnji Cooper #endif
51357718be8SEnji Cooper } else {
51457718be8SEnji Cooper xflags = R_FIRST;
515*cdebaff8SEnji Cooper #ifdef __NetBSD__
516*cdebaff8SEnji Cooper nflags = recurse ? R_RNEXT : R_NEXT;
517*cdebaff8SEnji Cooper #else
51857718be8SEnji Cooper nflags = R_NEXT;
519*cdebaff8SEnji Cooper #endif
52057718be8SEnji Cooper }
52157718be8SEnji Cooper for (;; xflags = nflags)
52257718be8SEnji Cooper switch (dbp->seq(dbp, &key, &data, xflags)) {
52357718be8SEnji Cooper case 0:
52457718be8SEnji Cooper (void)write(ofd, data.data, data.size);
52557718be8SEnji Cooper if (ofd == STDOUT_FILENO)
52657718be8SEnji Cooper (void)write(ofd, "\n", 1);
52757718be8SEnji Cooper break;
52857718be8SEnji Cooper case 1:
52957718be8SEnji Cooper goto done;
53057718be8SEnji Cooper case -1:
53157718be8SEnji Cooper err(1, "line %zu: (dump) seq failed", lineno);
53257718be8SEnji Cooper /* NOTREACHED */
53357718be8SEnji Cooper }
53457718be8SEnji Cooper done: return;
53557718be8SEnji Cooper }
53657718be8SEnji Cooper
537*cdebaff8SEnji Cooper #ifdef __NetBSD__
538*cdebaff8SEnji Cooper void
unlinkpg(DB * dbp)539*cdebaff8SEnji Cooper unlinkpg(DB *dbp)
540*cdebaff8SEnji Cooper {
541*cdebaff8SEnji Cooper BTREE *t = dbp->internal;
542*cdebaff8SEnji Cooper PAGE *h = NULL;
543*cdebaff8SEnji Cooper pgno_t pg;
544*cdebaff8SEnji Cooper
545*cdebaff8SEnji Cooper for (pg = P_ROOT; pg < t->bt_mp->npages;
546*cdebaff8SEnji Cooper mpool_put(t->bt_mp, h, 0), pg++) {
547*cdebaff8SEnji Cooper if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
548*cdebaff8SEnji Cooper break;
549*cdebaff8SEnji Cooper /* Look for a nonempty leaf page that has both left
550*cdebaff8SEnji Cooper * and right siblings. */
551*cdebaff8SEnji Cooper if (h->prevpg == P_INVALID || h->nextpg == P_INVALID)
552*cdebaff8SEnji Cooper continue;
553*cdebaff8SEnji Cooper if (NEXTINDEX(h) == 0)
554*cdebaff8SEnji Cooper continue;
555*cdebaff8SEnji Cooper if ((h->flags & (P_BLEAF | P_RLEAF)))
556*cdebaff8SEnji Cooper break;
557*cdebaff8SEnji Cooper }
558*cdebaff8SEnji Cooper if (h == NULL || pg == t->bt_mp->npages) {
559*cdebaff8SEnji Cooper errx(1, "%s: no appropriate page found", __func__);
560*cdebaff8SEnji Cooper return;
561*cdebaff8SEnji Cooper }
562*cdebaff8SEnji Cooper if (__bt_relink(t, h) != 0) {
563*cdebaff8SEnji Cooper perror("unlinkpg");
564*cdebaff8SEnji Cooper goto cleanup;
565*cdebaff8SEnji Cooper }
566*cdebaff8SEnji Cooper h->prevpg = P_INVALID;
567*cdebaff8SEnji Cooper h->nextpg = P_INVALID;
568*cdebaff8SEnji Cooper cleanup:
569*cdebaff8SEnji Cooper mpool_put(t->bt_mp, h, MPOOL_DIRTY);
570*cdebaff8SEnji Cooper }
571*cdebaff8SEnji Cooper #endif
572*cdebaff8SEnji Cooper
57357718be8SEnji Cooper static u_int
setflags(char * s)57457718be8SEnji Cooper setflags(char *s)
57557718be8SEnji Cooper {
57657718be8SEnji Cooper char *p;
57757718be8SEnji Cooper
57857718be8SEnji Cooper for (; isspace((unsigned char)*s); ++s);
57957718be8SEnji Cooper if (*s == '\n' || *s == '\0')
58057718be8SEnji Cooper return 0;
58157718be8SEnji Cooper if ((p = strchr(s, '\n')) != NULL)
58257718be8SEnji Cooper *p = '\0';
58357718be8SEnji Cooper if (!strcmp(s, "R_CURSOR")) return R_CURSOR;
58457718be8SEnji Cooper if (!strcmp(s, "R_FIRST")) return R_FIRST;
58557718be8SEnji Cooper if (!strcmp(s, "R_IAFTER")) return R_IAFTER;
58657718be8SEnji Cooper if (!strcmp(s, "R_IBEFORE")) return R_IBEFORE;
58757718be8SEnji Cooper if (!strcmp(s, "R_LAST")) return R_LAST;
58857718be8SEnji Cooper if (!strcmp(s, "R_NEXT")) return R_NEXT;
58957718be8SEnji Cooper if (!strcmp(s, "R_NOOVERWRITE")) return R_NOOVERWRITE;
59057718be8SEnji Cooper if (!strcmp(s, "R_PREV")) return R_PREV;
59157718be8SEnji Cooper if (!strcmp(s, "R_SETCURSOR")) return R_SETCURSOR;
59257718be8SEnji Cooper
59357718be8SEnji Cooper errx(1, "line %zu: %s: unknown flag", lineno, s);
59457718be8SEnji Cooper /* NOTREACHED */
59557718be8SEnji Cooper }
59657718be8SEnji Cooper
59757718be8SEnji Cooper static const char *
sflags(int xflags)59857718be8SEnji Cooper sflags(int xflags)
59957718be8SEnji Cooper {
60057718be8SEnji Cooper switch (xflags) {
60157718be8SEnji Cooper case R_CURSOR: return "R_CURSOR";
60257718be8SEnji Cooper case R_FIRST: return "R_FIRST";
60357718be8SEnji Cooper case R_IAFTER: return "R_IAFTER";
60457718be8SEnji Cooper case R_IBEFORE: return "R_IBEFORE";
60557718be8SEnji Cooper case R_LAST: return "R_LAST";
60657718be8SEnji Cooper case R_NEXT: return "R_NEXT";
60757718be8SEnji Cooper case R_NOOVERWRITE: return "R_NOOVERWRITE";
60857718be8SEnji Cooper case R_PREV: return "R_PREV";
60957718be8SEnji Cooper case R_SETCURSOR: return "R_SETCURSOR";
61057718be8SEnji Cooper }
61157718be8SEnji Cooper
61257718be8SEnji Cooper return "UNKNOWN!";
61357718be8SEnji Cooper }
61457718be8SEnji Cooper
61557718be8SEnji Cooper static DBTYPE
dbtype(const char * s)61657718be8SEnji Cooper dbtype(const char *s)
61757718be8SEnji Cooper {
61857718be8SEnji Cooper if (!strcmp(s, "btree"))
61957718be8SEnji Cooper return DB_BTREE;
62057718be8SEnji Cooper if (!strcmp(s, "hash"))
62157718be8SEnji Cooper return DB_HASH;
62257718be8SEnji Cooper if (!strcmp(s, "recno"))
62357718be8SEnji Cooper return DB_RECNO;
62457718be8SEnji Cooper errx(1, "%s: unknown type (use btree, hash or recno)", s);
62557718be8SEnji Cooper /* NOTREACHED */
62657718be8SEnji Cooper }
62757718be8SEnji Cooper
62857718be8SEnji Cooper static void *
setinfo(DBTYPE dtype,char * s)62957718be8SEnji Cooper setinfo(DBTYPE dtype, char *s)
63057718be8SEnji Cooper {
63157718be8SEnji Cooper static BTREEINFO ib;
63257718be8SEnji Cooper static HASHINFO ih;
63357718be8SEnji Cooper static RECNOINFO rh;
63457718be8SEnji Cooper char *eq;
63557718be8SEnji Cooper
63657718be8SEnji Cooper if ((eq = strchr(s, '=')) == NULL)
63757718be8SEnji Cooper errx(1, "%s: illegal structure set statement", s);
63857718be8SEnji Cooper *eq++ = '\0';
63957718be8SEnji Cooper if (!isdigit((unsigned char)*eq))
64057718be8SEnji Cooper errx(1, "%s: structure set statement must be a number", s);
64157718be8SEnji Cooper
64257718be8SEnji Cooper switch (dtype) {
64357718be8SEnji Cooper case DB_BTREE:
64457718be8SEnji Cooper if (!strcmp("flags", s)) {
64557718be8SEnji Cooper ib.flags = atoi(eq);
64657718be8SEnji Cooper return &ib;
64757718be8SEnji Cooper }
64857718be8SEnji Cooper if (!strcmp("cachesize", s)) {
64957718be8SEnji Cooper ib.cachesize = atoi(eq);
65057718be8SEnji Cooper return &ib;
65157718be8SEnji Cooper }
65257718be8SEnji Cooper if (!strcmp("maxkeypage", s)) {
65357718be8SEnji Cooper ib.maxkeypage = atoi(eq);
65457718be8SEnji Cooper return &ib;
65557718be8SEnji Cooper }
65657718be8SEnji Cooper if (!strcmp("minkeypage", s)) {
65757718be8SEnji Cooper ib.minkeypage = atoi(eq);
65857718be8SEnji Cooper return &ib;
65957718be8SEnji Cooper }
66057718be8SEnji Cooper if (!strcmp("lorder", s)) {
66157718be8SEnji Cooper ib.lorder = atoi(eq);
66257718be8SEnji Cooper return &ib;
66357718be8SEnji Cooper }
66457718be8SEnji Cooper if (!strcmp("psize", s)) {
66557718be8SEnji Cooper ib.psize = atoi(eq);
66657718be8SEnji Cooper return &ib;
66757718be8SEnji Cooper }
66857718be8SEnji Cooper break;
66957718be8SEnji Cooper case DB_HASH:
67057718be8SEnji Cooper if (!strcmp("bsize", s)) {
67157718be8SEnji Cooper ih.bsize = atoi(eq);
67257718be8SEnji Cooper return &ih;
67357718be8SEnji Cooper }
67457718be8SEnji Cooper if (!strcmp("ffactor", s)) {
67557718be8SEnji Cooper ih.ffactor = atoi(eq);
67657718be8SEnji Cooper return &ih;
67757718be8SEnji Cooper }
67857718be8SEnji Cooper if (!strcmp("nelem", s)) {
67957718be8SEnji Cooper ih.nelem = atoi(eq);
68057718be8SEnji Cooper return &ih;
68157718be8SEnji Cooper }
68257718be8SEnji Cooper if (!strcmp("cachesize", s)) {
68357718be8SEnji Cooper ih.cachesize = atoi(eq);
68457718be8SEnji Cooper return &ih;
68557718be8SEnji Cooper }
68657718be8SEnji Cooper if (!strcmp("lorder", s)) {
68757718be8SEnji Cooper ih.lorder = atoi(eq);
68857718be8SEnji Cooper return &ih;
68957718be8SEnji Cooper }
69057718be8SEnji Cooper break;
69157718be8SEnji Cooper case DB_RECNO:
69257718be8SEnji Cooper if (!strcmp("flags", s)) {
69357718be8SEnji Cooper rh.flags = atoi(eq);
69457718be8SEnji Cooper return &rh;
69557718be8SEnji Cooper }
69657718be8SEnji Cooper if (!strcmp("cachesize", s)) {
69757718be8SEnji Cooper rh.cachesize = atoi(eq);
69857718be8SEnji Cooper return &rh;
69957718be8SEnji Cooper }
70057718be8SEnji Cooper if (!strcmp("lorder", s)) {
70157718be8SEnji Cooper rh.lorder = atoi(eq);
70257718be8SEnji Cooper return &rh;
70357718be8SEnji Cooper }
70457718be8SEnji Cooper if (!strcmp("reclen", s)) {
70557718be8SEnji Cooper rh.reclen = atoi(eq);
70657718be8SEnji Cooper return &rh;
70757718be8SEnji Cooper }
70857718be8SEnji Cooper if (!strcmp("bval", s)) {
70957718be8SEnji Cooper rh.bval = atoi(eq);
71057718be8SEnji Cooper return &rh;
71157718be8SEnji Cooper }
71257718be8SEnji Cooper if (!strcmp("psize", s)) {
71357718be8SEnji Cooper rh.psize = atoi(eq);
71457718be8SEnji Cooper return &rh;
71557718be8SEnji Cooper }
71657718be8SEnji Cooper break;
71757718be8SEnji Cooper }
71857718be8SEnji Cooper errx(1, "%s: unknown structure value", s);
71957718be8SEnji Cooper /* NOTREACHED */
72057718be8SEnji Cooper }
72157718be8SEnji Cooper
72257718be8SEnji Cooper static void *
rfile(char * name,size_t * lenp)72357718be8SEnji Cooper rfile(char *name, size_t *lenp)
72457718be8SEnji Cooper {
72557718be8SEnji Cooper struct stat sb;
72657718be8SEnji Cooper void *p;
72757718be8SEnji Cooper int fd;
72857718be8SEnji Cooper char *np;
72957718be8SEnji Cooper
73057718be8SEnji Cooper for (; isspace((unsigned char)*name); ++name)
73157718be8SEnji Cooper continue;
73257718be8SEnji Cooper if ((np = strchr(name, '\n')) != NULL)
73357718be8SEnji Cooper *np = '\0';
73457718be8SEnji Cooper if ((fd = open(name, O_RDONLY, 0)) == -1 || fstat(fd, &sb) == -1)
73557718be8SEnji Cooper err(1, "Cannot open `%s'", name);
73657718be8SEnji Cooper #ifdef NOT_PORTABLE
73757718be8SEnji Cooper if (sb.st_size > (off_t)SIZE_T_MAX) {
73857718be8SEnji Cooper errno = E2BIG;
73957718be8SEnji Cooper err("Cannot process `%s'", name);
74057718be8SEnji Cooper }
74157718be8SEnji Cooper #endif
74257718be8SEnji Cooper if ((p = malloc((size_t)sb.st_size)) == NULL)
74357718be8SEnji Cooper err(1, "Cannot allocate %zu bytes", (size_t)sb.st_size);
74457718be8SEnji Cooper if (read(fd, p, (ssize_t)sb.st_size) != (ssize_t)sb.st_size)
74557718be8SEnji Cooper err(1, "read failed");
74657718be8SEnji Cooper *lenp = (size_t)sb.st_size;
74757718be8SEnji Cooper (void)close(fd);
74857718be8SEnji Cooper return p;
74957718be8SEnji Cooper }
75057718be8SEnji Cooper
75157718be8SEnji Cooper static void *
xcopy(void * text,size_t len)75257718be8SEnji Cooper xcopy(void *text, size_t len)
75357718be8SEnji Cooper {
75457718be8SEnji Cooper void *p;
75557718be8SEnji Cooper
75657718be8SEnji Cooper if ((p = malloc(len)) == NULL)
75757718be8SEnji Cooper err(1, "Cannot allocate %zu bytes", len);
75857718be8SEnji Cooper (void)memmove(p, text, len);
75957718be8SEnji Cooper return p;
76057718be8SEnji Cooper }
76157718be8SEnji Cooper
76257718be8SEnji Cooper static void
chkcmd(enum S state)76357718be8SEnji Cooper chkcmd(enum S state)
76457718be8SEnji Cooper {
76557718be8SEnji Cooper if (state != COMMAND)
76657718be8SEnji Cooper errx(1, "line %zu: not expecting command", lineno);
76757718be8SEnji Cooper }
76857718be8SEnji Cooper
76957718be8SEnji Cooper static void
chkdata(enum S state)77057718be8SEnji Cooper chkdata(enum S state)
77157718be8SEnji Cooper {
77257718be8SEnji Cooper if (state != DATA)
77357718be8SEnji Cooper errx(1, "line %zu: not expecting data", lineno);
77457718be8SEnji Cooper }
77557718be8SEnji Cooper
77657718be8SEnji Cooper static void
chkkey(enum S state)77757718be8SEnji Cooper chkkey(enum S state)
77857718be8SEnji Cooper {
77957718be8SEnji Cooper if (state != KEY)
78057718be8SEnji Cooper errx(1, "line %zu: not expecting a key", lineno);
78157718be8SEnji Cooper }
78257718be8SEnji Cooper
78357718be8SEnji Cooper static void
usage(void)78457718be8SEnji Cooper usage(void)
78557718be8SEnji Cooper {
78657718be8SEnji Cooper (void)fprintf(stderr,
787*cdebaff8SEnji Cooper #ifdef __NetBSD__
788*cdebaff8SEnji Cooper "Usage: %s [-lu] [-f file] [-i info] [-o file] [-O file] "
789*cdebaff8SEnji Cooper #else
790*cdebaff8SEnji Cooper "Usage: %s [-l] [-f file] [-i info] [-o file] "
791*cdebaff8SEnji Cooper #endif
792*cdebaff8SEnji Cooper "type script\n", getprogname());
79357718be8SEnji Cooper exit(1);
79457718be8SEnji Cooper }
795