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