]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/file/apprentice.c
Virgin import of Christos Zoulas's FILE 3.34.
[FreeBSD/FreeBSD.git] / contrib / file / apprentice.c
1 /*
2  * apprentice - make one pass through /etc/magic, learning its secrets.
3  *
4  * Copyright (c) Ian F. Darwin, 1987.
5  * Written by Ian F. Darwin.
6  *
7  * This software is not subject to any license of the American Telephone
8  * and Telegraph Company or of the Regents of the University of California.
9  *
10  * Permission is granted to anyone to use this software for any purpose on
11  * any computer system, and to alter it and redistribute it freely, subject
12  * to the following restrictions:
13  *
14  * 1. The author is not responsible for the consequences of use of this
15  *    software, no matter how awful, even if they arise from flaws in it.
16  *
17  * 2. The origin of this software must not be misrepresented, either by
18  *    explicit claim or by omission.  Since few users ever read sources,
19  *    credits must appear in the documentation.
20  *
21  * 3. Altered versions must be plainly marked as such, and must not be
22  *    misrepresented as being the original software.  Since few users
23  *    ever read sources, credits must appear in the documentation.
24  *
25  * 4. This notice may not be removed or altered.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #ifdef QUICK
34 #include <fcntl.h>
35 #include <sys/stat.h>
36 #include <sys/mman.h>
37 #endif
38 #include "file.h"
39
40 #ifndef lint
41 FILE_RCSID("@(#)$Id: apprentice.c,v 1.34 2001/03/11 20:29:16 christos Exp $")
42 #endif  /* lint */
43
44 #define EATAB {while (isascii((unsigned char) *l) && \
45                       isspace((unsigned char) *l))  ++l;}
46 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
47                         tolower((unsigned char) (l)) : (l))
48
49
50 #ifdef __EMX__
51   char PATHSEP=';';
52 #else
53   char PATHSEP=':';
54 #endif
55
56
57 static int getvalue     __P((struct magic *, char **));
58 static int hextoint     __P((int));
59 static char *getstr     __P((char *, char *, int, int *));
60 static int parse        __P((struct magic **, uint32 *, char *, int));
61 static void eatsize     __P((char **));
62 static int apprentice_1 __P((const char *, int));
63 static int apprentice_file      __P((struct magic **, uint32 *,
64     const char *, int));
65 #ifdef QUICK
66 static void byteswap    __P((struct magic *, uint32));
67 static void bs1         __P((struct magic *));
68 static uint16 swap2     __P((uint16));
69 static uint32 swap4     __P((uint32));
70 static char * mkdbname  __P((const char *));
71 static int apprentice_map       __P((struct magic **, uint32 *,
72     const char *, int));
73 static int apprentice_compile   __P((struct magic **, uint32 *,
74     const char *, int));
75 #endif
76
77 static int maxmagic = 0;
78
79 struct mlist mlist;
80
81
82 /*
83  * Handle one file.
84  */
85 static int
86 apprentice_1(fn, action)
87         const char *fn;
88         int action;
89 {
90         struct magic *magic = NULL;
91         uint32 nmagic = 0;
92         struct mlist *ml;
93         int rv = -1;
94
95 #ifdef QUICK
96         if (action == COMPILE) {
97                 rv = apprentice_file(&magic, &nmagic, fn, action);
98                 if (rv == 0)
99                         return apprentice_compile(&magic, &nmagic, fn, action);
100                 else
101                         return rv;
102         }
103         if ((rv = apprentice_map(&magic, &nmagic, fn, action)) != 0)
104                 (void)fprintf(stderr, "%s: Using regular magic file `%s'\n",
105                     progname, fn);
106 #endif
107                 
108         if (rv != 0)
109                 rv = apprentice_file(&magic, &nmagic, fn, action);
110
111         if (rv != 0)
112                 return rv;
113              
114         if ((ml = malloc(sizeof(*ml))) == NULL) {
115                 (void) fprintf(stderr, "%s: Out of memory.\n", progname);
116                 if (action == CHECK)
117                         return -1;
118         }
119
120         if (magic == NULL || nmagic == 0)
121                 return rv;
122
123         ml->magic = magic;
124         ml->nmagic = nmagic;
125
126         mlist.prev->next = ml;
127         ml->prev = mlist.prev;
128         ml->next = &mlist;
129         mlist.prev = ml;
130
131         return rv;
132 }
133
134
135 int
136 apprentice(fn, action)
137         const char *fn;                 /* list of magic files */
138         int action;
139 {
140         char *p, *mfn;
141         int file_err, errs = -1;
142
143         mlist.next = mlist.prev = &mlist;
144         mfn = malloc(strlen(fn)+1);
145         if (mfn == NULL) {
146                 (void) fprintf(stderr, "%s: Out of memory.\n", progname);
147                 if (action == CHECK)
148                         return -1;
149                 else
150                         exit(1);
151         }
152         fn = strcpy(mfn, fn);
153   
154         while (fn) {
155                 p = strchr(fn, PATHSEP);
156                 if (p)
157                         *p++ = '\0';
158                 file_err = apprentice_1(fn, action);
159                 if (file_err > errs)
160                         errs = file_err;
161                 fn = p;
162         }
163         if (errs == -1)
164                 (void) fprintf(stderr, "%s: couldn't find any magic files!\n",
165                     progname);
166         if (action == CHECK && errs)
167                 exit(1);
168
169         free(mfn);
170         return errs;
171 }
172
173 /*
174  * parse from a file
175  */
176 static int
177 apprentice_file(magicp, nmagicp, fn, action)
178         struct magic **magicp;
179         uint32 *nmagicp;
180         const char *fn;                 /* name of magic file */
181         int action;
182 {
183         static const char hdr[] =
184                 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
185         FILE *f;
186         char line[BUFSIZ+1];
187         int errs = 0;
188
189         f = fopen(fn, "r");
190         if (f == NULL) {
191                 if (errno != ENOENT)
192                         (void) fprintf(stderr,
193                             "%s: can't read magic file %s (%s)\n", 
194                             progname, fn, strerror(errno));
195                 return -1;
196         }
197
198         maxmagic = MAXMAGIS;
199         *magicp = (struct magic *) calloc(sizeof(struct magic), maxmagic);
200         if (*magicp == NULL) {
201                 (void) fprintf(stderr, "%s: Out of memory.\n", progname);
202                 if (action == CHECK)
203                         return -1;
204         }
205
206         /* parse it */
207         if (action == CHECK)    /* print silly verbose header for USG compat. */
208                 (void) printf("%s\n", hdr);
209
210         for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
211                 if (line[0]=='#')       /* comment, do not parse */
212                         continue;
213                 if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
214                         continue;
215                 line[strlen(line)-1] = '\0'; /* delete newline */
216                 if (parse(magicp, nmagicp, line, action) != 0)
217                         errs = 1;
218         }
219
220         (void) fclose(f);
221         if (errs) {
222                 free(*magicp);
223                 *magicp = NULL;
224                 *nmagicp = 0;
225         }
226         return errs;
227 }
228
229 /*
230  * extend the sign bit if the comparison is to be signed
231  */
232 uint32
233 signextend(m, v)
234         struct magic *m;
235         uint32 v;
236 {
237         if (!(m->flag & UNSIGNED))
238                 switch(m->type) {
239                 /*
240                  * Do not remove the casts below.  They are
241                  * vital.  When later compared with the data,
242                  * the sign extension must have happened.
243                  */
244                 case BYTE:
245                         v = (char) v;
246                         break;
247                 case SHORT:
248                 case BESHORT:
249                 case LESHORT:
250                         v = (short) v;
251                         break;
252                 case DATE:
253                 case BEDATE:
254                 case LEDATE:
255                 case LONG:
256                 case BELONG:
257                 case LELONG:
258                         v = (int32) v;
259                         break;
260                 case STRING:
261                         break;
262                 default:
263                         magwarn("can't happen: m->type=%d\n",
264                                 m->type);
265                         return -1;
266                 }
267         return v;
268 }
269
270 /*
271  * parse one line from magic file, put into magic[index++] if valid
272  */
273 static int
274 parse(magicp, nmagicp, l, action)
275         struct magic **magicp;
276         uint32 *nmagicp;
277         char *l;
278         int action;
279 {
280         int i = 0;
281         struct magic *m;
282         char *t, *s;
283
284 #define ALLOC_INCR      200
285         if (*nmagicp + 1 >= maxmagic){
286                 maxmagic += ALLOC_INCR;
287                 if ((m = (struct magic *) realloc(*magicp,
288                     sizeof(struct magic) * maxmagic)) == NULL) {
289                         (void) fprintf(stderr, "%s: Out of memory.\n",
290                             progname);
291                         if (*magicp)
292                                 free(*magicp);
293                         if (action == CHECK)
294                                 return -1;
295                         else
296                                 exit(1);
297                 }
298                 *magicp = m;
299                 memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic)
300                     * ALLOC_INCR);
301         }
302         m = &(*magicp)[*nmagicp];
303         m->flag = 0;
304         m->cont_level = 0;
305
306         while (*l == '>') {
307                 ++l;            /* step over */
308                 m->cont_level++; 
309         }
310
311         if (m->cont_level != 0 && *l == '(') {
312                 ++l;            /* step over */
313                 m->flag |= INDIR;
314         }
315         if (m->cont_level != 0 && *l == '&') {
316                 ++l;            /* step over */
317                 m->flag |= ADD;
318         }
319
320         /* get offset, then skip over it */
321         m->offset = (int) strtoul(l,&t,0);
322         if (l == t)
323                 magwarn("offset %s invalid", l);
324         l = t;
325
326         if (m->flag & INDIR) {
327                 m->in_type = LONG;
328                 m->in_offset = 0;
329                 /*
330                  * read [.lbs][+-]nnnnn)
331                  */
332                 if (*l == '.') {
333                         l++;
334                         switch (*l) {
335                         case 'l':
336                                 m->in_type = LELONG;
337                                 break;
338                         case 'L':
339                                 m->in_type = BELONG;
340                                 break;
341                         case 'h':
342                         case 's':
343                                 m->in_type = LESHORT;
344                                 break;
345                         case 'H':
346                         case 'S':
347                                 m->in_type = BESHORT;
348                                 break;
349                         case 'c':
350                         case 'b':
351                         case 'C':
352                         case 'B':
353                                 m->in_type = BYTE;
354                                 break;
355                         default:
356                                 magwarn("indirect offset type %c invalid", *l);
357                                 break;
358                         }
359                         l++;
360                 }
361                 s = l;
362                 if (*l == '+' || *l == '-') l++;
363                 if (isdigit((unsigned char)*l)) {
364                         m->in_offset = strtoul(l, &t, 0);
365                         if (*s == '-') m->in_offset = - m->in_offset;
366                 }
367                 else
368                         t = l;
369                 if (*t++ != ')') 
370                         magwarn("missing ')' in indirect offset");
371                 l = t;
372         }
373
374
375         while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
376                 ++l;
377         EATAB;
378
379 #define NBYTE           4
380 #define NSHORT          5
381 #define NLONG           4
382 #define NSTRING         6
383 #define NDATE           4
384 #define NBESHORT        7
385 #define NBELONG         6
386 #define NBEDATE         6
387 #define NLESHORT        7
388 #define NLELONG         6
389 #define NLEDATE         6
390
391         if (*l == 'u') {
392                 ++l;
393                 m->flag |= UNSIGNED;
394         }
395
396         /* get type, skip it */
397         if (strncmp(l, "char", NBYTE)==0) {     /* HP/UX compat */
398                 m->type = BYTE;
399                 l += NBYTE;
400         } else if (strncmp(l, "byte", NBYTE)==0) {
401                 m->type = BYTE;
402                 l += NBYTE;
403         } else if (strncmp(l, "short", NSHORT)==0) {
404                 m->type = SHORT;
405                 l += NSHORT;
406         } else if (strncmp(l, "long", NLONG)==0) {
407                 m->type = LONG;
408                 l += NLONG;
409         } else if (strncmp(l, "string", NSTRING)==0) {
410                 m->type = STRING;
411                 l += NSTRING;
412         } else if (strncmp(l, "date", NDATE)==0) {
413                 m->type = DATE;
414                 l += NDATE;
415         } else if (strncmp(l, "beshort", NBESHORT)==0) {
416                 m->type = BESHORT;
417                 l += NBESHORT;
418         } else if (strncmp(l, "belong", NBELONG)==0) {
419                 m->type = BELONG;
420                 l += NBELONG;
421         } else if (strncmp(l, "bedate", NBEDATE)==0) {
422                 m->type = BEDATE;
423                 l += NBEDATE;
424         } else if (strncmp(l, "leshort", NLESHORT)==0) {
425                 m->type = LESHORT;
426                 l += NLESHORT;
427         } else if (strncmp(l, "lelong", NLELONG)==0) {
428                 m->type = LELONG;
429                 l += NLELONG;
430         } else if (strncmp(l, "ledate", NLEDATE)==0) {
431                 m->type = LEDATE;
432                 l += NLEDATE;
433         } else {
434                 magwarn("type %s invalid", l);
435                 return -1;
436         }
437         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
438         if (*l == '&') {
439                 ++l;
440                 m->mask = signextend(m, strtoul(l, &l, 0));
441                 eatsize(&l);
442         } else if (STRING == m->type) {
443                 m->mask = 0L;
444                 if (*l == '/') { 
445                         while (!isspace(*++l)) {
446                                 switch (*l) {
447                                 case CHAR_IGNORE_LOWERCASE:
448                                         m->mask |= STRING_IGNORE_LOWERCASE;
449                                         break;
450                                 case CHAR_COMPACT_BLANK:
451                                         m->mask |= STRING_COMPACT_BLANK;
452                                         break;
453                                 case CHAR_COMPACT_OPTIONAL_BLANK:
454                                         m->mask |=
455                                             STRING_COMPACT_OPTIONAL_BLANK;
456                                         break;
457                                 default:
458                                         magwarn("string extension %c invalid",
459                                             *l);
460                                         return -1;
461                                 }
462                         }
463                 }
464         } else
465                 m->mask = ~0L;
466         EATAB;
467   
468         switch (*l) {
469         case '>':
470         case '<':
471         /* Old-style anding: "0 byte &0x80 dynamically linked" */
472         case '&':
473         case '^':
474         case '=':
475                 m->reln = *l;
476                 ++l;
477                 if (*l == '=') {
478                    /* HP compat: ignore &= etc. */
479                    ++l;
480                 }
481                 break;
482         case '!':
483                 if (m->type != STRING) {
484                         m->reln = *l;
485                         ++l;
486                         break;
487                 }
488                 /* FALL THROUGH */
489         default:
490                 if (*l == 'x' && isascii((unsigned char)l[1]) && 
491                     isspace((unsigned char)l[1])) {
492                         m->reln = *l;
493                         ++l;
494                         goto GetDesc;   /* Bill The Cat */
495                 }
496                 m->reln = '=';
497                 break;
498         }
499         EATAB;
500   
501         if (getvalue(m, &l))
502                 return -1;
503         /*
504          * TODO finish this macro and start using it!
505          * #define offsetcheck {if (offset > HOWMANY-1) 
506          *      magwarn("offset too big"); }
507          */
508
509         /*
510          * now get last part - the description
511          */
512 GetDesc:
513         EATAB;
514         if (l[0] == '\b') {
515                 ++l;
516                 m->nospflag = 1;
517         } else if ((l[0] == '\\') && (l[1] == 'b')) {
518                 ++l;
519                 ++l;
520                 m->nospflag = 1;
521         } else
522                 m->nospflag = 0;
523         while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
524                 /* NULLBODY */;
525
526         if (action == CHECK) {
527                 mdump(m);
528         }
529         ++(*nmagicp);           /* make room for next */
530         return 0;
531 }
532
533 /* 
534  * Read a numeric value from a pointer, into the value union of a magic 
535  * pointer, according to the magic type.  Update the string pointer to point 
536  * just after the number read.  Return 0 for success, non-zero for failure.
537  */
538 static int
539 getvalue(m, p)
540         struct magic *m;
541         char **p;
542 {
543         int slen;
544
545         if (m->type == STRING) {
546                 *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
547                 m->vallen = slen;
548         } else
549                 if (m->reln != 'x') {
550                         m->value.l = signextend(m, strtoul(*p, p, 0));
551                         eatsize(p);
552                 }
553         return 0;
554 }
555
556 /*
557  * Convert a string containing C character escapes.  Stop at an unescaped
558  * space or tab.
559  * Copy the converted version to "p", returning its length in *slen.
560  * Return updated scan pointer as function result.
561  */
562 static char *
563 getstr(s, p, plen, slen)
564         char    *s;
565         char    *p;
566         int     plen, *slen;
567 {
568         char    *origs = s, *origp = p;
569         char    *pmax = p + plen - 1;
570         int     c;
571         int     val;
572
573         while ((c = *s++) != '\0') {
574                 if (isspace((unsigned char) c))
575                         break;
576                 if (p >= pmax) {
577                         fprintf(stderr, "String too long: %s\n", origs);
578                         break;
579                 }
580                 if(c == '\\') {
581                         switch(c = *s++) {
582
583                         case '\0':
584                                 goto out;
585
586                         default:
587                                 *p++ = (char) c;
588                                 break;
589
590                         case 'n':
591                                 *p++ = '\n';
592                                 break;
593
594                         case 'r':
595                                 *p++ = '\r';
596                                 break;
597
598                         case 'b':
599                                 *p++ = '\b';
600                                 break;
601
602                         case 't':
603                                 *p++ = '\t';
604                                 break;
605
606                         case 'f':
607                                 *p++ = '\f';
608                                 break;
609
610                         case 'v':
611                                 *p++ = '\v';
612                                 break;
613
614                         /* \ and up to 3 octal digits */
615                         case '0':
616                         case '1':
617                         case '2':
618                         case '3':
619                         case '4':
620                         case '5':
621                         case '6':
622                         case '7':
623                                 val = c - '0';
624                                 c = *s++;  /* try for 2 */
625                                 if(c >= '0' && c <= '7') {
626                                         val = (val<<3) | (c - '0');
627                                         c = *s++;  /* try for 3 */
628                                         if(c >= '0' && c <= '7')
629                                                 val = (val<<3) | (c-'0');
630                                         else
631                                                 --s;
632                                 }
633                                 else
634                                         --s;
635                                 *p++ = (char)val;
636                                 break;
637
638                         /* \x and up to 2 hex digits */
639                         case 'x':
640                                 val = 'x';      /* Default if no digits */
641                                 c = hextoint(*s++);     /* Get next char */
642                                 if (c >= 0) {
643                                         val = c;
644                                         c = hextoint(*s++);
645                                         if (c >= 0)
646                                                 val = (val << 4) + c;
647                                         else
648                                                 --s;
649                                 } else
650                                         --s;
651                                 *p++ = (char)val;
652                                 break;
653                         }
654                 } else
655                         *p++ = (char)c;
656         }
657 out:
658         *p = '\0';
659         *slen = p - origp;
660         return s;
661 }
662
663
664 /* Single hex char to int; -1 if not a hex char. */
665 static int
666 hextoint(c)
667         int c;
668 {
669         if (!isascii((unsigned char) c))
670                 return -1;
671         if (isdigit((unsigned char) c))
672                 return c - '0';
673         if ((c >= 'a')&&(c <= 'f'))
674                 return c + 10 - 'a';
675         if (( c>= 'A')&&(c <= 'F'))
676                 return c + 10 - 'A';
677         return -1;
678 }
679
680
681 /*
682  * Print a string containing C character escapes.
683  */
684 void
685 showstr(fp, s, len)
686         FILE *fp;
687         const char *s;
688         int len;
689 {
690         char    c;
691
692         for (;;) {
693                 c = *s++;
694                 if (len == -1) {
695                         if (c == '\0')
696                                 break;
697                 }
698                 else  {
699                         if (len-- == 0)
700                                 break;
701                 }
702                 if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
703                         (void) fputc(c, fp);
704                 else {
705                         (void) fputc('\\', fp);
706                         switch (c) {
707                         
708                         case '\n':
709                                 (void) fputc('n', fp);
710                                 break;
711
712                         case '\r':
713                                 (void) fputc('r', fp);
714                                 break;
715
716                         case '\b':
717                                 (void) fputc('b', fp);
718                                 break;
719
720                         case '\t':
721                                 (void) fputc('t', fp);
722                                 break;
723
724                         case '\f':
725                                 (void) fputc('f', fp);
726                                 break;
727
728                         case '\v':
729                                 (void) fputc('v', fp);
730                                 break;
731
732                         default:
733                                 (void) fprintf(fp, "%.3o", c & 0377);
734                                 break;
735                         }
736                 }
737         }
738 }
739
740 /*
741  * eatsize(): Eat the size spec from a number [eg. 10UL]
742  */
743 static void
744 eatsize(p)
745         char **p;
746 {
747         char *l = *p;
748
749         if (LOWCASE(*l) == 'u') 
750                 l++;
751
752         switch (LOWCASE(*l)) {
753         case 'l':    /* long */
754         case 's':    /* short */
755         case 'h':    /* short */
756         case 'b':    /* char/byte */
757         case 'c':    /* char/byte */
758                 l++;
759                 /*FALLTHROUGH*/
760         default:
761                 break;
762         }
763
764         *p = l;
765 }
766
767 #ifdef QUICK
768 /*
769  * handle an mmaped file.
770  */
771 static int
772 apprentice_map(magicp, nmagicp, fn, action)
773         struct magic **magicp;
774         uint32 *nmagicp;
775         const char *fn;
776         int action;
777 {
778         int fd;
779         struct stat st;
780         uint32 *ptr;
781         uint32 version;
782         int needsbyteswap;
783         char *dbname = mkdbname(fn);
784
785         if ((fd = open(dbname, O_RDONLY)) == -1)
786                 return -1;
787
788         if (fstat(fd, &st) == -1) {
789                 (void)fprintf(stderr, "%s: Cannot stat `%s' (%s)\n",
790                     progname, dbname, strerror(errno));
791                 goto error;
792         }
793
794         if ((*magicp = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
795             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
796                 (void)fprintf(stderr, "%s: Cannot map `%s' (%s)\n",
797                     progname, dbname, strerror(errno));
798                 goto error;
799         }
800         (void)close(fd);
801         ptr = (uint32 *) *magicp;
802         if (*ptr != MAGICNO) {
803                 if (swap4(*ptr) != MAGICNO) {
804                         (void)fprintf(stderr, "%s: Bad magic in `%s'\n",
805                             progname, dbname);
806                         goto error;
807                 }
808                 needsbyteswap = 1;
809         } else
810                 needsbyteswap = 0;
811         if (needsbyteswap)
812                 version = swap4(ptr[1]);
813         else
814                 version = ptr[1];
815         if (version != VERSIONNO) {
816                 (void)fprintf(stderr, 
817                     "%s: version mismatch (%d != %d) in `%s'\n",
818                     progname, version, VERSION, dbname);
819                 goto error;
820         }
821         *nmagicp = (st.st_size / sizeof(struct magic)) - 1;
822         (*magicp)++;
823         if (needsbyteswap)
824                 byteswap(*magicp, *nmagicp);
825         return 0;
826
827 error:
828         if (fd != -1)
829                 (void)close(fd);
830         if (*magicp)
831                 (void)munmap(*magicp, (size_t)st.st_size);
832         else {
833                 *magicp = NULL;
834                 *nmagicp = 0;
835         }
836         return -1;
837 }
838
839 /*
840  * handle an mmaped file.
841  */
842 static int
843 apprentice_compile(magicp, nmagicp, fn, action)
844         struct magic **magicp;
845         uint32 *nmagicp;
846         const char *fn;
847         int action;
848 {
849         int fd;
850         char *dbname = mkdbname(fn);
851         static const uint32 ar[] = {
852             MAGICNO, VERSIONNO
853         };
854
855         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
856                 (void)fprintf(stderr, "%s: Cannot open `%s' (%s)\n",
857                     progname, dbname, strerror(errno));
858                 return -1;
859         }
860
861         if (write(fd, ar, sizeof(ar)) != sizeof(ar)) {
862                 (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
863                     progname, dbname, strerror(errno));
864                 return -1;
865         }
866
867         if (lseek(fd, sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
868                 (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n",
869                     progname, dbname, strerror(errno));
870                 return -1;
871         }
872
873         if (write(fd, *magicp,  sizeof(struct magic) * *nmagicp) 
874             != sizeof(struct magic) * *nmagicp) {
875                 (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
876                     progname, dbname, strerror(errno));
877                 return -1;
878         }
879
880         (void)close(fd);
881         return 0;
882 }
883
884 /*
885  * make a dbname
886  */
887 char *
888 mkdbname(fn)
889         const char *fn;
890 {
891         static const char ext[] = ".mgc";
892         static char *buf = NULL;
893         size_t len = strlen(fn) + sizeof(ext) + 1;
894         if (buf == NULL)
895                 buf = malloc(len);
896         else
897                 buf = realloc(buf, len);
898         (void)strcpy(buf, fn);
899         (void)strcat(buf, ext);
900         return buf;
901 }
902
903 /*
904  * Byteswap an mmap'ed file if needed
905  */
906 static void
907 byteswap(magic, nmagic)
908         struct magic *magic;
909         uint32 nmagic;
910 {
911         uint32 i;
912         for (i = 0; i < nmagic; i++)
913                 bs1(&magic[i]);
914 }
915
916 /*
917  * swap a short
918  */
919 static uint16
920 swap2(sv) 
921         uint16 sv;
922 {
923         uint16 rv;
924         uint8 *s = (uint8 *) &sv; 
925         uint8 *d = (uint8 *) &rv; 
926         d[0] = s[1];
927         d[1] = s[0];
928         return rv;
929 }
930
931 /*
932  * swap an int
933  */
934 static uint32
935 swap4(sv) 
936         uint32 sv;
937 {
938         uint32 rv;
939         uint8 *s = (uint8 *) &sv; 
940         uint8 *d = (uint8 *) &rv; 
941         d[0] = s[3];
942         d[1] = s[2];
943         d[2] = s[1];
944         d[3] = s[0];
945         return rv;
946 }
947
948 /*
949  * byteswap a single magic entry
950  */
951 static
952 void bs1(m)
953         struct magic *m;
954 {
955         m->cont_level = swap2(m->cont_level);
956         m->offset = swap4(m->offset);
957         m->in_offset = swap4(m->in_offset);
958         if (m->type != STRING)
959                 m->value.l = swap4(m->value.l);
960         m->mask = swap4(m->mask);
961 }
962 #endif