Path: blob/main/crypto/krb5/src/plugins/kdb/db2/libdb2/test/dbtest.c
34927 views
/*-1* Copyright (c) 1992, 1993, 19942* The Regents of the University of California. All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. All advertising materials mentioning features or use of this software13* must display the following acknowledgement:14* This product includes software developed by the University of15* California, Berkeley and its contributors.16* 4. Neither the name of the University nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/32/*33* Copyright (C) 2016 by the Massachusetts Institute of Technology.34* All rights reserved.35*36* Redistribution and use in source and binary forms, with or without37* modification, are permitted provided that the following conditions38* are met:39*40* * Redistributions of source code must retain the above copyright41* notice, this list of conditions and the following disclaimer.42*43* * Redistributions in binary form must reproduce the above copyright44* notice, this list of conditions and the following disclaimer in45* the documentation and/or other materials provided with the46* distribution.47*48* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS49* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT50* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS51* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE52* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,53* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES54* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR55* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)56* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,57* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)58* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED59* OF THE POSSIBILITY OF SUCH DAMAGE.60*/6162#if !defined(lint) && defined(LIBC_SCCS)63static char copyright[] =64"@(#) Copyright (c) 1992, 1993, 1994\n\65The Regents of the University of California. All rights reserved.\n";66#endif /* not lint */6768#if !defined(lint) && defined(LIBC_SCCS)69static char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";70#endif /* not lint */7172#include <sys/param.h>73#include <sys/stat.h>7475#include <ctype.h>76#include <errno.h>77#include <fcntl.h>78#include <limits.h>79#include <stdio.h>80#include <stdlib.h>81#include <string.h>82#include <unistd.h>8384#include "db-int.h"85#include "btree.h"8687enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };8889#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)90#define ATTR(x) __attribute__(x)91#else92#define ATTR(x)93#endif9495void compare __P((DBT *, DBT *));96DBTYPE dbtype __P((char *));97void dump __P((DB *, int, int));98void err __P((const char *, ...)) ATTR ((__format__(__printf__,1,2))) ATTR ((__noreturn__));99void get __P((DB *, DBT *));100void getdata __P((DB *, DBT *, DBT *));101void put __P((DB *, DBT *, DBT *));102void rem __P((DB *, DBT *));103char *sflags __P((int));104void synk __P((DB *));105void *rfile __P((char *, size_t *));106void seq __P((DB *, DBT *));107u_int setflags __P((char *));108void *setinfo __P((DBTYPE, char *));109void unlinkpg __P((DB *));110void usage __P((void));111void *xmalloc __P((char *, size_t));112113DBTYPE type; /* Database type. */114void *infop; /* Iflags. */115u_long lineno; /* Current line in test script. */116u_int flags; /* Current DB flags. */117int ofd = STDOUT_FILENO; /* Standard output fd. */118119DB *XXdbp; /* Global for gdb. */120u_long XXlineno; /* Fast breakpoint for gdb. */121122int123main(int argc, char *argv[])124{125extern int optind;126extern char *optarg;127enum S command = COMMAND, state;128DB *dbp;129DBT data, key, keydata;130size_t len;131int ch, oflags, sflag;132char *fname, *infoarg, *p, *t, buf[8 * 1024];133134infoarg = NULL;135fname = NULL;136oflags = O_CREAT | O_RDWR | O_BINARY;137sflag = 0;138while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)139switch (ch) {140case 'f':141fname = optarg;142break;143case 'i':144infoarg = optarg;145break;146case 'l':147oflags |= DB_LOCK;148break;149case 'o':150if ((ofd = open(optarg,151O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)152err("%s: %s", optarg, strerror(errno));153break;154case 's':155sflag = 1;156break;157case '?':158default:159usage();160}161argc -= optind;162argv += optind;163164if (argc != 2)165usage();166167/* Set the type. */168type = dbtype(*argv++);169170/* Open the descriptor file. */171if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)172err("%s: %s", *argv, strerror(errno));173174/* Set up the db structure as necessary. */175if (infoarg == NULL)176infop = NULL;177else178for (p = strtok(infoarg, ",\t "); p != NULL;179p = strtok(0, ",\t "))180if (*p != '\0')181infop = setinfo(type, p);182183/*184* Open the DB. Delete any preexisting copy, you almost never185* want it around, and it often screws up tests.186*/187if (fname == NULL) {188p = getenv("TMPDIR");189if (p == NULL)190p = "/var/tmp";191(void)snprintf(buf, sizeof(buf), "%s/__dbtest", p);192fname = buf;193(void)unlink(buf);194} else if (!sflag)195(void)unlink(fname);196197if ((dbp = dbopen(fname,198oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)199err("dbopen: %s", strerror(errno));200XXdbp = dbp;201202state = COMMAND;203for (lineno = 1;204(p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {205/* Delete the newline, displaying the key/data is easier. */206if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)207*t = '\0';208if ((len = strlen(buf)) == 0 || isspace((int) *p) || *p == '#')209continue;210211/* Convenient gdb break point. */212if (XXlineno == lineno)213XXlineno = 1;214switch (*p) {215case 'c': /* compare */216if (state != COMMAND)217err("line %lu: not expecting command", lineno);218state = KEY;219command = COMPARE;220break;221case 'e': /* echo */222if (state != COMMAND)223err("line %lu: not expecting command", lineno);224/* Don't display the newline, if CR at EOL. */225if (p[len - 2] == '\r')226--len;227if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 ||228write(ofd, "\n", 1) != 1)229err("write: %s", strerror(errno));230break;231case 'g': /* get */232if (state != COMMAND)233err("line %lu: not expecting command", lineno);234state = KEY;235command = GET;236break;237case 'p': /* put */238if (state != COMMAND)239err("line %lu: not expecting command", lineno);240state = KEY;241command = PUT;242break;243case 'r': /* remove */244if (state != COMMAND)245err("line %lu: not expecting command", lineno);246if (flags == R_CURSOR) {247rem(dbp, &key);248state = COMMAND;249} else {250state = KEY;251command = REMOVE;252}253break;254case 'S': /* sync */255if (state != COMMAND)256err("line %lu: not expecting command", lineno);257synk(dbp);258state = COMMAND;259break;260case 's': /* seq */261if (state != COMMAND)262err("line %lu: not expecting command", lineno);263if (flags == R_CURSOR) {264state = KEY;265command = SEQ;266} else267seq(dbp, &key);268break;269case 'f':270flags = setflags(p + 1);271break;272case 'D': /* data file */273if (state != DATA)274err("line %lu: not expecting data", lineno);275data.data = rfile(p + 1, &data.size);276goto ldata;277case 'd': /* data */278if (state != DATA)279err("line %lu: not expecting data", lineno);280data.data = xmalloc(p + 1, len - 1);281data.size = len - 1;282ldata: switch (command) {283case COMPARE:284compare(&keydata, &data);285break;286case PUT:287put(dbp, &key, &data);288break;289default:290err("line %lu: command doesn't take data",291lineno);292}293if (type != DB_RECNO)294free(key.data);295free(data.data);296state = COMMAND;297break;298case 'K': /* key file */299if (state != KEY)300err("line %lu: not expecting a key", lineno);301if (type == DB_RECNO)302err("line %lu: 'K' not available for recno",303lineno);304key.data = rfile(p + 1, &key.size);305goto lkey;306case 'k': /* key */307if (state != KEY)308err("line %lu: not expecting a key", lineno);309if (type == DB_RECNO) {310static recno_t recno;311recno = atoi(p + 1);312key.data = &recno;313key.size = sizeof(recno);314} else {315key.data = xmalloc(p + 1, len - 1);316key.size = len - 1;317}318lkey: switch (command) {319case COMPARE:320getdata(dbp, &key, &keydata);321state = DATA;322break;323case GET:324get(dbp, &key);325if (type != DB_RECNO)326free(key.data);327state = COMMAND;328break;329case PUT:330state = DATA;331break;332case REMOVE:333rem(dbp, &key);334if ((type != DB_RECNO) && (flags != R_CURSOR))335free(key.data);336state = COMMAND;337break;338case SEQ:339seq(dbp, &key);340if ((type != DB_RECNO) && (flags != R_CURSOR))341free(key.data);342state = COMMAND;343break;344default:345err("line %lu: command doesn't take a key",346lineno);347}348break;349case 'o':350dump(dbp, p[1] == 'r', 0);351break;352case 'O':353dump(dbp, p[1] == 'r', 1);354break;355case 'u':356unlinkpg(dbp);357break;358default:359err("line %lu: %s: unknown command character",360lineno, p);361}362}363#ifdef STATISTICS364/*365* -l must be used (DB_LOCK must be set) for this to be366* used, otherwise a page will be locked and it will fail.367*/368if (type == DB_BTREE && oflags & DB_LOCK)369__bt_stat(dbp);370#endif371if (dbp->close(dbp))372err("db->close: %s", strerror(errno));373(void)close(ofd);374exit(0);375}376377#define NOOVERWRITE "put failed, would overwrite key\n"378379void380compare(DBT *db1, DBT *db2)381{382size_t len;383u_char *p1, *p2;384385if (db1->size != db2->size) {386printf("compare failed: key->data len %lu != data len %lu\n",387(u_long) db1->size, (u_long) db2->size);388exit (1);389}390391len = MIN(db1->size, db2->size);392for (p1 = db1->data, p2 = db2->data; len--;)393if (*p1++ != *p2++) {394err("compare failed at offset %d\n",395(int)(p1 - (u_char *)db1->data));396break;397}398}399400void401get(DB *dbp, DBT *kp)402{403DBT data;404405switch (dbp->get(dbp, kp, &data, flags)) {406case 0:407if (write(ofd, data.data, data.size) != (ssize_t)data.size)408err("write: %s", strerror(errno));409if (ofd == STDOUT_FILENO) {410if (write(ofd, "\n", 1) != 1)411err("write: %s", strerror(errno));412}413break;414case -1:415err("line %lu: get: %s", lineno, strerror(errno));416/* NOTREACHED */417case 1:418#define NOSUCHKEY "get failed, no such key\n"419if (ofd != STDOUT_FILENO) {420if (write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1) !=421sizeof(NOSUCHKEY) - 1)422err("write: %s", strerror(errno));423exit(1);424} else425(void)fprintf(stderr, "%lu: %.*s: %s",426lineno, (int) MIN(kp->size, 20), (char *) kp->data,427NOSUCHKEY);428#undef NOSUCHKEY429break;430}431}432433void434getdata(DB *dbp, DBT *kp, DBT *dp)435{436switch (dbp->get(dbp, kp, dp, flags)) {437case 0:438return;439case -1:440err("line %lu: getdata: %s", lineno, strerror(errno));441/* NOTREACHED */442case 1:443err("line %lu: getdata failed, no such key", lineno);444/* NOTREACHED */445}446}447448void449put(DB *dbp, DBT *kp, DBT *dp)450{451switch (dbp->put(dbp, kp, dp, flags)) {452case 0:453break;454case -1:455err("line %lu: put: %s", lineno, strerror(errno));456/* NOTREACHED */457case 1:458if (write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1) !=459sizeof(NOOVERWRITE) - 1)460err("write: %s", strerror(errno));461break;462}463}464465void466rem(DB *dbp, DBT *kp)467{468switch (dbp->del(dbp, kp, flags)) {469case 0:470break;471case -1:472err("line %lu: rem: %s", lineno, strerror(errno));473/* NOTREACHED */474case 1:475#define NOSUCHKEY "rem failed, no such key\n"476if (ofd != STDOUT_FILENO) {477if (write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1) !=478sizeof(NOSUCHKEY) - 1)479err("write: %s", strerror(errno));480} else if (flags != R_CURSOR)481(void)fprintf(stderr, "%lu: %.*s: %s",482lineno, (int) MIN(kp->size, 20), (char *) kp->data,483NOSUCHKEY);484else485(void)fprintf(stderr,486"%lu: rem of cursor failed\n", lineno);487#undef NOSUCHKEY488break;489}490}491492void493synk(DB *dbp)494{495switch (dbp->sync(dbp, flags)) {496case 0:497break;498case -1:499err("line %lu: synk: %s", lineno, strerror(errno));500/* NOTREACHED */501}502}503504void505seq(DB *dbp, DBT *kp)506{507DBT data;508509switch (dbp->seq(dbp, kp, &data, flags)) {510case 0:511if (write(ofd, data.data, data.size) != (ssize_t)data.size)512err("write: %s", strerror(errno));513if (ofd == STDOUT_FILENO)514if (write(ofd, "\n", 1) != 1)515err("write: %s", strerror(errno));516break;517case -1:518err("line %lu: seq: %s", lineno, strerror(errno));519/* NOTREACHED */520case 1:521#define NOSUCHKEY "seq failed, no such key\n"522if (ofd != STDOUT_FILENO) {523if (write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1) !=524sizeof(NOSUCHKEY) - 1)525err("write: %s", strerror(errno));526} else if (flags == R_CURSOR)527(void)fprintf(stderr, "%lu: %.*s: %s",528lineno, (int) MIN(kp->size, 20), (char *) kp->data,529NOSUCHKEY);530else531(void)fprintf(stderr,532"%lu: seq (%s) failed\n", lineno, sflags(flags));533#undef NOSUCHKEY534break;535}536}537538void539dump(DB *dbp, int rev, int recurse)540{541DBT key, data;542int lflags, nflags;543544if (rev) {545lflags = R_LAST;546nflags = recurse ? R_RPREV : R_PREV;547} else {548lflags = R_FIRST;549nflags = recurse ? R_RNEXT : R_NEXT;550}551for (;; lflags = nflags)552switch (dbp->seq(dbp, &key, &data, lflags)) {553case 0:554if (write(ofd, data.data, data.size) !=555(ssize_t)data.size)556err("write: %s", strerror(errno));557if (ofd == STDOUT_FILENO) {558if (write(ofd, "\n", 1) != 1)559err("write: %s", strerror(errno));560}561break;562case 1:563goto done;564case -1:565err("line %lu: (dump) seq: %s",566lineno, strerror(errno));567/* NOTREACHED */568}569done: return;570}571572void573unlinkpg(DB *dbp)574{575BTREE *t = dbp->internal;576PAGE *h = NULL;577db_pgno_t pg;578579for (pg = P_ROOT; pg < t->bt_mp->npages;580mpool_put(t->bt_mp, h, 0), pg++) {581if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)582break;583/* Look for a nonempty leaf page that has both left584* and right siblings. */585if (h->prevpg == P_INVALID || h->nextpg == P_INVALID)586continue;587if (NEXTINDEX(h) == 0)588continue;589if ((h->flags & (P_BLEAF | P_RLEAF)))590break;591}592if (h == NULL || pg == t->bt_mp->npages) {593fprintf(stderr, "unlinkpg: no appropriate page found\n");594return;595}596if (__bt_relink(t, h) != 0) {597perror("unlinkpg");598goto cleanup;599}600h->prevpg = P_INVALID;601h->nextpg = P_INVALID;602cleanup:603mpool_put(t->bt_mp, h, MPOOL_DIRTY);604}605606u_int607setflags(char *s)608{609char *p;610611for (; isspace((int) *s); ++s);612if (*s == '\n' || *s == '\0')613return (0);614if ((p = strchr(s, '\n')) != NULL)615*p = '\0';616if (!strcmp(s, "R_CURSOR")) return (R_CURSOR);617if (!strcmp(s, "R_FIRST")) return (R_FIRST);618if (!strcmp(s, "R_IAFTER")) return (R_IAFTER);619if (!strcmp(s, "R_IBEFORE")) return (R_IBEFORE);620if (!strcmp(s, "R_LAST")) return (R_LAST);621if (!strcmp(s, "R_NEXT")) return (R_NEXT);622if (!strcmp(s, "R_NOOVERWRITE")) return (R_NOOVERWRITE);623if (!strcmp(s, "R_PREV")) return (R_PREV);624if (!strcmp(s, "R_SETCURSOR")) return (R_SETCURSOR);625626err("line %lu: %s: unknown flag", lineno, s);627/* NOTREACHED */628}629630char *631sflags(int lflags)632{633switch (lflags) {634case R_CURSOR: return ("R_CURSOR");635case R_FIRST: return ("R_FIRST");636case R_IAFTER: return ("R_IAFTER");637case R_IBEFORE: return ("R_IBEFORE");638case R_LAST: return ("R_LAST");639case R_NEXT: return ("R_NEXT");640case R_NOOVERWRITE: return ("R_NOOVERWRITE");641case R_PREV: return ("R_PREV");642case R_SETCURSOR: return ("R_SETCURSOR");643}644645return ("UNKNOWN!");646}647648DBTYPE649dbtype(char *s)650{651if (!strcmp(s, "btree"))652return (DB_BTREE);653if (!strcmp(s, "hash"))654return (DB_HASH);655if (!strcmp(s, "recno"))656return (DB_RECNO);657err("%s: unknown type (use btree, hash or recno)", s);658/* NOTREACHED */659}660661void *662setinfo(DBTYPE db_type, char *s)663{664static BTREEINFO ib;665static HASHINFO ih;666static RECNOINFO rh;667char *eq;668669if ((eq = strchr(s, '=')) == NULL)670err("%s: illegal structure set statement", s);671*eq++ = '\0';672if (!isdigit((int) *eq))673err("%s: structure set statement must be a number", s);674675switch (db_type) {676case DB_BTREE:677if (!strcmp("flags", s)) {678ib.flags = atoi(eq);679return (&ib);680}681if (!strcmp("cachesize", s)) {682ib.cachesize = atoi(eq);683return (&ib);684}685if (!strcmp("maxkeypage", s)) {686ib.maxkeypage = atoi(eq);687return (&ib);688}689if (!strcmp("minkeypage", s)) {690ib.minkeypage = atoi(eq);691return (&ib);692}693if (!strcmp("lorder", s)) {694ib.lorder = atoi(eq);695return (&ib);696}697if (!strcmp("psize", s)) {698ib.psize = atoi(eq);699return (&ib);700}701break;702case DB_HASH:703if (!strcmp("bsize", s)) {704ih.bsize = atoi(eq);705return (&ih);706}707if (!strcmp("ffactor", s)) {708ih.ffactor = atoi(eq);709return (&ih);710}711if (!strcmp("nelem", s)) {712ih.nelem = atoi(eq);713return (&ih);714}715if (!strcmp("cachesize", s)) {716ih.cachesize = atoi(eq);717return (&ih);718}719if (!strcmp("lorder", s)) {720ih.lorder = atoi(eq);721return (&ih);722}723break;724case DB_RECNO:725if (!strcmp("flags", s)) {726rh.flags = atoi(eq);727return (&rh);728}729if (!strcmp("cachesize", s)) {730rh.cachesize = atoi(eq);731return (&rh);732}733if (!strcmp("lorder", s)) {734rh.lorder = atoi(eq);735return (&rh);736}737if (!strcmp("reclen", s)) {738rh.reclen = atoi(eq);739return (&rh);740}741if (!strcmp("bval", s)) {742rh.bval = atoi(eq);743return (&rh);744}745if (!strcmp("psize", s)) {746rh.psize = atoi(eq);747return (&rh);748}749break;750}751err("%s: unknown structure value", s);752/* NOTREACHED */753}754755void *756rfile(char *name, size_t *lenp)757{758struct stat sb;759void *p;760int fd;761char *np;762763for (; isspace((int) *name); ++name);764if ((np = strchr(name, '\n')) != NULL)765*np = '\0';766if ((fd = open(name, O_RDONLY, 0)) < 0 ||767fstat(fd, &sb))768err("%s: %s\n", name, strerror(errno));769#ifdef NOT_PORTABLE770if (sb.st_size > (off_t)SIZE_T_MAX)771err("%s: %s\n", name, strerror(E2BIG));772#endif773if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)774err("%s", strerror(errno));775if (read(fd, p, (int)sb.st_size) == -1)776err("%s", strerror(errno));777*lenp = sb.st_size;778(void)close(fd);779return (p);780}781782void *783xmalloc(char *text, size_t len)784{785void *p;786787if ((p = (void *)malloc(len)) == NULL)788err("%s", strerror(errno));789memmove(p, text, len);790return (p);791}792793void794usage(void)795{796(void)fprintf(stderr,797"usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");798exit(1);799}800801#include <stdarg.h>802803void804err(const char *fmt, ...)805{806va_list ap;807va_start(ap, fmt);808(void)fprintf(stderr, "dbtest: ");809(void)vfprintf(stderr, fmt, ap);810va_end(ap);811(void)fprintf(stderr, "\n");812exit(1);813/* NOTREACHED */814}815816817