1/*	$NetBSD: h_db.c,v 1.3 2016/09/24 21:18:22 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1992, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
18 *
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
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
35	The Regents of the University of California.  All rights reserved.");
36#endif /* not lint */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)dbtest.c	8.17 (Berkeley) 9/1/94";
41#else
42__RCSID("$NetBSD: h_db.c,v 1.3 2016/09/24 21:18:22 christos Exp $");
43#endif
44#endif /* not lint */
45
46#include <sys/param.h>
47#include <sys/stat.h>
48
49#include <ctype.h>
50#include <errno.h>
51#include <fcntl.h>
52#include <limits.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <stdbool.h>
57#include <unistd.h>
58#include <err.h>
59#include <db.h>
60#include "btree.h"
61
62enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
63
64static void	 compare(DBT *, DBT *);
65static DBTYPE	 dbtype(const char *);
66static void	 dump(DB *, int, int);
67static void	 get(DB *, DBT *);
68static void	 getdata(DB *, DBT *, DBT *);
69static void	 put(DB *, DBT *, DBT *);
70static void	 rem(DB *, DBT *);
71static const char *sflags(int);
72static void	 synk(DB *);
73static void	*rfile(char *, size_t *);
74static void	 seq(DB *, DBT *);
75static u_int	 setflags(char *);
76static void	*setinfo(DBTYPE, char *);
77static void	 unlinkpg(DB *);
78static void	 usage(void) __attribute__((__noreturn__));
79static void	*xcopy(void *, size_t);
80static void	 chkcmd(enum S);
81static void	 chkdata(enum S);
82static void	 chkkey(enum S);
83
84#ifdef STATISTICS
85extern void __bt_stat(DB *);
86#endif
87extern int __bt_relink(BTREE *, PAGE *);
88
89static DBTYPE type;			/* Database type. */
90static void *infop;			/* Iflags. */
91static size_t lineno;			/* Current line in test script. */
92static u_int flags;				/* Current DB flags. */
93static int ofd = STDOUT_FILENO;		/* Standard output fd. */
94
95static DB *XXdbp;			/* Global for gdb. */
96static size_t XXlineno;			/* Fast breakpoint for gdb. */
97
98int
99main(int argc, char *argv[])
100{
101	extern int optind;
102	extern char *optarg;
103	enum S command = COMMAND, state;
104	DB *dbp;
105	DBT data, key, keydata;
106	size_t len;
107	int ch, oflags, sflag;
108	char *fname, *infoarg, *p, *t, buf[8 * 1024];
109	bool unlink_dbfile;
110
111	infoarg = NULL;
112	fname = NULL;
113	unlink_dbfile = false;
114	oflags = O_CREAT | O_RDWR;
115	sflag = 0;
116	while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
117		switch (ch) {
118		case 'f':
119			fname = optarg;
120			break;
121		case 'i':
122			infoarg = optarg;
123			break;
124		case 'l':
125			oflags |= DB_LOCK;
126			break;
127		case 'o':
128			if ((ofd = open(optarg,
129			    O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
130				err(1, "Cannot create `%s'", optarg);
131			break;
132		case 's':
133			sflag = 1;
134			break;
135		case '?':
136		default:
137			usage();
138		}
139	argc -= optind;
140	argv += optind;
141
142	if (argc != 2)
143		usage();
144
145	/* Set the type. */
146	type = dbtype(*argv++);
147
148	/* Open the descriptor file. */
149        if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
150	    err(1, "Cannot reopen `%s'", *argv);
151
152	/* Set up the db structure as necessary. */
153	if (infoarg == NULL)
154		infop = NULL;
155	else
156		for (p = strtok(infoarg, ",\t "); p != NULL;
157		    p = strtok(0, ",\t "))
158			if (*p != '\0')
159				infop = setinfo(type, p);
160
161	/*
162	 * Open the DB.  Delete any preexisting copy, you almost never
163	 * want it around, and it often screws up tests.
164	 */
165	if (fname == NULL) {
166		const char *q = getenv("TMPDIR");
167		if (q == NULL)
168			q = "/var/tmp";
169		(void)snprintf(buf, sizeof(buf), "%s/__dbtest", q);
170		fname = buf;
171		(void)unlink(buf);
172		unlink_dbfile = true;
173	} else  if (!sflag)
174		(void)unlink(fname);
175
176	if ((dbp = dbopen(fname,
177	    oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
178		err(1, "Cannot dbopen `%s'", fname);
179	XXdbp = dbp;
180	if (unlink_dbfile)
181		(void)unlink(fname);
182
183	state = COMMAND;
184	for (lineno = 1;
185	    (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
186		/* Delete the newline, displaying the key/data is easier. */
187		if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
188			*t = '\0';
189		if ((len = strlen(buf)) == 0 || isspace((unsigned char)*p) ||
190		    *p == '#')
191			continue;
192
193		/* Convenient gdb break point. */
194		if (XXlineno == lineno)
195			XXlineno = 1;
196		switch (*p) {
197		case 'c':			/* compare */
198			chkcmd(state);
199			state = KEY;
200			command = COMPARE;
201			break;
202		case 'e':			/* echo */
203			chkcmd(state);
204			/* Don't display the newline, if CR at EOL. */
205			if (p[len - 2] == '\r')
206				--len;
207			if (write(ofd, p + 1, len - 1) != (ssize_t)len - 1 ||
208			    write(ofd, "\n", 1) != 1)
209				err(1, "write failed");
210			break;
211		case 'g':			/* get */
212			chkcmd(state);
213			state = KEY;
214			command = GET;
215			break;
216		case 'p':			/* put */
217			chkcmd(state);
218			state = KEY;
219			command = PUT;
220			break;
221		case 'r':			/* remove */
222			chkcmd(state);
223                        if (flags == R_CURSOR) {
224				rem(dbp, &key);
225				state = COMMAND;
226                        } else {
227				state = KEY;
228				command = REMOVE;
229			}
230			break;
231		case 'S':			/* sync */
232			chkcmd(state);
233			synk(dbp);
234			state = COMMAND;
235			break;
236		case 's':			/* seq */
237			chkcmd(state);
238			if (flags == R_CURSOR) {
239				state = KEY;
240				command = SEQ;
241			} else
242				seq(dbp, &key);
243			break;
244		case 'f':
245			flags = setflags(p + 1);
246			break;
247		case 'D':			/* data file */
248			chkdata(state);
249			data.data = rfile(p + 1, &data.size);
250			goto ldata;
251		case 'd':			/* data */
252			chkdata(state);
253			data.data = xcopy(p + 1, len - 1);
254			data.size = len - 1;
255ldata:			switch (command) {
256			case COMPARE:
257				compare(&keydata, &data);
258				break;
259			case PUT:
260				put(dbp, &key, &data);
261				break;
262			default:
263				errx(1, "line %zu: command doesn't take data",
264				    lineno);
265			}
266			if (type != DB_RECNO)
267				free(key.data);
268			free(data.data);
269			state = COMMAND;
270			break;
271		case 'K':			/* key file */
272			chkkey(state);
273			if (type == DB_RECNO)
274				errx(1, "line %zu: 'K' not available for recno",
275				    lineno);
276			key.data = rfile(p + 1, &key.size);
277			goto lkey;
278		case 'k':			/* key */
279			chkkey(state);
280			if (type == DB_RECNO) {
281				static recno_t recno;
282				recno = atoi(p + 1);
283				key.data = &recno;
284				key.size = sizeof(recno);
285			} else {
286				key.data = xcopy(p + 1, len - 1);
287				key.size = len - 1;
288			}
289lkey:			switch (command) {
290			case COMPARE:
291				getdata(dbp, &key, &keydata);
292				state = DATA;
293				break;
294			case GET:
295				get(dbp, &key);
296				if (type != DB_RECNO)
297					free(key.data);
298				state = COMMAND;
299				break;
300			case PUT:
301				state = DATA;
302				break;
303			case REMOVE:
304				rem(dbp, &key);
305				if ((type != DB_RECNO) && (flags != R_CURSOR))
306					free(key.data);
307				state = COMMAND;
308				break;
309			case SEQ:
310				seq(dbp, &key);
311				if ((type != DB_RECNO) && (flags != R_CURSOR))
312					free(key.data);
313				state = COMMAND;
314				break;
315			default:
316				errx(1, "line %zu: command doesn't take a key",
317				    lineno);
318			}
319			break;
320		case 'o':
321			dump(dbp, p[1] == 'r', 0);
322			break;
323		case 'O':
324			dump(dbp, p[1] == 'r', 1);
325			break;
326		case 'u':
327			unlinkpg(dbp);
328			break;
329		default:
330			errx(1, "line %zu: %s: unknown command character",
331			    lineno, p);
332		}
333	}
334#ifdef STATISTICS
335	/*
336	 * -l must be used (DB_LOCK must be set) for this to be
337	 * used, otherwise a page will be locked and it will fail.
338	 */
339	if (type == DB_BTREE && oflags & DB_LOCK)
340		__bt_stat(dbp);
341#endif
342	if ((*dbp->close)(dbp))
343		err(1, "db->close failed");
344	(void)close(ofd);
345	return 0;
346}
347
348#define	NOOVERWRITE	"put failed, would overwrite key\n"
349
350static void
351compare(DBT *db1, DBT *db2)
352{
353	size_t len;
354	u_char *p1, *p2;
355
356	if (db1->size != db2->size)
357		printf("compare failed: key->data len %zu != data len %zu\n",
358		    db1->size, db2->size);
359
360	len = MIN(db1->size, db2->size);
361	for (p1 = db1->data, p2 = db2->data; len--;)
362		if (*p1++ != *p2++) {
363			printf("compare failed at offset %lu\n",
364			    (unsigned long)(p1 - (u_char *)db1->data));
365			break;
366		}
367}
368
369static void
370get(DB *dbp, DBT *kp)
371{
372	DBT data;
373
374	switch ((*dbp->get)(dbp, kp, &data, flags)) {
375	case 0:
376		(void)write(ofd, data.data, data.size);
377		if (ofd == STDOUT_FILENO)
378			(void)write(ofd, "\n", 1);
379		break;
380	case -1:
381		err(1, "line %zu: get failed", lineno);
382		/* NOTREACHED */
383	case 1:
384#define	NOSUCHKEY	"get failed, no such key\n"
385		if (ofd != STDOUT_FILENO)
386			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
387		else
388			(void)fprintf(stderr, "%zu: %.*s: %s",
389			    lineno, (int)MIN(kp->size, 20),
390			    (const char *)kp->data,
391			    NOSUCHKEY);
392#undef	NOSUCHKEY
393		break;
394	}
395}
396
397static void
398getdata(DB *dbp, DBT *kp, DBT *dp)
399{
400	switch ((*dbp->get)(dbp, kp, dp, flags)) {
401	case 0:
402		return;
403	case -1:
404		err(1, "line %zu: getdata failed", lineno);
405		/* NOTREACHED */
406	case 1:
407		errx(1, "line %zu: getdata failed, no such key", lineno);
408		/* NOTREACHED */
409	}
410}
411
412static void
413put(DB *dbp, DBT *kp, DBT *dp)
414{
415	switch ((*dbp->put)(dbp, kp, dp, flags)) {
416	case 0:
417		break;
418	case -1:
419		err(1, "line %zu: put failed", lineno);
420		/* NOTREACHED */
421	case 1:
422		(void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
423		break;
424	}
425}
426
427static void
428rem(DB *dbp, DBT *kp)
429{
430	switch ((*dbp->del)(dbp, kp, flags)) {
431	case 0:
432		break;
433	case -1:
434		err(1, "line %zu: rem failed", lineno);
435		/* NOTREACHED */
436	case 1:
437#define	NOSUCHKEY	"rem failed, no such key\n"
438		if (ofd != STDOUT_FILENO)
439			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
440		else if (flags != R_CURSOR)
441			(void)fprintf(stderr, "%zu: %.*s: %s",
442			    lineno, (int)MIN(kp->size, 20),
443			    (const char *)kp->data, NOSUCHKEY);
444		else
445			(void)fprintf(stderr,
446			    "%zu: rem of cursor failed\n", lineno);
447#undef	NOSUCHKEY
448		break;
449	}
450}
451
452static void
453synk(DB *dbp)
454{
455	switch ((*dbp->sync)(dbp, flags)) {
456	case 0:
457		break;
458	case -1:
459		err(1, "line %zu: synk failed", lineno);
460		/* NOTREACHED */
461	}
462}
463
464static void
465seq(DB *dbp, DBT *kp)
466{
467	DBT data;
468
469	switch (dbp->seq(dbp, kp, &data, flags)) {
470	case 0:
471		(void)write(ofd, data.data, data.size);
472		if (ofd == STDOUT_FILENO)
473			(void)write(ofd, "\n", 1);
474		break;
475	case -1:
476		err(1, "line %zu: seq failed", lineno);
477		/* NOTREACHED */
478	case 1:
479#define	NOSUCHKEY	"seq failed, no such key\n"
480		if (ofd != STDOUT_FILENO)
481			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
482		else if (flags == R_CURSOR)
483			(void)fprintf(stderr, "%zu: %.*s: %s",
484			    lineno, (int)MIN(kp->size, 20),
485			    (const char *)kp->data, NOSUCHKEY);
486		else
487			(void)fprintf(stderr,
488			    "%zu: seq (%s) failed\n", lineno, sflags(flags));
489#undef	NOSUCHKEY
490		break;
491	}
492}
493
494static void
495dump(DB *dbp, int rev, int recurse)
496{
497	DBT key, data;
498	int xflags, nflags;
499
500	if (rev) {
501		xflags = R_LAST;
502		nflags = recurse ? R_RPREV : R_PREV;
503	} else {
504		xflags = R_FIRST;
505		nflags = recurse ? R_RNEXT : R_NEXT;
506	}
507	for (;; xflags = nflags)
508		switch (dbp->seq(dbp, &key, &data, xflags)) {
509		case 0:
510			(void)write(ofd, data.data, data.size);
511			if (ofd == STDOUT_FILENO)
512				(void)write(ofd, "\n", 1);
513			break;
514		case 1:
515			goto done;
516		case -1:
517			err(1, "line %zu: (dump) seq failed", lineno);
518			/* NOTREACHED */
519		}
520done:	return;
521}
522
523void
524unlinkpg(DB *dbp)
525{
526	BTREE *t = dbp->internal;
527	PAGE *h = NULL;
528	pgno_t pg;
529
530	for (pg = P_ROOT; pg < t->bt_mp->npages;
531	     mpool_put(t->bt_mp, h, 0), pg++) {
532		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
533			break;
534		/* Look for a nonempty leaf page that has both left
535		 * and right siblings. */
536		if (h->prevpg == P_INVALID || h->nextpg == P_INVALID)
537			continue;
538		if (NEXTINDEX(h) == 0)
539			continue;
540		if ((h->flags & (P_BLEAF | P_RLEAF)))
541			break;
542	}
543	if (h == NULL || pg == t->bt_mp->npages) {
544		errx(1, "%s: no appropriate page found", __func__);
545		return;
546	}
547	if (__bt_relink(t, h) != 0) {
548		perror("unlinkpg");
549		goto cleanup;
550	}
551	h->prevpg = P_INVALID;
552	h->nextpg = P_INVALID;
553cleanup:
554	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
555}
556
557static u_int
558setflags(char *s)
559{
560	char *p;
561
562	for (; isspace((unsigned char)*s); ++s);
563	if (*s == '\n' || *s == '\0')
564		return 0;
565	if ((p = strchr(s, '\n')) != NULL)
566		*p = '\0';
567	if (!strcmp(s, "R_CURSOR"))		return R_CURSOR;
568	if (!strcmp(s, "R_FIRST"))		return R_FIRST;
569	if (!strcmp(s, "R_IAFTER")) 		return R_IAFTER;
570	if (!strcmp(s, "R_IBEFORE")) 		return R_IBEFORE;
571	if (!strcmp(s, "R_LAST")) 		return R_LAST;
572	if (!strcmp(s, "R_NEXT")) 		return R_NEXT;
573	if (!strcmp(s, "R_NOOVERWRITE"))	return R_NOOVERWRITE;
574	if (!strcmp(s, "R_PREV"))		return R_PREV;
575	if (!strcmp(s, "R_SETCURSOR"))		return R_SETCURSOR;
576
577	errx(1, "line %zu: %s: unknown flag", lineno, s);
578	/* NOTREACHED */
579}
580
581static const char *
582sflags(int xflags)
583{
584	switch (xflags) {
585	case R_CURSOR:		return "R_CURSOR";
586	case R_FIRST:		return "R_FIRST";
587	case R_IAFTER:		return "R_IAFTER";
588	case R_IBEFORE:		return "R_IBEFORE";
589	case R_LAST:		return "R_LAST";
590	case R_NEXT:		return "R_NEXT";
591	case R_NOOVERWRITE:	return "R_NOOVERWRITE";
592	case R_PREV:		return "R_PREV";
593	case R_SETCURSOR:	return "R_SETCURSOR";
594	}
595
596	return "UNKNOWN!";
597}
598
599static DBTYPE
600dbtype(const char *s)
601{
602	if (!strcmp(s, "btree"))
603		return DB_BTREE;
604	if (!strcmp(s, "hash"))
605		return DB_HASH;
606	if (!strcmp(s, "recno"))
607		return DB_RECNO;
608	errx(1, "%s: unknown type (use btree, hash or recno)", s);
609	/* NOTREACHED */
610}
611
612static void *
613setinfo(DBTYPE dtype, char *s)
614{
615	static BTREEINFO ib;
616	static HASHINFO ih;
617	static RECNOINFO rh;
618	char *eq;
619
620	if ((eq = strchr(s, '=')) == NULL)
621		errx(1, "%s: illegal structure set statement", s);
622	*eq++ = '\0';
623	if (!isdigit((unsigned char)*eq))
624		errx(1, "%s: structure set statement must be a number", s);
625
626	switch (dtype) {
627	case DB_BTREE:
628		if (!strcmp("flags", s)) {
629			ib.flags = atoi(eq);
630			return &ib;
631		}
632		if (!strcmp("cachesize", s)) {
633			ib.cachesize = atoi(eq);
634			return &ib;
635		}
636		if (!strcmp("maxkeypage", s)) {
637			ib.maxkeypage = atoi(eq);
638			return &ib;
639		}
640		if (!strcmp("minkeypage", s)) {
641			ib.minkeypage = atoi(eq);
642			return &ib;
643		}
644		if (!strcmp("lorder", s)) {
645			ib.lorder = atoi(eq);
646			return &ib;
647		}
648		if (!strcmp("psize", s)) {
649			ib.psize = atoi(eq);
650			return &ib;
651		}
652		break;
653	case DB_HASH:
654		if (!strcmp("bsize", s)) {
655			ih.bsize = atoi(eq);
656			return &ih;
657		}
658		if (!strcmp("ffactor", s)) {
659			ih.ffactor = atoi(eq);
660			return &ih;
661		}
662		if (!strcmp("nelem", s)) {
663			ih.nelem = atoi(eq);
664			return &ih;
665		}
666		if (!strcmp("cachesize", s)) {
667			ih.cachesize = atoi(eq);
668			return &ih;
669		}
670		if (!strcmp("lorder", s)) {
671			ih.lorder = atoi(eq);
672			return &ih;
673		}
674		break;
675	case DB_RECNO:
676		if (!strcmp("flags", s)) {
677			rh.flags = atoi(eq);
678			return &rh;
679		}
680		if (!strcmp("cachesize", s)) {
681			rh.cachesize = atoi(eq);
682			return &rh;
683		}
684		if (!strcmp("lorder", s)) {
685			rh.lorder = atoi(eq);
686			return &rh;
687		}
688		if (!strcmp("reclen", s)) {
689			rh.reclen = atoi(eq);
690			return &rh;
691		}
692		if (!strcmp("bval", s)) {
693			rh.bval = atoi(eq);
694			return &rh;
695		}
696		if (!strcmp("psize", s)) {
697			rh.psize = atoi(eq);
698			return &rh;
699		}
700		break;
701	}
702	errx(1, "%s: unknown structure value", s);
703	/* NOTREACHED */
704}
705
706static void *
707rfile(char *name, size_t *lenp)
708{
709	struct stat sb;
710	void *p;
711	int fd;
712	char *np;
713
714	for (; isspace((unsigned char)*name); ++name)
715		continue;
716	if ((np = strchr(name, '\n')) != NULL)
717		*np = '\0';
718	if ((fd = open(name, O_RDONLY, 0)) == -1 || fstat(fd, &sb) == -1)
719		err(1, "Cannot open `%s'", name);
720#ifdef NOT_PORTABLE
721	if (sb.st_size > (off_t)SIZE_T_MAX) {
722		errno = E2BIG;
723		err("Cannot process `%s'", name);
724	}
725#endif
726	if ((p = malloc((size_t)sb.st_size)) == NULL)
727		err(1, "Cannot allocate %zu bytes", (size_t)sb.st_size);
728	if (read(fd, p, (ssize_t)sb.st_size) != (ssize_t)sb.st_size)
729		err(1, "read failed");
730	*lenp = (size_t)sb.st_size;
731	(void)close(fd);
732	return p;
733}
734
735static void *
736xcopy(void *text, size_t len)
737{
738	void *p;
739
740	if ((p = malloc(len)) == NULL)
741		err(1, "Cannot allocate %zu bytes", len);
742	(void)memmove(p, text, len);
743	return p;
744}
745
746static void
747chkcmd(enum S state)
748{
749	if (state != COMMAND)
750		errx(1, "line %zu: not expecting command", lineno);
751}
752
753static void
754chkdata(enum S state)
755{
756	if (state != DATA)
757		errx(1, "line %zu: not expecting data", lineno);
758}
759
760static void
761chkkey(enum S state)
762{
763	if (state != KEY)
764		errx(1, "line %zu: not expecting a key", lineno);
765}
766
767static void
768usage(void)
769{
770	(void)fprintf(stderr,
771	    "Usage: %s [-lu] [-f file] [-i info] [-o file] [-O file] "
772		"type script\n", getprogname());
773	exit(1);
774}
775