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