h_db.c revision 313535
1118611Snjl/* $NetBSD: h_db.c,v 1.3 2016/09/24 21:18:22 christos Exp $ */ 2118611Snjl 3118611Snjl/*- 4118611Snjl * Copyright (c) 1992, 1993, 1994 5118611Snjl * The Regents of the University of California. All rights reserved. 6118611Snjl * 7217365Sjkim * Redistribution and use in source and binary forms, with or without 8245582Sjkim * modification, are permitted provided that the following conditions 9118611Snjl * are met: 10118611Snjl * 1. Redistributions of source code must retain the above copyright 11217365Sjkim * notice, this list of conditions and the following disclaimer. 12217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright 13217365Sjkim * notice, this list of conditions and the following disclaimer in the 14217365Sjkim * documentation and/or other materials provided with the distribution. 15217365Sjkim * 3. Neither the name of the University nor the names of its contributors 16217365Sjkim * may be used to endorse or promote products derived from this software 17217365Sjkim * without specific prior written permission. 18217365Sjkim * 19217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25118611Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29118611Snjl * SUCH DAMAGE. 30217365Sjkim */ 31217365Sjkim 32217365Sjkim#include <sys/cdefs.h> 33217365Sjkim#ifndef lint 34217365Sjkim__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\ 35217365Sjkim The Regents of the University of California. All rights reserved."); 36217365Sjkim#endif /* not lint */ 37217365Sjkim 38217365Sjkim#ifndef lint 39217365Sjkim#if 0 40217365Sjkimstatic char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94"; 41217365Sjkim#else 42217365Sjkim__RCSID("$NetBSD: h_db.c,v 1.3 2016/09/24 21:18:22 christos Exp $"); 43118611Snjl#endif 44118611Snjl#endif /* not lint */ 45118611Snjl 46151937Sjkim#include <sys/param.h> 47193529Sjkim#include <sys/stat.h> 48193529Sjkim 49193529Sjkim#include <ctype.h> 50118611Snjl#include <errno.h> 51118611Snjl#include <fcntl.h> 52118611Snjl#include <limits.h> 53118611Snjl#include <stdio.h> 54118611Snjl#include <stdlib.h> 55118611Snjl#include <string.h> 56151937Sjkim#include <stdbool.h> 57118611Snjl#include <unistd.h> 58151937Sjkim#include <err.h> 59151937Sjkim#include <db.h> 60151937Sjkim#include "btree.h" 61151937Sjkim 62151937Sjkimenum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA }; 63151937Sjkim 64151937Sjkimstatic void compare(DBT *, DBT *); 65151937Sjkimstatic DBTYPE dbtype(const char *); 66151937Sjkimstatic void dump(DB *, int, int); 67151937Sjkimstatic void get(DB *, DBT *); 68151937Sjkimstatic void getdata(DB *, DBT *, DBT *); 69151937Sjkimstatic void put(DB *, DBT *, DBT *); 70151937Sjkimstatic void rem(DB *, DBT *); 71151937Sjkimstatic const char *sflags(int); 72151937Sjkimstatic void synk(DB *); 73151937Sjkimstatic void *rfile(char *, size_t *); 74151937Sjkimstatic void seq(DB *, DBT *); 75193529Sjkimstatic u_int setflags(char *); 76151937Sjkimstatic void *setinfo(DBTYPE, char *); 77151937Sjkim#ifdef __NetBSD__ 78151937Sjkimstatic void unlinkpg(DB *); 79151937Sjkim#endif 80193529Sjkimstatic void usage(void) __attribute__((__noreturn__)); 81193529Sjkimstatic void *xcopy(void *, size_t); 82193529Sjkimstatic void chkcmd(enum S); 83193529Sjkimstatic void chkdata(enum S); 84193529Sjkimstatic void chkkey(enum S); 85151937Sjkim 86193529Sjkim#ifdef STATISTICS 87118611Snjlextern void __bt_stat(DB *); 88118611Snjl#endif 89118611Snjl#ifdef __NetBSD__ 90118611Snjlextern int __bt_relink(BTREE *, PAGE *); 91151937Sjkim#endif 92118611Snjl 93118611Snjlstatic DBTYPE type; /* Database type. */ 94118611Snjlstatic void *infop; /* Iflags. */ 95118611Snjlstatic size_t lineno; /* Current line in test script. */ 96193529Sjkimstatic u_int flags; /* Current DB flags. */ 97118611Snjlstatic int ofd = STDOUT_FILENO; /* Standard output fd. */ 98118611Snjl 99118611Snjlstatic DB *XXdbp; /* Global for gdb. */ 100118611Snjlstatic size_t XXlineno; /* Fast breakpoint for gdb. */ 101118611Snjl 102118611Snjlint 103118611Snjlmain(int argc, char *argv[]) 104118611Snjl{ 105118611Snjl extern int optind; 106118611Snjl extern char *optarg; 107118611Snjl enum S command = COMMAND, state; 108118611Snjl DB *dbp; 109118611Snjl DBT data, key, keydata; 110118611Snjl size_t len; 111118611Snjl int ch, oflags, sflag; 112118611Snjl char *fname, *infoarg, *p, *t, buf[8 * 1024]; 113118611Snjl bool unlink_dbfile; 114118611Snjl 115118611Snjl infoarg = NULL; 116241973Sjkim fname = NULL; 117118611Snjl unlink_dbfile = false; 118118611Snjl oflags = O_CREAT | O_RDWR; 119193529Sjkim sflag = 0; 120118611Snjl while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1) 121118611Snjl switch (ch) { 122193529Sjkim case 'f': 123118611Snjl fname = optarg; 124193529Sjkim break; 125193529Sjkim case 'i': 126193529Sjkim infoarg = optarg; 127193529Sjkim break; 128193529Sjkim case 'l': 129118611Snjl oflags |= DB_LOCK; 130118611Snjl break; 131118611Snjl case 'o': 132241973Sjkim if ((ofd = open(optarg, 133118611Snjl O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 134118611Snjl err(1, "Cannot create `%s'", optarg); 135118611Snjl break; 136118611Snjl case 's': 137118611Snjl sflag = 1; 138118611Snjl break; 139118611Snjl case '?': 140151937Sjkim default: 141118611Snjl usage(); 142118611Snjl } 143118611Snjl argc -= optind; 144118611Snjl argv += optind; 145118611Snjl 146118611Snjl if (argc != 2) 147118611Snjl usage(); 148118611Snjl 149118611Snjl /* Set the type. */ 150151937Sjkim type = dbtype(*argv++); 151118611Snjl 152118611Snjl /* Open the descriptor file. */ 153118611Snjl if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL) 154118611Snjl err(1, "Cannot reopen `%s'", *argv); 155118611Snjl 156118611Snjl /* Set up the db structure as necessary. */ 157118611Snjl if (infoarg == NULL) 158118611Snjl infop = NULL; 159118611Snjl else 160118611Snjl for (p = strtok(infoarg, ",\t "); p != NULL; 161118611Snjl p = strtok(0, ",\t ")) 162118611Snjl if (*p != '\0') 163118611Snjl infop = setinfo(type, p); 164118611Snjl 165118611Snjl /* 166118611Snjl * Open the DB. Delete any preexisting copy, you almost never 167118611Snjl * want it around, and it often screws up tests. 168118611Snjl */ 169118611Snjl if (fname == NULL) { 170118611Snjl const char *q = getenv("TMPDIR"); 171118611Snjl if (q == NULL) 172118611Snjl q = "/var/tmp"; 173118611Snjl (void)snprintf(buf, sizeof(buf), "%s/__dbtest", q); 174118611Snjl fname = buf; 175118611Snjl (void)unlink(buf); 176118611Snjl unlink_dbfile = true; 177118611Snjl } else if (!sflag) 178118611Snjl (void)unlink(fname); 179118611Snjl 180250838Sjkim if ((dbp = dbopen(fname, 181118611Snjl oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL) 182250838Sjkim err(1, "Cannot dbopen `%s'", fname); 183118611Snjl XXdbp = dbp; 184118611Snjl if (unlink_dbfile) 185118611Snjl (void)unlink(fname); 186118611Snjl 187118611Snjl state = COMMAND; 188118611Snjl for (lineno = 1; 189118611Snjl (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) { 190118611Snjl /* Delete the newline, displaying the key/data is easier. */ 191118611Snjl if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL) 192118611Snjl *t = '\0'; 193118611Snjl if ((len = strlen(buf)) == 0 || isspace((unsigned char)*p) || 194228110Sjkim *p == '#') 195118611Snjl continue; 196118611Snjl 197118611Snjl /* Convenient gdb break point. */ 198118611Snjl if (XXlineno == lineno) 199151937Sjkim XXlineno = 1; 200151937Sjkim switch (*p) { 201151937Sjkim case 'c': /* compare */ 202151937Sjkim chkcmd(state); 203151937Sjkim state = KEY; 204151937Sjkim command = COMPARE; 205151937Sjkim break; 206118611Snjl case 'e': /* echo */ 207118611Snjl chkcmd(state); 208118611Snjl /* Don't display the newline, if CR at EOL. */ 209118611Snjl if (p[len - 2] == '\r') 210151937Sjkim --len; 211151937Sjkim if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 || 212151937Sjkim write(ofd, "\n", 1) != 1) 213118611Snjl err(1, "write failed"); 214118611Snjl break; 215118611Snjl case 'g': /* get */ 216118611Snjl chkcmd(state); 217118611Snjl state = KEY; 218118611Snjl command = GET; 219151937Sjkim break; 220151937Sjkim case 'p': /* put */ 221118611Snjl chkcmd(state); 222118611Snjl state = KEY; 223118611Snjl command = PUT; 224118611Snjl break; 225151937Sjkim case 'r': /* remove */ 226118611Snjl chkcmd(state); 227118611Snjl if (flags == R_CURSOR) { 228118611Snjl rem(dbp, &key); 229228110Sjkim state = COMMAND; 230118611Snjl } else { 231118611Snjl state = KEY; 232228110Sjkim command = REMOVE; 233118611Snjl } 234118611Snjl break; 235118611Snjl case 'S': /* sync */ 236118611Snjl chkcmd(state); 237118611Snjl synk(dbp); 238118611Snjl state = COMMAND; 239118611Snjl break; 240118611Snjl case 's': /* seq */ 241151937Sjkim chkcmd(state); 242118611Snjl if (flags == R_CURSOR) { 243118611Snjl state = KEY; 244118611Snjl command = SEQ; 245118611Snjl } else 246118611Snjl seq(dbp, &key); 247118611Snjl break; 248118611Snjl case 'f': 249193529Sjkim flags = setflags(p + 1); 250118611Snjl break; 251118611Snjl case 'D': /* data file */ 252118611Snjl chkdata(state); 253118611Snjl data.data = rfile(p + 1, &data.size); 254118611Snjl goto ldata; 255151937Sjkim case 'd': /* data */ 256118611Snjl chkdata(state); 257118611Snjl data.data = xcopy(p + 1, len - 1); 258118611Snjl data.size = len - 1; 259118611Snjlldata: switch (command) { 260118611Snjl case COMPARE: 261118611Snjl compare(&keydata, &data); 262118611Snjl break; 263118611Snjl case PUT: 264118611Snjl put(dbp, &key, &data); 265118611Snjl break; 266151937Sjkim default: 267151937Sjkim errx(1, "line %zu: command doesn't take data", 268118611Snjl lineno); 269118611Snjl } 270151937Sjkim if (type != DB_RECNO) 271151937Sjkim free(key.data); 272151937Sjkim free(data.data); 273118611Snjl state = COMMAND; 274118611Snjl break; 275151937Sjkim case 'K': /* key file */ 276151937Sjkim chkkey(state); 277151937Sjkim if (type == DB_RECNO) 278151937Sjkim errx(1, "line %zu: 'K' not available for recno", 279151937Sjkim lineno); 280151937Sjkim key.data = rfile(p + 1, &key.size); 281151937Sjkim goto lkey; 282151937Sjkim case 'k': /* key */ 283118611Snjl chkkey(state); 284118611Snjl if (type == DB_RECNO) { 285118611Snjl static recno_t recno; 286167802Sjkim recno = atoi(p + 1); 287167802Sjkim key.data = &recno; 288197104Sjkim key.size = sizeof(recno); 289167802Sjkim } else { 290118611Snjl key.data = xcopy(p + 1, len - 1); 291118611Snjl key.size = len - 1; 292118611Snjl } 293118611Snjllkey: switch (command) { 294118611Snjl case COMPARE: 295118611Snjl getdata(dbp, &key, &keydata); 296118611Snjl state = DATA; 297118611Snjl break; 298118611Snjl case GET: 299118611Snjl get(dbp, &key); 300151937Sjkim if (type != DB_RECNO) 301151937Sjkim free(key.data); 302151937Sjkim state = COMMAND; 303151937Sjkim break; 304151937Sjkim case PUT: 305118611Snjl state = DATA; 306118611Snjl break; 307118611Snjl case REMOVE: 308118611Snjl rem(dbp, &key); 309118611Snjl if ((type != DB_RECNO) && (flags != R_CURSOR)) 310118611Snjl free(key.data); 311228110Sjkim state = COMMAND; 312228110Sjkim break; 313118611Snjl case SEQ: 314228110Sjkim seq(dbp, &key); 315228110Sjkim if ((type != DB_RECNO) && (flags != R_CURSOR)) 316118611Snjl free(key.data); 317151937Sjkim state = COMMAND; 318228110Sjkim break; 319118611Snjl default: 320118611Snjl errx(1, "line %zu: command doesn't take a key", 321118611Snjl lineno); 322118611Snjl } 323118611Snjl break; 324118611Snjl case 'o': 325118611Snjl dump(dbp, p[1] == 'r', 0); 326118611Snjl break; 327118611Snjl#ifdef __NetBSD__ 328118611Snjl case 'O': 329118611Snjl dump(dbp, p[1] == 'r', 1); 330118611Snjl break; 331118611Snjl case 'u': 332118611Snjl unlinkpg(dbp); 333118611Snjl break; 334118611Snjl#endif 335193529Sjkim default: 336118611Snjl errx(1, "line %zu: %s: unknown command character", 337118611Snjl lineno, p); 338118611Snjl } 339118611Snjl } 340151937Sjkim#ifdef STATISTICS 341118611Snjl /* 342118611Snjl * -l must be used (DB_LOCK must be set) for this to be 343118611Snjl * used, otherwise a page will be locked and it will fail. 344118611Snjl */ 345118611Snjl if (type == DB_BTREE && oflags & DB_LOCK) 346118611Snjl __bt_stat(dbp); 347118611Snjl#endif 348118611Snjl if ((*dbp->close)(dbp)) 349118611Snjl err(1, "db->close failed"); 350118611Snjl (void)close(ofd); 351118611Snjl return 0; 352118611Snjl} 353118611Snjl 354118611Snjl#define NOOVERWRITE "put failed, would overwrite key\n" 355167802Sjkim 356118611Snjlstatic void 357118611Snjlcompare(DBT *db1, DBT *db2) 358167802Sjkim{ 359118611Snjl size_t len; 360118611Snjl u_char *p1, *p2; 361118611Snjl 362118611Snjl if (db1->size != db2->size) 363118611Snjl printf("compare failed: key->data len %zu != data len %zu\n", 364118611Snjl db1->size, db2->size); 365118611Snjl 366118611Snjl len = MIN(db1->size, db2->size); 367118611Snjl for (p1 = db1->data, p2 = db2->data; len--;) 368118611Snjl if (*p1++ != *p2++) { 369118611Snjl printf("compare failed at offset %lu\n", 370118611Snjl (unsigned long)(p1 - (u_char *)db1->data)); 371118611Snjl break; 372118611Snjl } 373118611Snjl} 374118611Snjl 375118611Snjlstatic void 376118611Snjlget(DB *dbp, DBT *kp) 377118611Snjl{ 378118611Snjl DBT data; 379250838Sjkim 380118611Snjl switch ((*dbp->get)(dbp, kp, &data, flags)) { 381118611Snjl case 0: 382118611Snjl (void)write(ofd, data.data, data.size); 383118611Snjl if (ofd == STDOUT_FILENO) 384118611Snjl (void)write(ofd, "\n", 1); 385118611Snjl break; 386118611Snjl case -1: 387118611Snjl err(1, "line %zu: get failed", lineno); 388118611Snjl /* NOTREACHED */ 389118611Snjl case 1: 390118611Snjl#define NOSUCHKEY "get failed, no such key\n" 391118611Snjl if (ofd != STDOUT_FILENO) 392118611Snjl (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 393118611Snjl else 394118611Snjl (void)fprintf(stderr, "%zu: %.*s: %s", 395118611Snjl lineno, (int)MIN(kp->size, 20), 396118611Snjl (const char *)kp->data, 397118611Snjl NOSUCHKEY); 398118611Snjl#undef NOSUCHKEY 399118611Snjl break; 400118611Snjl } 401118611Snjl} 402151937Sjkim 403151937Sjkimstatic void 404118611Snjlgetdata(DB *dbp, DBT *kp, DBT *dp) 405167802Sjkim{ 406167802Sjkim switch ((*dbp->get)(dbp, kp, dp, flags)) { 407167802Sjkim case 0: 408167802Sjkim return; 409167802Sjkim case -1: 410167802Sjkim err(1, "line %zu: getdata failed", lineno); 411167802Sjkim /* NOTREACHED */ 412167802Sjkim case 1: 413167802Sjkim errx(1, "line %zu: getdata failed, no such key", lineno); 414167802Sjkim /* NOTREACHED */ 415118611Snjl } 416118611Snjl} 417118611Snjl 418118611Snjlstatic void 419118611Snjlput(DB *dbp, DBT *kp, DBT *dp) 420118611Snjl{ 421118611Snjl switch ((*dbp->put)(dbp, kp, dp, flags)) { 422118611Snjl case 0: 423118611Snjl break; 424118611Snjl case -1: 425118611Snjl err(1, "line %zu: put failed", lineno); 426118611Snjl /* NOTREACHED */ 427118611Snjl case 1: 428118611Snjl (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1); 429118611Snjl break; 430118611Snjl } 431118611Snjl} 432118611Snjl 433118611Snjlstatic void 434118611Snjlrem(DB *dbp, DBT *kp) 435118611Snjl{ 436118611Snjl switch ((*dbp->del)(dbp, kp, flags)) { 437167802Sjkim case 0: 438167802Sjkim break; 439167802Sjkim case -1: 440167802Sjkim err(1, "line %zu: rem failed", lineno); 441167802Sjkim /* NOTREACHED */ 442167802Sjkim case 1: 443167802Sjkim#define NOSUCHKEY "rem failed, no such key\n" 444167802Sjkim if (ofd != STDOUT_FILENO) 445167802Sjkim (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 446167802Sjkim else if (flags != R_CURSOR) 447167802Sjkim (void)fprintf(stderr, "%zu: %.*s: %s", 448167802Sjkim lineno, (int)MIN(kp->size, 20), 449167802Sjkim (const char *)kp->data, NOSUCHKEY); 450167802Sjkim else 451167802Sjkim (void)fprintf(stderr, 452167802Sjkim "%zu: rem of cursor failed\n", lineno); 453167802Sjkim#undef NOSUCHKEY 454167802Sjkim break; 455167802Sjkim } 456118611Snjl} 457118611Snjl 458118611Snjlstatic void 459118611Snjlsynk(DB *dbp) 460167802Sjkim{ 461118611Snjl switch ((*dbp->sync)(dbp, flags)) { 462118611Snjl case 0: 463202771Sjkim break; 464118611Snjl case -1: 465118611Snjl err(1, "line %zu: synk failed", lineno); 466118611Snjl /* NOTREACHED */ 467118611Snjl } 468118611Snjl} 469118611Snjl 470118611Snjlstatic void 471118611Snjlseq(DB *dbp, DBT *kp) 472118611Snjl{ 473118611Snjl DBT data; 474118611Snjl 475193529Sjkim switch (dbp->seq(dbp, kp, &data, flags)) { 476118611Snjl case 0: 477118611Snjl (void)write(ofd, data.data, data.size); 478151937Sjkim if (ofd == STDOUT_FILENO) 479151937Sjkim (void)write(ofd, "\n", 1); 480118611Snjl break; 481118611Snjl case -1: 482118611Snjl err(1, "line %zu: seq failed", lineno); 483118611Snjl /* NOTREACHED */ 484118611Snjl case 1: 485118611Snjl#define NOSUCHKEY "seq failed, no such key\n" 486151937Sjkim if (ofd != STDOUT_FILENO) 487151937Sjkim (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1); 488151937Sjkim else if (flags == R_CURSOR) 489151937Sjkim (void)fprintf(stderr, "%zu: %.*s: %s", 490254745Sjkim lineno, (int)MIN(kp->size, 20), 491254745Sjkim (const char *)kp->data, NOSUCHKEY); 492254745Sjkim else 493254745Sjkim (void)fprintf(stderr, 494118611Snjl "%zu: seq (%s) failed\n", lineno, sflags(flags)); 495118611Snjl#undef NOSUCHKEY 496118611Snjl break; 497118611Snjl } 498118611Snjl} 499118611Snjl 500151937Sjkimstatic void 501151937Sjkimdump(DB *dbp, int rev, int recurse) 502151937Sjkim{ 503151937Sjkim DBT key, data; 504118611Snjl int xflags, nflags; 505118611Snjl 506118611Snjl if (rev) { 507198237Sjkim xflags = R_LAST; 508198237Sjkim#ifdef __NetBSD__ 509198237Sjkim nflags = recurse ? R_RPREV : R_PREV; 510202771Sjkim#else 511118611Snjl nflags = R_PREV; 512118611Snjl#endif 513118611Snjl } else { 514118611Snjl xflags = R_FIRST; 515118611Snjl#ifdef __NetBSD__ 516118611Snjl nflags = recurse ? R_RNEXT : R_NEXT; 517118611Snjl#else 518118611Snjl nflags = R_NEXT; 519118611Snjl#endif 520118611Snjl } 521118611Snjl for (;; xflags = nflags) 522118611Snjl switch (dbp->seq(dbp, &key, &data, xflags)) { 523118611Snjl case 0: 524118611Snjl (void)write(ofd, data.data, data.size); 525118611Snjl if (ofd == STDOUT_FILENO) 526118611Snjl (void)write(ofd, "\n", 1); 527118611Snjl break; 528118611Snjl case 1: 529118611Snjl goto done; 530151937Sjkim case -1: 531151937Sjkim err(1, "line %zu: (dump) seq failed", lineno); 532118611Snjl /* NOTREACHED */ 533118611Snjl } 534118611Snjldone: return; 535118611Snjl} 536118611Snjl 537118611Snjl#ifdef __NetBSD__ 538118611Snjlvoid 539128212Snjlunlinkpg(DB *dbp) 540118611Snjl{ 541118611Snjl BTREE *t = dbp->internal; 542118611Snjl PAGE *h = NULL; 543151937Sjkim pgno_t pg; 544151937Sjkim 545128212Snjl for (pg = P_ROOT; pg < t->bt_mp->npages; 546151937Sjkim mpool_put(t->bt_mp, h, 0), pg++) { 547151937Sjkim if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) 548128212Snjl break; 549128212Snjl /* Look for a nonempty leaf page that has both left 550128212Snjl * and right siblings. */ 551128212Snjl if (h->prevpg == P_INVALID || h->nextpg == P_INVALID) 552118611Snjl continue; 553118611Snjl if (NEXTINDEX(h) == 0) 554118611Snjl continue; 555118611Snjl if ((h->flags & (P_BLEAF | P_RLEAF))) 556151937Sjkim break; 557151937Sjkim } 558151937Sjkim if (h == NULL || pg == t->bt_mp->npages) { 559151937Sjkim errx(1, "%s: no appropriate page found", __func__); 560118611Snjl return; 561118611Snjl } 562118611Snjl if (__bt_relink(t, h) != 0) { 563118611Snjl perror("unlinkpg"); 564118611Snjl goto cleanup; 565193529Sjkim } 566118611Snjl h->prevpg = P_INVALID; 567128212Snjl h->nextpg = P_INVALID; 568151937Sjkimcleanup: 569151937Sjkim mpool_put(t->bt_mp, h, MPOOL_DIRTY); 570128212Snjl} 571128212Snjl#endif 572128212Snjl 573128212Snjlstatic u_int 574118611Snjlsetflags(char *s) 575118611Snjl{ 576118611Snjl char *p; 577118611Snjl 578118611Snjl for (; isspace((unsigned char)*s); ++s); 579118611Snjl if (*s == '\n' || *s == '\0') 580118611Snjl return 0; 581118611Snjl if ((p = strchr(s, '\n')) != NULL) 582118611Snjl *p = '\0'; 583118611Snjl if (!strcmp(s, "R_CURSOR")) return R_CURSOR; 584118611Snjl if (!strcmp(s, "R_FIRST")) return R_FIRST; 585118611Snjl if (!strcmp(s, "R_IAFTER")) return R_IAFTER; 586118611Snjl if (!strcmp(s, "R_IBEFORE")) return R_IBEFORE; 587118611Snjl if (!strcmp(s, "R_LAST")) return R_LAST; 588118611Snjl if (!strcmp(s, "R_NEXT")) return R_NEXT; 589118611Snjl if (!strcmp(s, "R_NOOVERWRITE")) return R_NOOVERWRITE; 590118611Snjl if (!strcmp(s, "R_PREV")) return R_PREV; 591118611Snjl if (!strcmp(s, "R_SETCURSOR")) return R_SETCURSOR; 592118611Snjl 593118611Snjl errx(1, "line %zu: %s: unknown flag", lineno, s); 594118611Snjl /* NOTREACHED */ 595118611Snjl} 596193529Sjkim 597193529Sjkimstatic const char * 598151937Sjkimsflags(int xflags) 599151937Sjkim{ 600118611Snjl switch (xflags) { 601118611Snjl case R_CURSOR: return "R_CURSOR"; 602167802Sjkim case R_FIRST: return "R_FIRST"; 603118611Snjl case R_IAFTER: return "R_IAFTER"; 604118611Snjl case R_IBEFORE: return "R_IBEFORE"; 605118611Snjl case R_LAST: return "R_LAST"; 606118611Snjl case R_NEXT: return "R_NEXT"; 607118611Snjl case R_NOOVERWRITE: return "R_NOOVERWRITE"; 608118611Snjl case R_PREV: return "R_PREV"; 609118611Snjl case R_SETCURSOR: return "R_SETCURSOR"; 610118611Snjl } 611167802Sjkim 612167802Sjkim return "UNKNOWN!"; 613118611Snjl} 614118611Snjl 615118611Snjlstatic DBTYPE 616193529Sjkimdbtype(const char *s) 617193529Sjkim{ 618167802Sjkim if (!strcmp(s, "btree")) 619167802Sjkim return DB_BTREE; 620167802Sjkim if (!strcmp(s, "hash")) 621167802Sjkim return DB_HASH; 622167802Sjkim if (!strcmp(s, "recno")) 623167802Sjkim return DB_RECNO; 624167802Sjkim errx(1, "%s: unknown type (use btree, hash or recno)", s); 625167802Sjkim /* NOTREACHED */ 626167802Sjkim} 627167802Sjkim 628167802Sjkimstatic void * 629167802Sjkimsetinfo(DBTYPE dtype, char *s) 630167802Sjkim{ 631167802Sjkim static BTREEINFO ib; 632167802Sjkim static HASHINFO ih; 633167802Sjkim static RECNOINFO rh; 634167802Sjkim char *eq; 635167802Sjkim 636167802Sjkim if ((eq = strchr(s, '=')) == NULL) 637167802Sjkim errx(1, "%s: illegal structure set statement", s); 638118611Snjl *eq++ = '\0'; 639118611Snjl if (!isdigit((unsigned char)*eq)) 640167802Sjkim errx(1, "%s: structure set statement must be a number", s); 641167802Sjkim 642151937Sjkim switch (dtype) { 643151937Sjkim case DB_BTREE: 644202771Sjkim if (!strcmp("flags", s)) { 645118611Snjl ib.flags = atoi(eq); 646118611Snjl return &ib; 647118611Snjl } 648118611Snjl if (!strcmp("cachesize", s)) { 649151937Sjkim ib.cachesize = atoi(eq); 650198237Sjkim return &ib; 651202771Sjkim } 652118611Snjl if (!strcmp("maxkeypage", s)) { 653118611Snjl ib.maxkeypage = atoi(eq); 654118611Snjl return &ib; 655167802Sjkim } 656167802Sjkim if (!strcmp("minkeypage", s)) { 657167802Sjkim ib.minkeypage = atoi(eq); 658167802Sjkim return &ib; 659167802Sjkim } 660167802Sjkim if (!strcmp("lorder", s)) { 661167802Sjkim ib.lorder = atoi(eq); 662167802Sjkim return &ib; 663118611Snjl } 664118611Snjl if (!strcmp("psize", s)) { 665118611Snjl ib.psize = atoi(eq); 666118611Snjl return &ib; 667118611Snjl } 668118611Snjl break; 669118611Snjl case DB_HASH: 670151937Sjkim if (!strcmp("bsize", s)) { 671118611Snjl ih.bsize = atoi(eq); 672118611Snjl return &ih; 673118611Snjl } 674118611Snjl if (!strcmp("ffactor", s)) { 675118611Snjl ih.ffactor = atoi(eq); 676118611Snjl return &ih; 677151937Sjkim } 678118611Snjl if (!strcmp("nelem", s)) { 679118611Snjl ih.nelem = atoi(eq); 680118611Snjl return &ih; 681118611Snjl } 682118611Snjl if (!strcmp("cachesize", s)) { 683151937Sjkim ih.cachesize = atoi(eq); 684151937Sjkim return &ih; 685118611Snjl } 686151937Sjkim if (!strcmp("lorder", s)) { 687118611Snjl ih.lorder = atoi(eq); 688118611Snjl return &ih; 689202771Sjkim } 690118611Snjl break; 691118611Snjl case DB_RECNO: 692118611Snjl if (!strcmp("flags", s)) { 693118611Snjl rh.flags = atoi(eq); 694118611Snjl return &rh; 695193529Sjkim } 696118611Snjl if (!strcmp("cachesize", s)) { 697118611Snjl rh.cachesize = atoi(eq); 698118611Snjl return &rh; 699118611Snjl } 700118611Snjl if (!strcmp("lorder", s)) { 701193529Sjkim rh.lorder = atoi(eq); 702193529Sjkim return &rh; 703193529Sjkim } 704193529Sjkim if (!strcmp("reclen", s)) { 705193529Sjkim rh.reclen = atoi(eq); 706193529Sjkim return &rh; 707193529Sjkim } 708193529Sjkim if (!strcmp("bval", s)) { 709193529Sjkim rh.bval = atoi(eq); 710193529Sjkim return &rh; 711193529Sjkim } 712193529Sjkim if (!strcmp("psize", s)) { 713193529Sjkim rh.psize = atoi(eq); 714193529Sjkim return &rh; 715193529Sjkim } 716193529Sjkim break; 717193529Sjkim } 718193529Sjkim errx(1, "%s: unknown structure value", s); 719193529Sjkim /* NOTREACHED */ 720193529Sjkim} 721193529Sjkim 722193529Sjkimstatic void * 723193529Sjkimrfile(char *name, size_t *lenp) 724193529Sjkim{ 725193529Sjkim struct stat sb; 726193529Sjkim void *p; 727193529Sjkim int fd; 728193529Sjkim char *np; 729193529Sjkim 730193529Sjkim for (; isspace((unsigned char)*name); ++name) 731193529Sjkim continue; 732193529Sjkim if ((np = strchr(name, '\n')) != NULL) 733193529Sjkim *np = '\0'; 734193529Sjkim if ((fd = open(name, O_RDONLY, 0)) == -1 || fstat(fd, &sb) == -1) 735193529Sjkim err(1, "Cannot open `%s'", name); 736193529Sjkim#ifdef NOT_PORTABLE 737193529Sjkim if (sb.st_size > (off_t)SIZE_T_MAX) { 738193529Sjkim errno = E2BIG; 739193529Sjkim err("Cannot process `%s'", name); 740193529Sjkim } 741193529Sjkim#endif 742193529Sjkim if ((p = malloc((size_t)sb.st_size)) == NULL) 743193529Sjkim err(1, "Cannot allocate %zu bytes", (size_t)sb.st_size); 744193529Sjkim if (read(fd, p, (ssize_t)sb.st_size) != (ssize_t)sb.st_size) 745193529Sjkim err(1, "read failed"); 746193529Sjkim *lenp = (size_t)sb.st_size; 747193529Sjkim (void)close(fd); 748193529Sjkim return p; 749193529Sjkim} 750193529Sjkim 751193529Sjkimstatic void * 752193529Sjkimxcopy(void *text, size_t len) 753193529Sjkim{ 754193529Sjkim void *p; 755193529Sjkim 756193529Sjkim if ((p = malloc(len)) == NULL) 757193529Sjkim err(1, "Cannot allocate %zu bytes", len); 758193529Sjkim (void)memmove(p, text, len); 759193529Sjkim return p; 760193529Sjkim} 761193529Sjkim 762193529Sjkimstatic void 763193529Sjkimchkcmd(enum S state) 764193529Sjkim{ 765193529Sjkim if (state != COMMAND) 766193529Sjkim errx(1, "line %zu: not expecting command", lineno); 767193529Sjkim} 768193529Sjkim 769193529Sjkimstatic void 770193529Sjkimchkdata(enum S state) 771193529Sjkim{ 772193529Sjkim if (state != DATA) 773193529Sjkim errx(1, "line %zu: not expecting data", lineno); 774193529Sjkim} 775193529Sjkim 776193529Sjkimstatic void 777193529Sjkimchkkey(enum S state) 778193529Sjkim{ 779193529Sjkim if (state != KEY) 780193529Sjkim errx(1, "line %zu: not expecting a key", lineno); 781193529Sjkim} 782193529Sjkim 783193529Sjkimstatic void 784193529Sjkimusage(void) 785193529Sjkim{ 786193529Sjkim (void)fprintf(stderr, 787193529Sjkim#ifdef __NetBSD__ 788193529Sjkim "Usage: %s [-lu] [-f file] [-i info] [-o file] [-O file] " 789193529Sjkim#else 790193529Sjkim "Usage: %s [-l] [-f file] [-i info] [-o file] " 791193529Sjkim#endif 792193529Sjkim "type script\n", getprogname()); 793193529Sjkim exit(1); 794193529Sjkim} 795193529Sjkim