[mq]: file
1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* Copyright (c) 1987, 1988 Microsoft Corporation */ 26 /* All Rights Reserved */ 27 28 /* 29 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 30 * Use is subject to license terms. 31 */ 32 33 /* 34 * Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved. 35 */ 36 37 #define _LARGEFILE64_SOURCE 38 39 /* Get definitions for the relocation types supported. */ 40 #define ELF_TARGET_ALL 41 42 #include <ctype.h> 43 #include <unistd.h> 44 #include <fcntl.h> 45 #include <signal.h> 46 #include <stdio.h> 47 #include <libelf.h> 48 #include <stdlib.h> 49 #include <limits.h> 50 #include <locale.h> 51 #include <wctype.h> 52 #include <string.h> 53 #include <errno.h> 54 #include <door.h> 55 #include <sys/param.h> 56 #include <sys/types.h> 57 #include <sys/mkdev.h> 58 #include <sys/stat.h> 59 #include <sys/elf.h> 60 #include <procfs.h> 61 #include <sys/core.h> 62 #include <sys/dumphdr.h> 63 #include <netinet/in.h> 64 #include <gelf.h> 65 #include <elfcap.h> 66 #include <sgsrtcid.h> 67 #include "file.h" 68 #include "elf_read.h" 69 70 /* 71 * Misc 72 */ 73 74 #define FBSZ 512 75 #define MLIST_SZ 12 76 77 /* 78 * The 0x8FCA0102 magic string was used in crash dumps generated by releases 79 * prior to Solaris 7. 80 */ 81 #define OLD_DUMP_MAGIC 0x8FCA0102 82 83 #if defined(__sparc) 84 #define NATIVE_ISA "SPARC" 85 #define OTHER_ISA "Intel" 86 #else 87 #define NATIVE_ISA "Intel" 88 #define OTHER_ISA "SPARC" 89 #endif 90 91 /* Assembly language comment char */ 92 #ifdef pdp11 93 #define ASCOMCHAR '/' 94 #else 95 #define ASCOMCHAR '!' 96 #endif 97 98 #pragma align 16(fbuf) 99 static char fbuf[FBSZ]; 100 101 /* 102 * Magic file variables 103 */ 104 static intmax_t maxmagicoffset; 105 static intmax_t tmpmax; 106 static char *magicbuf; 107 108 static char *dfile; 109 static char *troff[] = { /* new troff intermediate lang */ 110 "x", "T", "res", "init", "font", "202", "V0", "p1", 0}; 111 112 static char *fort[] = { /* FORTRAN */ 113 "function", "subroutine", "common", "dimension", "block", 114 "integer", "real", "data", "double", 115 "FUNCTION", "SUBROUTINE", "COMMON", "DIMENSION", "BLOCK", 116 "INTEGER", "REAL", "DATA", "DOUBLE", 0}; 117 118 static char *asc[] = { /* Assembler Commands */ 119 "sys", "mov", "tst", "clr", "jmp", "cmp", "set", "inc", 120 "dec", 0}; 121 122 static char *c[] = { /* C Language */ 123 "int", "char", "float", "double", "short", "long", "unsigned", 124 "register", "static", "struct", "extern", 0}; 125 126 static char *as[] = { /* Assembler Pseudo Ops, prepended with '.' */ 127 "globl", "global", "ident", "file", "byte", "even", 128 "text", "data", "bss", "comm", 0}; 129 130 /* 131 * The line and debug section names are used by the strip command. 132 * Any changes in the strip implementation need to be reflected here. 133 */ 134 static char *debug_sections[] = { /* Debug sections in a ELF file */ 135 ".debug", ".stab", ".dwarf", ".line", NULL}; 136 137 /* start for MB env */ 138 static wchar_t wchar; 139 static int length; 140 static int IS_ascii; 141 static int Max; 142 /* end for MB env */ 143 static int i; /* global index into first 'fbsz' bytes of file */ 144 static int fbsz; 145 static int ifd = -1; 146 static int elffd = -1; 147 static int tret; 148 static int sflg; 149 static int hflg; 150 static int dflg; 151 static int mflg; 152 static int M_flg; 153 static int iflg; 154 static struct stat64 mbuf; 155 156 static char **mlist1; /* 1st ordered list of magic files */ 157 static char **mlist2; /* 2nd ordered list of magic files */ 158 static size_t mlist1_sz; /* number of ptrs allocated for mlist1 */ 159 static size_t mlist2_sz; /* number of ptrs allocated for mlist2 */ 160 static char **mlist1p; /* next entry in mlist1 */ 161 static char **mlist2p; /* next entry in mlist2 */ 162 163 static ssize_t mread; 164 165 static void ar_coff_or_aout(int ifd); 166 static int type(char *file); 167 static int def_position_tests(char *file); 168 static void def_context_tests(void); 169 static int troffint(char *bp, int n); 170 static int lookup(char **tab); 171 static int ccom(void); 172 static int ascom(void); 173 static int sccs(void); 174 static int english(char *bp, int n); 175 static int shellscript(char buf[], struct stat64 *sb); 176 static int elf_check(char *file); 177 static int get_door_target(char *, char *, size_t); 178 static int zipfile(char *, int); 179 static int is_crash_dump(const char *, int); 180 static void print_dumphdr(const int, const dumphdr_t *, uint32_t (*)(uint32_t), 181 const char *); 182 static uint32_t swap_uint32(uint32_t); 183 static uint32_t return_uint32(uint32_t); 184 static void usage(void); 185 static void default_magic(void); 186 static void add_to_mlist(char *, int); 187 static void fd_cleanup(void); 188 static int is_rtld_config(void); 189 190 /* from elf_read.c */ 191 int elf_read32(int elffd, Elf_Info *EInfo); 192 int elf_read64(int elffd, Elf_Info *EInfo); 193 194 #ifdef XPG4 195 /* SUSv3 requires a single <space> after the colon */ 196 #define prf(x) (void) printf("%s: ", x); 197 #else /* !XPG4 */ 198 #define prf(x) (void) printf("%s:%s", x, (int)strlen(x) > 6 ? "\t" : "\t\t"); 199 #endif /* XPG4 */ 200 201 /* 202 * Static program identifier - used to prevent localization of the name "file" 203 * within individual error messages. 204 */ 205 const char *File = "file"; 206 207 int 208 main(int argc, char **argv) 209 { 210 char *p; 211 int ch; 212 FILE *fl; 213 int cflg = 0; 214 int eflg = 0; 215 int fflg = 0; 216 char *ap = NULL; 217 int pathlen; 218 char **filep; 219 220 (void) setlocale(LC_ALL, ""); 221 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 222 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 223 #endif 224 (void) textdomain(TEXT_DOMAIN); 225 226 while ((ch = getopt(argc, argv, "M:cdsf:him:")) != EOF) { 227 switch (ch) { 228 229 case 'M': 230 add_to_mlist(optarg, !dflg); 231 M_flg++; 232 break; 233 234 case 'c': 235 cflg++; 236 break; 237 238 case 'd': 239 if (!dflg) { 240 default_magic(); 241 add_to_mlist(dfile, 0); 242 dflg++; 243 } 244 break; 245 246 case 's': 247 sflg++; 248 break; 249 250 case 'f': 251 fflg++; 252 errno = 0; 253 if ((fl = fopen(optarg, "r")) == NULL) { 254 int err = errno; 255 (void) fprintf(stderr, gettext("%s: cannot " 256 "open file %s: %s\n"), File, optarg, 257 err ? strerror(err) : ""); 258 usage(); 259 } 260 pathlen = pathconf("/", _PC_PATH_MAX); 261 if (pathlen == -1) { 262 int err = errno; 263 (void) fprintf(stderr, gettext("%s: cannot " 264 "determine maximum path length: %s\n"), 265 File, strerror(err)); 266 exit(1); 267 } 268 pathlen += 2; /* for null and newline in fgets */ 269 if ((ap = malloc(pathlen * sizeof (char))) == NULL) { 270 int err = errno; 271 (void) fprintf(stderr, gettext("%s: malloc " 272 "failed: %s\n"), File, strerror(err)); 273 exit(2); 274 } 275 break; 276 277 case 'h': 278 hflg++; 279 break; 280 281 case 'i': 282 iflg++; 283 break; 284 285 case 'm': 286 add_to_mlist(optarg, !dflg); 287 mflg++; 288 break; 289 290 case '?': 291 eflg++; 292 break; 293 } 294 } 295 if (!cflg && !fflg && (eflg || optind == argc)) 296 usage(); 297 if (iflg && (dflg || mflg || M_flg)) { 298 usage(); 299 } 300 if (iflg && cflg) { 301 usage(); 302 } 303 if (sflg && (iflg || cflg)) 304 usage(); 305 306 if (!dflg && !mflg && !M_flg && !iflg) { 307 /* no -d, -m, nor -M option; also -i option doesn't need magic */ 308 default_magic(); 309 if (f_mkmtab(dfile, cflg, 0) == -1) { 310 exit(2); 311 } 312 } 313 314 else if (mflg && !M_flg && !dflg) { 315 /* -m specified without -d nor -M */ 316 317 #ifdef XPG4 /* For SUSv3 only */ 318 319 /* 320 * The default position-dependent magic file tests 321 * in /etc/magic will follow all the -m magic tests. 322 */ 323 324 for (filep = mlist1; filep < mlist1p; filep++) { 325 if (f_mkmtab(*filep, cflg, 1) == -1) { 326 exit(2); 327 } 328 } 329 default_magic(); 330 if (f_mkmtab(dfile, cflg, 0) == -1) { 331 exit(2); 332 } 333 #else /* !XPG4 */ 334 /* 335 * Retain Solaris file behavior for -m before SUSv3, 336 * when the new -d and -M options are not specified. 337 * Use the -m file specified in place of the default 338 * /etc/magic file. Solaris file will 339 * now allow more than one magic file to be specified 340 * with multiple -m options, for consistency with 341 * other behavior. 342 * 343 * Put the magic table(s) specified by -m into 344 * the second magic table instead of the first 345 * (as indicated by the last argument to f_mkmtab()), 346 * since they replace the /etc/magic tests and 347 * must be executed alongside the default 348 * position-sensitive tests. 349 */ 350 351 for (filep = mlist1; filep < mlist1p; filep++) { 352 if (f_mkmtab(*filep, cflg, 0) == -1) { 353 exit(2); 354 } 355 } 356 #endif /* XPG4 */ 357 } else { 358 /* 359 * For any other combination of -d, -m, and -M, 360 * use the magic files in command-line order. 361 * Store the entries from the two separate lists of magic 362 * files, if any, into two separate magic file tables. 363 * mlist1: magic tests executed before default magic tests 364 * mlist2: default magic tests and after 365 */ 366 for (filep = mlist1; filep && (filep < mlist1p); filep++) { 367 if (f_mkmtab(*filep, cflg, 1) == -1) { 368 exit(2); 369 } 370 } 371 for (filep = mlist2; filep && (filep < mlist2p); filep++) { 372 if (f_mkmtab(*filep, cflg, 0) == -1) { 373 exit(2); 374 } 375 } 376 } 377 378 /* Initialize the magic file variables; check both magic tables */ 379 tmpmax = f_getmaxoffset(1); 380 maxmagicoffset = f_getmaxoffset(0); 381 if (maxmagicoffset < tmpmax) { 382 maxmagicoffset = tmpmax; 383 } 384 if (maxmagicoffset < (intmax_t)FBSZ) 385 maxmagicoffset = (intmax_t)FBSZ; 386 if ((magicbuf = malloc(maxmagicoffset)) == NULL) { 387 int err = errno; 388 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 389 File, strerror(err)); 390 exit(2); 391 } 392 393 if (cflg) { 394 f_prtmtab(); 395 if (ferror(stdout) != 0) { 396 (void) fprintf(stderr, gettext("%s: error writing to " 397 "stdout\n"), File); 398 exit(1); 399 } 400 if (fclose(stdout) != 0) { 401 int err = errno; 402 (void) fprintf(stderr, gettext("%s: fclose " 403 "failed: %s\n"), File, strerror(err)); 404 exit(1); 405 } 406 exit(0); 407 } 408 409 for (; fflg || optind < argc; optind += !fflg) { 410 register int l; 411 412 if (fflg) { 413 if ((p = fgets(ap, pathlen, fl)) == NULL) { 414 fflg = 0; 415 optind--; 416 continue; 417 } 418 l = strlen(p); 419 if (l > 0) 420 p[l - 1] = '\0'; 421 } else 422 p = argv[optind]; 423 prf(p); /* print "file_name:<tab>" */ 424 425 if (type(p)) 426 tret = 1; 427 } 428 if (ap != NULL) 429 free(ap); 430 if (tret != 0) 431 exit(tret); 432 433 if (ferror(stdout) != 0) { 434 (void) fprintf(stderr, gettext("%s: error writing to " 435 "stdout\n"), File); 436 exit(1); 437 } 438 if (fclose(stdout) != 0) { 439 int err = errno; 440 (void) fprintf(stderr, gettext("%s: fclose failed: %s\n"), 441 File, strerror(err)); 442 exit(1); 443 } 444 return (0); 445 } 446 447 static int 448 type(char *file) 449 { 450 int cc; 451 char buf[BUFSIZ]; 452 int (*statf)() = hflg ? lstat64 : stat64; 453 454 i = 0; /* reset index to beginning of file */ 455 ifd = -1; 456 if ((*statf)(file, &mbuf) < 0) { 457 if (statf == lstat64 || lstat64(file, &mbuf) < 0) { 458 int err = errno; 459 (void) printf(gettext("cannot open: %s\n"), 460 strerror(err)); 461 return (0); /* POSIX.2 */ 462 } 463 } 464 switch (mbuf.st_mode & S_IFMT) { 465 case S_IFREG: 466 if (iflg) { 467 (void) printf(gettext("regular file\n")); 468 return (0); 469 } 470 break; 471 case S_IFCHR: 472 if (sflg) 473 break; 474 (void) printf(gettext("character")); 475 goto spcl; 476 477 case S_IFDIR: 478 (void) printf(gettext("directory\n")); 479 return (0); 480 481 case S_IFIFO: 482 (void) printf(gettext("fifo\n")); 483 return (0); 484 485 case S_IFLNK: 486 if ((cc = readlink(file, buf, BUFSIZ)) < 0) { 487 int err = errno; 488 (void) printf(gettext("readlink error: %s\n"), 489 strerror(err)); 490 return (1); 491 } 492 buf[cc] = '\0'; 493 (void) printf(gettext("symbolic link to %s\n"), buf); 494 return (0); 495 496 case S_IFBLK: 497 if (sflg) 498 break; 499 (void) printf(gettext("block")); 500 /* major and minor, see sys/mkdev.h */ 501 spcl: 502 (void) printf(gettext(" special (%d/%d)\n"), 503 major(mbuf.st_rdev), minor(mbuf.st_rdev)); 504 return (0); 505 506 case S_IFSOCK: 507 (void) printf("socket\n"); 508 /* FIXME, should open and try to getsockname. */ 509 return (0); 510 511 case S_IFDOOR: 512 if (get_door_target(file, buf, sizeof (buf)) == 0) 513 (void) printf(gettext("door to %s\n"), buf); 514 else 515 (void) printf(gettext("door\n")); 516 return (0); 517 518 } 519 520 if (elf_version(EV_CURRENT) == EV_NONE) { 521 (void) printf(gettext("libelf is out of date\n")); 522 return (1); 523 } 524 525 ifd = open64(file, O_RDONLY); 526 if (ifd < 0) { 527 int err = errno; 528 (void) printf(gettext("cannot open: %s\n"), strerror(err)); 529 return (0); /* POSIX.2 */ 530 } 531 532 /* need another fd for elf, since we might want to read the file too */ 533 elffd = open64(file, O_RDONLY); 534 if (elffd < 0) { 535 int err = errno; 536 (void) printf(gettext("cannot open: %s\n"), strerror(err)); 537 (void) close(ifd); 538 ifd = -1; 539 return (0); /* POSIX.2 */ 540 } 541 if ((fbsz = read(ifd, fbuf, FBSZ)) == -1) { 542 int err = errno; 543 (void) printf(gettext("cannot read: %s\n"), strerror(err)); 544 (void) close(ifd); 545 ifd = -1; 546 return (0); /* POSIX.2 */ 547 } 548 if (fbsz == 0) { 549 (void) printf(gettext("empty file\n")); 550 fd_cleanup(); 551 return (0); 552 } 553 554 /* 555 * First try user-specified position-dependent magic tests, if any, 556 * which need to execute before the default tests. 557 */ 558 if ((mread = pread(ifd, (void*)magicbuf, (size_t)maxmagicoffset, 559 (off_t)0)) == -1) { 560 int err = errno; 561 (void) printf(gettext("cannot read: %s\n"), strerror(err)); 562 fd_cleanup(); 563 return (0); 564 } 565 566 /* 567 * ChecK against Magic Table entries. 568 * Check first magic table for magic tests to be applied 569 * before default tests. 570 * If no default tests are to be applied, all magic tests 571 * should occur in this magic table. 572 */ 573 switch (f_ckmtab(magicbuf, mread, 1)) { 574 case -1: /* Error */ 575 exit(2); 576 break; 577 case 0: /* Not magic */ 578 break; 579 default: /* Switch is magic index */ 580 (void) putchar('\n'); 581 fd_cleanup(); 582 return (0); 583 /* NOTREACHED */ 584 break; 585 } 586 587 if (dflg || !M_flg) { 588 /* 589 * default position-dependent tests, 590 * plus non-default magic tests, if any 591 */ 592 switch (def_position_tests(file)) { 593 case -1: /* error */ 594 fd_cleanup(); 595 return (1); 596 case 1: /* matching type found */ 597 fd_cleanup(); 598 return (0); 599 /* NOTREACHED */ 600 break; 601 case 0: /* no matching type found */ 602 break; 603 } 604 /* default context-sensitive tests */ 605 def_context_tests(); 606 } else { 607 /* no more tests to apply; no match was found */ 608 (void) printf(gettext("data\n")); 609 } 610 fd_cleanup(); 611 return (0); 612 } 613 614 /* 615 * def_position_tests() - applies default position-sensitive tests, 616 * looking for values in specific positions in the file. 617 * These are followed by default (followed by possibly some 618 * non-default) magic file tests. 619 * 620 * All position-sensitive tests, default or otherwise, must 621 * be applied before context-sensitive tests, to avoid 622 * false context-sensitive matches. 623 * 624 * Returns -1 on error which should result in error (non-zero) 625 * exit status for the file utility. 626 * Returns 0 if no matching file type found. 627 * Returns 1 if matching file type found. 628 */ 629 630 static int 631 def_position_tests(char *file) 632 { 633 if (sccs()) { /* look for "1hddddd" where d is a digit */ 634 (void) printf("sccs \n"); 635 return (1); 636 } 637 if (fbuf[0] == '#' && fbuf[1] == '!' && shellscript(fbuf+2, &mbuf)) 638 return (1); 639 640 if (elf_check(file) == 0) { 641 (void) putchar('\n'); 642 return (1); 643 /* LINTED: pointer cast may result in improper alignment */ 644 } else if (*(int *)fbuf == CORE_MAGIC) { 645 /* LINTED: pointer cast may result in improper alignment */ 646 struct core *corep = (struct core *)fbuf; 647 648 (void) printf("a.out core file"); 649 650 if (*(corep->c_cmdname) != '\0') 651 (void) printf(" from '%s'", corep->c_cmdname); 652 (void) putchar('\n'); 653 return (1); 654 } 655 656 /* 657 * Runtime linker (ld.so.1) configuration file. 658 */ 659 if (is_rtld_config()) 660 return (1); 661 662 /* 663 * ZIP files, JAR files, and Java executables 664 */ 665 if (zipfile(fbuf, ifd)) 666 return (1); 667 668 if (is_crash_dump(fbuf, ifd)) 669 return (1); 670 671 /* 672 * ChecK against Magic Table entries. 673 * The magic entries checked here always start with default 674 * magic tests and may be followed by other, non-default magic 675 * tests. If no default tests are to be executed, all the 676 * magic tests should have been in the first magic table. 677 */ 678 switch (f_ckmtab(magicbuf, mread, 0)) { 679 case -1: /* Error */ 680 exit(2); 681 break; 682 case 0: /* Not magic */ 683 return (0); 684 /* NOTREACHED */ 685 break; 686 default: /* Switch is magic index */ 687 688 /* 689 * f_ckmtab recognizes file type, 690 * check if it is PostScript. 691 * if not, check if elf or a.out 692 */ 693 if (magicbuf[0] == '%' && magicbuf[1] == '!') { 694 (void) putchar('\n'); 695 } else { 696 697 /* 698 * Check that the file is executable (dynamic 699 * objects must be executable to be exec'ed, 700 * shared objects need not be, but by convention 701 * should be executable). 702 * 703 * Note that we should already have processed 704 * the file if it was an ELF file. 705 */ 706 ar_coff_or_aout(elffd); 707 (void) putchar('\n'); 708 } 709 return (1); 710 /* NOTREACHED */ 711 break; 712 } 713 714 return (0); /* file was not identified */ 715 } 716 717 /* 718 * def_context_tests() - default context-sensitive tests. 719 * These are the last tests to be applied. 720 * If no match is found, prints out "data". 721 */ 722 723 static void 724 def_context_tests(void) 725 { 726 int j; 727 int nl; 728 char ch; 729 int len; 730 731 if (ccom() == 0) 732 goto notc; 733 while (fbuf[i] == '#') { 734 j = i; 735 while (fbuf[i++] != '\n') { 736 if (i - j > 255) { 737 (void) printf(gettext("data\n")); 738 return; 739 } 740 if (i >= fbsz) 741 goto notc; 742 } 743 if (ccom() == 0) 744 goto notc; 745 } 746 check: 747 if (lookup(c) == 1) { 748 while ((ch = fbuf[i]) != ';' && ch != '{') { 749 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 750 len = 1; 751 i += len; 752 if (i >= fbsz) 753 goto notc; 754 } 755 (void) printf(gettext("c program text")); 756 goto outa; 757 } 758 nl = 0; 759 while (fbuf[i] != '(') { 760 if (fbuf[i] <= 0) 761 goto notas; 762 if (fbuf[i] == ';') { 763 i++; 764 goto check; 765 } 766 if (fbuf[i++] == '\n') 767 if (nl++ > 6) 768 goto notc; 769 if (i >= fbsz) 770 goto notc; 771 } 772 while (fbuf[i] != ')') { 773 if (fbuf[i++] == '\n') 774 if (nl++ > 6) 775 goto notc; 776 if (i >= fbsz) 777 goto notc; 778 } 779 while (fbuf[i] != '{') { 780 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 781 len = 1; 782 if (fbuf[i] == '\n') 783 if (nl++ > 6) 784 goto notc; 785 i += len; 786 if (i >= fbsz) 787 goto notc; 788 } 789 (void) printf(gettext("c program text")); 790 goto outa; 791 notc: 792 i = 0; /* reset to begining of file again */ 793 while (fbuf[i] == 'c' || fbuf[i] == 'C'|| fbuf[i] == '!' || 794 fbuf[i] == '*' || fbuf[i] == '\n') { 795 while (fbuf[i++] != '\n') 796 if (i >= fbsz) 797 goto notfort; 798 } 799 if (lookup(fort) == 1) { 800 (void) printf(gettext("fortran program text")); 801 goto outa; 802 } 803 notfort: /* looking for assembler program */ 804 i = 0; /* reset to beginning of file again */ 805 if (ccom() == 0) /* assembler programs may contain */ 806 /* c-style comments */ 807 goto notas; 808 if (ascom() == 0) 809 goto notas; 810 j = i - 1; 811 if (fbuf[i] == '.') { 812 i++; 813 if (lookup(as) == 1) { 814 (void) printf(gettext("assembler program text")); 815 goto outa; 816 } else if (j != -1 && fbuf[j] == '\n' && isalpha(fbuf[j + 2])) { 817 (void) printf( 818 gettext("[nt]roff, tbl, or eqn input text")); 819 goto outa; 820 } 821 } 822 while (lookup(asc) == 0) { 823 if (ccom() == 0) 824 goto notas; 825 if (ascom() == 0) 826 goto notas; 827 while (fbuf[i] != '\n' && fbuf[i++] != ':') { 828 if (i >= fbsz) 829 goto notas; 830 } 831 while (fbuf[i] == '\n' || fbuf[i] == ' ' || fbuf[i] == '\t') 832 if (i++ >= fbsz) 833 goto notas; 834 j = i - 1; 835 if (fbuf[i] == '.') { 836 i++; 837 if (lookup(as) == 1) { 838 (void) printf( 839 gettext("assembler program text")); 840 goto outa; 841 } else if (fbuf[j] == '\n' && isalpha(fbuf[j+2])) { 842 (void) printf( 843 gettext("[nt]roff, tbl, or eqn input " 844 "text")); 845 goto outa; 846 } 847 } 848 } 849 (void) printf(gettext("assembler program text")); 850 goto outa; 851 notas: 852 /* start modification for multibyte env */ 853 IS_ascii = 1; 854 if (fbsz < FBSZ) 855 Max = fbsz; 856 else 857 Max = FBSZ - MB_LEN_MAX; /* prevent cut of wchar read */ 858 /* end modification for multibyte env */ 859 860 for (i = 0; i < Max; /* null */) 861 if (fbuf[i] & 0200) { 862 IS_ascii = 0; 863 if (fbuf[0] == '\100' && fbuf[1] == '\357') { 864 (void) printf(gettext("troff output\n")); 865 return; 866 } 867 /* start modification for multibyte env */ 868 if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX)) 869 <= 0 || !iswprint(wchar)) { 870 (void) printf(gettext("data\n")); 871 return; 872 } 873 i += length; 874 } 875 else 876 i++; 877 i = fbsz; 878 /* end modification for multibyte env */ 879 if (mbuf.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH)) 880 (void) printf(gettext("commands text")); 881 else if (troffint(fbuf, fbsz)) 882 (void) printf(gettext("troff intermediate output text")); 883 else if (english(fbuf, fbsz)) 884 (void) printf(gettext("English text")); 885 else if (IS_ascii) 886 (void) printf(gettext("ascii text")); 887 else 888 (void) printf(gettext("text")); /* for multibyte env */ 889 outa: 890 /* 891 * This code is to make sure that no MB char is cut in half 892 * while still being used. 893 */ 894 fbsz = (fbsz < FBSZ ? fbsz : fbsz - MB_CUR_MAX + 1); 895 while (i < fbsz) { 896 if (isascii(fbuf[i])) { 897 i++; 898 continue; 899 } else { 900 if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX)) 901 <= 0 || !iswprint(wchar)) { 902 (void) printf(gettext(" with garbage\n")); 903 return; 904 } 905 i = i + length; 906 } 907 } 908 (void) printf("\n"); 909 } 910 911 static int 912 troffint(char *bp, int n) 913 { 914 int k; 915 916 i = 0; 917 for (k = 0; k < 6; k++) { 918 if (lookup(troff) == 0) 919 return (0); 920 if (lookup(troff) == 0) 921 return (0); 922 while (i < n && bp[i] != '\n') 923 i++; 924 if (i++ >= n) 925 return (0); 926 } 927 return (1); 928 } 929 930 static void 931 ar_coff_or_aout(int elffd) 932 { 933 Elf *elf; 934 935 /* 936 * Get the files elf descriptor and process it as an elf or 937 * a.out (4.x) file. 938 */ 939 940 elf = elf_begin(elffd, ELF_C_READ, (Elf *)0); 941 switch (elf_kind(elf)) { 942 case ELF_K_AR : 943 (void) printf(gettext(", not a dynamic executable " 944 "or shared object")); 945 break; 946 case ELF_K_COFF: 947 (void) printf(gettext(", unsupported or unknown " 948 "file type")); 949 break; 950 default: 951 /* 952 * This is either an unknown file or an aout format 953 * At this time, we don't print dynamic/stripped 954 * info. on a.out or non-Elf binaries. 955 */ 956 break; 957 } 958 (void) elf_end(elf); 959 } 960 961 962 static void 963 print_elf_type(Elf_Info EI) 964 { 965 switch (EI.type) { 966 case ET_NONE: 967 (void) printf(" %s", gettext("unknown type")); 968 break; 969 case ET_REL: 970 (void) printf(" %s", gettext("relocatable")); 971 break; 972 case ET_EXEC: 973 (void) printf(" %s", gettext("executable")); 974 break; 975 case ET_DYN: 976 (void) printf(" %s", gettext("dynamic lib")); 977 break; 978 default: 979 break; 980 } 981 } 982 983 static void 984 print_elf_machine(int machine) 985 { 986 /* 987 * This table must be kept in sync with the EM_ constants 988 * in /usr/include/sys/elf.h. 989 */ 990 static const char *mach_str[EM_NUM] = { 991 "unknown machine", /* 0 - EM_NONE */ 992 "WE32100", /* 1 - EM_M32 */ 993 "SPARC", /* 2 - EM_SPARC */ 994 "80386", /* 3 - EM_386 */ 995 "M68000", /* 4 - EM_68K */ 996 "M88000", /* 5 - EM_88K */ 997 "80486", /* 6 - EM_486 */ 998 "i860", /* 7 - EM_860 */ 999 "MIPS RS3000 Big-Endian", /* 8 - EM_MIPS */ 1000 "S/370", /* 9 - EM_S370 */ 1001 "MIPS RS3000 Little-Endian", /* 10 - EM_MIPS_RS3_LE */ 1002 "MIPS RS6000", /* 11 - EM_RS6000 */ 1003 NULL, /* 12 - EM_UNKNOWN12 */ 1004 NULL, /* 13 - EM_UNKNOWN13 */ 1005 NULL, /* 14 - EM_UNKNOWN14 */ 1006 "PA-RISC", /* 15 - EM_PA_RISC */ 1007 "nCUBE", /* 16 - EM_nCUBE */ 1008 "VPP500", /* 17 - EM_VPP500 */ 1009 "SPARC32PLUS", /* 18 - EM_SPARC32PLUS */ 1010 "i960", /* 19 - EM_960 */ 1011 "PowerPC", /* 20 - EM_PPC */ 1012 "PowerPC64", /* 21 - EM_PPC64 */ 1013 "S/390", /* 22 - EM_S390 */ 1014 NULL, /* 23 - EM_UNKNOWN23 */ 1015 NULL, /* 24 - EM_UNKNOWN24 */ 1016 NULL, /* 25 - EM_UNKNOWN25 */ 1017 NULL, /* 26 - EM_UNKNOWN26 */ 1018 NULL, /* 27 - EM_UNKNOWN27 */ 1019 NULL, /* 28 - EM_UNKNOWN28 */ 1020 NULL, /* 29 - EM_UNKNOWN29 */ 1021 NULL, /* 30 - EM_UNKNOWN30 */ 1022 NULL, /* 31 - EM_UNKNOWN31 */ 1023 NULL, /* 32 - EM_UNKNOWN32 */ 1024 NULL, /* 33 - EM_UNKNOWN33 */ 1025 NULL, /* 34 - EM_UNKNOWN34 */ 1026 NULL, /* 35 - EM_UNKNOWN35 */ 1027 "V800", /* 36 - EM_V800 */ 1028 "FR20", /* 37 - EM_FR20 */ 1029 "RH32", /* 38 - EM_RH32 */ 1030 "RCE", /* 39 - EM_RCE */ 1031 "ARM", /* 40 - EM_ARM */ 1032 "Alpha", /* 41 - EM_ALPHA */ 1033 "S/390", /* 42 - EM_SH */ 1034 "SPARCV9", /* 43 - EM_SPARCV9 */ 1035 "Tricore", /* 44 - EM_TRICORE */ 1036 "ARC", /* 45 - EM_ARC */ 1037 "H8/300", /* 46 - EM_H8_300 */ 1038 "H8/300H", /* 47 - EM_H8_300H */ 1039 "H8S", /* 48 - EM_H8S */ 1040 "H8/500", /* 49 - EM_H8_500 */ 1041 "IA64", /* 50 - EM_IA_64 */ 1042 "MIPS-X", /* 51 - EM_MIPS_X */ 1043 "Coldfire", /* 52 - EM_COLDFIRE */ 1044 "M68HC12", /* 53 - EM_68HC12 */ 1045 "MMA", /* 54 - EM_MMA */ 1046 "PCP", /* 55 - EM_PCP */ 1047 "nCPU", /* 56 - EM_NCPU */ 1048 "NDR1", /* 57 - EM_NDR1 */ 1049 "Starcore", /* 58 - EM_STARCORE */ 1050 "ME16", /* 59 - EM_ME16 */ 1051 "ST100", /* 60 - EM_ST100 */ 1052 "TINYJ", /* 61 - EM_TINYJ */ 1053 "AMD64", /* 62 - EM_AMD64 */ 1054 "PDSP", /* 63 - EM_PDSP */ 1055 NULL, /* 64 - EM_UNKNOWN64 */ 1056 NULL, /* 65 - EM_UNKNOWN65 */ 1057 "FX66", /* 66 - EM_FX66 */ 1058 "ST9 PLUS", /* 67 - EM_ST9PLUS */ 1059 "ST7", /* 68 - EM_ST7 */ 1060 "68HC16", /* 69 - EM_68HC16 */ 1061 "68HC11", /* 70 - EM_68HC11 */ 1062 "68H08", /* 71 - EM_68HC08 */ 1063 "68HC05", /* 72 - EM_68HC05 */ 1064 "SVX", /* 73 - EM_SVX */ 1065 "ST19", /* 74 - EM_ST19 */ 1066 "VAX", /* 75 - EM_VAX */ 1067 "CRIS", /* 76 - EM_CRIS */ 1068 "Javelin", /* 77 - EM_JAVELIN */ 1069 "Firepath", /* 78 - EM_FIREPATH */ 1070 "ZSP", /* 79 - EM_ZSP */ 1071 "MMIX", /* 80 - EM_MMIX */ 1072 "HUANY", /* 81 - EM_HUANY */ 1073 "Prism", /* 82 - EM_PRISM */ 1074 "AVR", /* 83 - EM_AVR */ 1075 "FR30", /* 84 - EM_FR30 */ 1076 "D10V", /* 85 - EM_D10V */ 1077 "D30V", /* 86 - EM_D30V */ 1078 "V850", /* 87 - EM_V850 */ 1079 "M32R", /* 88 - EM_M32R */ 1080 "MN10300", /* 89 - EM_MN10300 */ 1081 "MN10200", /* 90 - EM_MN10200 */ 1082 "picoJava", /* 91 - EM_PJ */ 1083 "OpenRISC", /* 92 - EM_OPENRISC */ 1084 "Tangent-A5", /* 93 - EM_ARC_A5 */ 1085 "Xtensa" /* 94 - EM_XTENSA */ 1086 }; 1087 /* If new machine is added, refuse to compile until we're updated */ 1088 #if EM_NUM != 95 1089 #error "Number of known ELF machine constants has changed" 1090 #endif 1091 1092 const char *str; 1093 1094 if ((machine < EM_NONE) || (machine >= EM_NUM)) 1095 machine = EM_NONE; 1096 1097 str = mach_str[machine]; 1098 if (str) 1099 (void) printf(" %s", str); 1100 } 1101 1102 static void 1103 print_elf_datatype(int datatype) 1104 { 1105 switch (datatype) { 1106 case ELFDATA2LSB: 1107 (void) printf(" LSB"); 1108 break; 1109 case ELFDATA2MSB: 1110 (void) printf(" MSB"); 1111 break; 1112 default: 1113 break; 1114 } 1115 } 1116 1117 static void 1118 print_elf_class(int class) 1119 { 1120 switch (class) { 1121 case ELFCLASS32: 1122 (void) printf(" %s", gettext("32-bit")); 1123 break; 1124 case ELFCLASS64: 1125 (void) printf(" %s", gettext("64-bit")); 1126 break; 1127 default: 1128 break; 1129 } 1130 } 1131 1132 static void 1133 print_elf_flags(Elf_Info EI) 1134 { 1135 unsigned int flags; 1136 1137 flags = EI.flags; 1138 switch (EI.machine) { 1139 case EM_SPARCV9: 1140 if (flags & EF_SPARC_EXT_MASK) { 1141 if (flags & EF_SPARC_SUN_US3) { 1142 (void) printf("%s", gettext( 1143 ", UltraSPARC3 Extensions Required")); 1144 } else if (flags & EF_SPARC_SUN_US1) { 1145 (void) printf("%s", gettext( 1146 ", UltraSPARC1 Extensions Required")); 1147 } 1148 if (flags & EF_SPARC_HAL_R1) 1149 (void) printf("%s", gettext( 1150 ", HaL R1 Extensions Required")); 1151 } 1152 break; 1153 case EM_SPARC32PLUS: 1154 if (flags & EF_SPARC_32PLUS) 1155 (void) printf("%s", gettext(", V8+ Required")); 1156 if (flags & EF_SPARC_SUN_US3) { 1157 (void) printf("%s", 1158 gettext(", UltraSPARC3 Extensions Required")); 1159 } else if (flags & EF_SPARC_SUN_US1) { 1160 (void) printf("%s", 1161 gettext(", UltraSPARC1 Extensions Required")); 1162 } 1163 if (flags & EF_SPARC_HAL_R1) 1164 (void) printf("%s", 1165 gettext(", HaL R1 Extensions Required")); 1166 break; 1167 default: 1168 break; 1169 } 1170 } 1171 1172 /* 1173 * check_ident: checks the ident field of the presumeably 1174 * elf file. If check fails, this is not an 1175 * elf file. 1176 */ 1177 static int 1178 check_ident(unsigned char *ident, int fd) 1179 { 1180 int class; 1181 if (pread64(fd, ident, EI_NIDENT, 0) != EI_NIDENT) 1182 return (ELF_READ_FAIL); 1183 class = ident[EI_CLASS]; 1184 if (class != ELFCLASS32 && class != ELFCLASS64) 1185 return (ELF_READ_FAIL); 1186 if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 1187 ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) 1188 return (ELF_READ_FAIL); 1189 1190 return (ELF_READ_OKAY); 1191 } 1192 1193 static int 1194 elf_check(char *file) 1195 { 1196 Elf_Info EInfo; 1197 int class, version, format; 1198 unsigned char ident[EI_NIDENT]; 1199 1200 (void) memset(&EInfo, 0, sizeof (Elf_Info)); 1201 EInfo.file = file; 1202 1203 /* 1204 * Verify information in file indentifier. 1205 * Return quietly if not elf; Different type of file. 1206 */ 1207 if (check_ident(ident, elffd) == ELF_READ_FAIL) 1208 return (1); 1209 1210 /* 1211 * Read the elf headers for processing and get the 1212 * get the needed information in Elf_Info struct. 1213 */ 1214 class = ident[EI_CLASS]; 1215 if (class == ELFCLASS32) { 1216 if (elf_read32(elffd, &EInfo) == ELF_READ_FAIL) { 1217 (void) fprintf(stderr, gettext("%s: %s: can't " 1218 "read ELF header\n"), File, file); 1219 return (1); 1220 } 1221 } else if (class == ELFCLASS64) { 1222 if (elf_read64(elffd, &EInfo) == ELF_READ_FAIL) { 1223 (void) fprintf(stderr, gettext("%s: %s: can't " 1224 "read ELF header\n"), File, file); 1225 return (1); 1226 } 1227 } else { 1228 /* something wrong */ 1229 return (1); 1230 } 1231 1232 /* version not in ident then 1 */ 1233 version = ident[EI_VERSION] ? ident[EI_VERSION] : 1; 1234 1235 format = ident[EI_DATA]; 1236 (void) printf("%s", gettext("ELF")); 1237 print_elf_class(class); 1238 print_elf_datatype(format); 1239 print_elf_type(EInfo); 1240 1241 if (EInfo.core_type != EC_NOTCORE) { 1242 /* Print what kind of core is this */ 1243 if (EInfo.core_type == EC_OLDCORE) 1244 (void) printf(" %s", gettext("pre-2.6 core file")); 1245 else 1246 (void) printf(" %s", gettext("core file")); 1247 } 1248 1249 /* Print machine info */ 1250 print_elf_machine(EInfo.machine); 1251 1252 /* Print Version */ 1253 if (version == 1) 1254 (void) printf(" %s %d", gettext("Version"), version); 1255 1256 /* Print Flags */ 1257 print_elf_flags(EInfo); 1258 1259 /* Last bit, if it is a core */ 1260 if (EInfo.core_type != EC_NOTCORE) { 1261 /* Print the program name that dumped this core */ 1262 (void) printf(gettext(", from '%s'"), EInfo.fname); 1263 return (0); 1264 } 1265 1266 /* Print Capabilities */ 1267 if (EInfo.cap_str[0] != '\0') 1268 (void) printf(" [%s]", EInfo.cap_str); 1269 1270 if ((EInfo.type != ET_EXEC) && (EInfo.type != ET_DYN)) 1271 return (0); 1272 1273 /* Print if it is dynamically linked */ 1274 if (EInfo.dynamic) 1275 (void) printf(gettext(", dynamically linked")); 1276 else 1277 (void) printf(gettext(", statically linked")); 1278 1279 /* Printf it it is stripped */ 1280 if (EInfo.stripped & E_SYMTAB) { 1281 (void) printf(gettext(", not stripped")); 1282 if (!(EInfo.stripped & E_DBGINF)) { 1283 (void) printf(gettext( 1284 ", no debugging information available")); 1285 } 1286 } else { 1287 (void) printf(gettext(", stripped")); 1288 } 1289 1290 return (0); 1291 } 1292 1293 /* 1294 * is_rtld_config - If file is a runtime linker config file, prints 1295 * the description and returns True (1). Otherwise, silently returns 1296 * False (0). 1297 */ 1298 int 1299 is_rtld_config(void) 1300 { 1301 Rtc_id *id; 1302 1303 if ((fbsz >= sizeof (*id)) && RTC_ID_TEST(fbuf)) { 1304 (void) printf(gettext("Runtime Linking Configuration")); 1305 id = (Rtc_id *) fbuf; 1306 print_elf_class(id->id_class); 1307 print_elf_datatype(id->id_data); 1308 print_elf_machine(id->id_machine); 1309 (void) printf("\n"); 1310 return (1); 1311 } 1312 1313 return (0); 1314 } 1315 1316 /* 1317 * lookup - 1318 * Attempts to match one of the strings from a list, 'tab', 1319 * with what is in the file, starting at the current index position 'i'. 1320 * Looks past any initial whitespace and expects whitespace or other 1321 * delimiting characters to follow the matched string. 1322 * A match identifies the file as being 'assembler', 'fortran', 'c', etc. 1323 * Returns 1 for a successful match, 0 otherwise. 1324 */ 1325 static int 1326 lookup(char **tab) 1327 { 1328 register char r; 1329 register int k, j, l; 1330 1331 while (fbuf[i] == ' ' || fbuf[i] == '\t' || fbuf[i] == '\n') 1332 i++; 1333 for (j = 0; tab[j] != 0; j++) { 1334 l = 0; 1335 for (k = i; ((r = tab[j][l++]) == fbuf[k] && r != '\0'); k++) 1336 ; 1337 if (r == '\0') 1338 if (fbuf[k] == ' ' || fbuf[k] == '\n' || 1339 fbuf[k] == '\t' || fbuf[k] == '{' || 1340 fbuf[k] == '/') { 1341 i = k; 1342 return (1); 1343 } 1344 } 1345 return (0); 1346 } 1347 1348 /* 1349 * ccom - 1350 * Increments the current index 'i' into the file buffer 'fbuf' past any 1351 * whitespace lines and C-style comments found, starting at the current 1352 * position of 'i'. Returns 1 as long as we don't increment i past the 1353 * size of fbuf (fbsz). Otherwise, returns 0. 1354 */ 1355 1356 static int 1357 ccom(void) 1358 { 1359 register char cc; 1360 int len; 1361 1362 while ((cc = fbuf[i]) == ' ' || cc == '\t' || cc == '\n') 1363 if (i++ >= fbsz) 1364 return (0); 1365 if (fbuf[i] == '/' && fbuf[i+1] == '*') { 1366 i += 2; 1367 while (fbuf[i] != '*' || fbuf[i+1] != '/') { 1368 if (fbuf[i] == '\\') 1369 i++; 1370 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 1371 len = 1; 1372 i += len; 1373 if (i >= fbsz) 1374 return (0); 1375 } 1376 if ((i += 2) >= fbsz) 1377 return (0); 1378 } 1379 if (fbuf[i] == '\n') 1380 if (ccom() == 0) 1381 return (0); 1382 return (1); 1383 } 1384 1385 /* 1386 * ascom - 1387 * Increments the current index 'i' into the file buffer 'fbuf' past 1388 * consecutive assembler program comment lines starting with ASCOMCHAR, 1389 * starting at the current position of 'i'. 1390 * Returns 1 as long as we don't increment i past the 1391 * size of fbuf (fbsz). Otherwise returns 0. 1392 */ 1393 1394 static int 1395 ascom(void) 1396 { 1397 while (fbuf[i] == ASCOMCHAR) { 1398 i++; 1399 while (fbuf[i++] != '\n') 1400 if (i >= fbsz) 1401 return (0); 1402 while (fbuf[i] == '\n') 1403 if (i++ >= fbsz) 1404 return (0); 1405 } 1406 return (1); 1407 } 1408 1409 static int 1410 sccs(void) 1411 { /* look for "1hddddd" where d is a digit */ 1412 register int j; 1413 1414 if (fbuf[0] == 1 && fbuf[1] == 'h') { 1415 for (j = 2; j <= 6; j++) { 1416 if (isdigit(fbuf[j])) 1417 continue; 1418 else 1419 return (0); 1420 } 1421 } else { 1422 return (0); 1423 } 1424 return (1); 1425 } 1426 1427 static int 1428 english(char *bp, int n) 1429 { 1430 #define NASC 128 /* number of ascii char ?? */ 1431 register int j, vow, freq, rare, len; 1432 register int badpun = 0, punct = 0; 1433 int ct[NASC]; 1434 1435 if (n < 50) 1436 return (0); /* no point in statistics on squibs */ 1437 for (j = 0; j < NASC; j++) 1438 ct[j] = 0; 1439 for (j = 0; j < n; j += len) { 1440 if ((unsigned char)bp[j] < NASC) 1441 ct[bp[j]|040]++; 1442 switch (bp[j]) { 1443 case '.': 1444 case ',': 1445 case ')': 1446 case '%': 1447 case ';': 1448 case ':': 1449 case '?': 1450 punct++; 1451 if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n') 1452 badpun++; 1453 } 1454 if ((len = mblen(&bp[j], MB_CUR_MAX)) <= 0) 1455 len = 1; 1456 } 1457 if (badpun*5 > punct) 1458 return (0); 1459 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 1460 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 1461 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 1462 if (2*ct[';'] > ct['e']) 1463 return (0); 1464 if ((ct['>'] + ct['<'] + ct['/']) > ct['e']) 1465 return (0); /* shell file test */ 1466 return (vow * 5 >= n - ct[' '] && freq >= 10 * rare); 1467 } 1468 1469 1470 static int 1471 shellscript(char buf[], struct stat64 *sb) 1472 { 1473 char *tp, *cp, *xp, *up, *gp; 1474 1475 cp = strchr(buf, '\n'); 1476 if (cp == NULL || cp - fbuf > fbsz) 1477 return (0); 1478 for (tp = buf; tp != cp && isspace((unsigned char)*tp); tp++) 1479 if (!isascii(*tp)) 1480 return (0); 1481 for (xp = tp; tp != cp && !isspace((unsigned char)*tp); tp++) 1482 if (!isascii(*tp)) 1483 return (0); 1484 if (tp == xp) 1485 return (0); 1486 if (sb->st_mode & S_ISUID) 1487 up = gettext("set-uid "); 1488 else 1489 up = ""; 1490 1491 if (sb->st_mode & S_ISGID) 1492 gp = gettext("set-gid "); 1493 else 1494 gp = ""; 1495 1496 if (strncmp(xp, "/bin/sh", tp - xp) == 0) 1497 xp = gettext("shell"); 1498 else if (strncmp(xp, "/bin/csh", tp - xp) == 0) 1499 xp = gettext("c-shell"); 1500 else if (strncmp(xp, "/usr/sbin/dtrace", tp - xp) == 0) 1501 xp = gettext("DTrace"); 1502 else 1503 *tp = '\0'; 1504 /* 1505 * TRANSLATION_NOTE 1506 * This message is printed by file command for shell scripts. 1507 * The first %s is for the translation for "set-uid " (if the script 1508 * has the set-uid bit set), or is for an empty string (if the 1509 * script does not have the set-uid bit set). 1510 * Similarly, the second %s is for the translation for "set-gid ", 1511 * or is for an empty string. 1512 * The third %s is for the translation for either: "shell", "c-shell", 1513 * or "DTrace", or is for the pathname of the program the script 1514 * executes. 1515 */ 1516 (void) printf(gettext("%s%sexecutable %s script\n"), up, gp, xp); 1517 return (1); 1518 } 1519 1520 static int 1521 get_door_target(char *file, char *buf, size_t bufsize) 1522 { 1523 int fd; 1524 door_info_t di; 1525 psinfo_t psinfo; 1526 1527 if ((fd = open64(file, O_RDONLY)) < 0 || 1528 door_info(fd, &di) != 0) { 1529 if (fd >= 0) 1530 (void) close(fd); 1531 return (-1); 1532 } 1533 (void) close(fd); 1534 1535 (void) sprintf(buf, "/proc/%ld/psinfo", di.di_target); 1536 if ((fd = open64(buf, O_RDONLY)) < 0 || 1537 read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) { 1538 if (fd >= 0) 1539 (void) close(fd); 1540 return (-1); 1541 } 1542 (void) close(fd); 1543 1544 (void) snprintf(buf, bufsize, "%s[%ld]", psinfo.pr_fname, di.di_target); 1545 return (0); 1546 } 1547 1548 /* 1549 * ZIP file header information 1550 */ 1551 #define SIGSIZ 4 1552 #define LOCSIG "PK\003\004" 1553 #define LOCHDRSIZ 30 1554 1555 #define CH(b, n) (((unsigned char *)(b))[n]) 1556 #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) 1557 #define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) 1558 1559 #define LOCNAM(b) (SH(b, 26)) /* filename size */ 1560 #define LOCEXT(b) (SH(b, 28)) /* extra field size */ 1561 1562 #define XFHSIZ 4 /* header id, data size */ 1563 #define XFHID(b) (SH(b, 0)) /* extract field header id */ 1564 #define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */ 1565 #define XFJAVASIG 0xcafe /* java executables */ 1566 1567 static int 1568 zipfile(char *fbuf, int fd) 1569 { 1570 off_t xoff, xoff_end; 1571 1572 if (strncmp(fbuf, LOCSIG, SIGSIZ) != 0) 1573 return (0); 1574 1575 xoff = LOCHDRSIZ + LOCNAM(fbuf); 1576 xoff_end = xoff + LOCEXT(fbuf); 1577 1578 while (xoff < xoff_end) { 1579 char xfhdr[XFHSIZ]; 1580 1581 if (pread(fd, xfhdr, XFHSIZ, xoff) != XFHSIZ) 1582 break; 1583 1584 if (XFHID(xfhdr) == XFJAVASIG) { 1585 (void) printf("%s\n", gettext("java archive file")); 1586 return (1); 1587 } 1588 xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr); 1589 } 1590 1591 /* 1592 * We could just print "ZIP archive" here. 1593 * 1594 * However, customers may be using their own entries in 1595 * /etc/magic to distinguish one kind of ZIP file from another, so 1596 * let's defer the printing of "ZIP archive" to there. 1597 */ 1598 return (0); 1599 } 1600 1601 static int 1602 is_crash_dump(const char *buf, int fd) 1603 { 1604 /* LINTED: pointer cast may result in improper alignment */ 1605 const dumphdr_t *dhp = (const dumphdr_t *)buf; 1606 1607 /* 1608 * The current DUMP_MAGIC string covers Solaris 7 and later releases. 1609 * The utsname struct is only present in dumphdr_t's with dump_version 1610 * greater than or equal to 9. 1611 */ 1612 if (dhp->dump_magic == DUMP_MAGIC) { 1613 print_dumphdr(fd, dhp, return_uint32, NATIVE_ISA); 1614 1615 } else if (dhp->dump_magic == swap_uint32(DUMP_MAGIC)) { 1616 print_dumphdr(fd, dhp, swap_uint32, OTHER_ISA); 1617 1618 } else if (dhp->dump_magic == OLD_DUMP_MAGIC || 1619 dhp->dump_magic == swap_uint32(OLD_DUMP_MAGIC)) { 1620 char *isa = (dhp->dump_magic == OLD_DUMP_MAGIC ? 1621 NATIVE_ISA : OTHER_ISA); 1622 (void) printf(gettext("SunOS 32-bit %s crash dump\n"), isa); 1623 1624 } else { 1625 return (0); 1626 } 1627 1628 return (1); 1629 } 1630 1631 static void 1632 print_dumphdr(const int fd, const dumphdr_t *dhp, uint32_t (*swap)(uint32_t), 1633 const char *isa) 1634 { 1635 dumphdr_t dh; 1636 1637 /* 1638 * A dumphdr_t is bigger than FBSZ, so we have to manually read the 1639 * rest of it. 1640 */ 1641 if (swap(dhp->dump_version) > 8 && pread(fd, &dh, sizeof (dumphdr_t), 1642 (off_t)0) == sizeof (dumphdr_t)) { 1643 const char *c = swap(dh.dump_flags) & DF_COMPRESSED ? 1644 "compressed " : ""; 1645 const char *l = swap(dh.dump_flags) & DF_LIVE ? 1646 "live" : "crash"; 1647 1648 (void) printf(gettext( 1649 "%s %s %s %u-bit %s %s%s dump from '%s'\n"), 1650 dh.dump_utsname.sysname, dh.dump_utsname.release, 1651 dh.dump_utsname.version, swap(dh.dump_wordsize), isa, 1652 c, l, dh.dump_utsname.nodename); 1653 } else { 1654 (void) printf(gettext("SunOS %u-bit %s crash dump\n"), 1655 swap(dhp->dump_wordsize), isa); 1656 } 1657 } 1658 1659 static void 1660 usage(void) 1661 { 1662 (void) fprintf(stderr, gettext( 1663 "usage: file [-dhs] [-M mfile] [-m mfile] [-f ffile] file ...\n" 1664 " file [-dhs] [-M mfile] [-m mfile] -f ffile\n" 1665 " file -i [-h] [-f ffile] file ...\n" 1666 " file -i [-h] -f ffile\n" 1667 " file -c [-d] [-M mfile] [-m mfile]\n")); 1668 exit(2); 1669 } 1670 1671 static uint32_t 1672 swap_uint32(uint32_t in) 1673 { 1674 uint32_t out; 1675 1676 out = (in & 0x000000ff) << 24; 1677 out |= (in & 0x0000ff00) << 8; /* >> 8 << 16 */ 1678 out |= (in & 0x00ff0000) >> 8; /* >> 16 << 8 */ 1679 out |= (in & 0xff000000) >> 24; 1680 1681 return (out); 1682 } 1683 1684 static uint32_t 1685 return_uint32(uint32_t in) 1686 { 1687 return (in); 1688 } 1689 1690 /* 1691 * Check if str is in the string list str_list. 1692 */ 1693 int 1694 is_in_list(char *str) 1695 { 1696 int i; 1697 1698 /* 1699 * Only need to compare the strlen(str_list[i]) bytes. 1700 * That way .stab will match on .stab* sections, and 1701 * .debug will match on .debug* sections. 1702 */ 1703 for (i = 0; debug_sections[i] != NULL; i++) { 1704 if (strncmp(debug_sections[i], str, 1705 strlen(debug_sections[i])) == 0) { 1706 return (1); 1707 } 1708 } 1709 return (0); 1710 } 1711 1712 /* 1713 * default_magic - 1714 * allocate space for and create the default magic file 1715 * name string. 1716 */ 1717 1718 static void 1719 default_magic(void) 1720 { 1721 const char *msg_locale = setlocale(LC_MESSAGES, NULL); 1722 struct stat statbuf; 1723 1724 if ((dfile = malloc(strlen(msg_locale) + 35)) == NULL) { 1725 int err = errno; 1726 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1727 File, strerror(err)); 1728 exit(2); 1729 } 1730 (void) snprintf(dfile, strlen(msg_locale) + 35, 1731 "/usr/lib/locale/%s/LC_MESSAGES/magic", msg_locale); 1732 if (stat(dfile, &statbuf) != 0) { 1733 (void) strcpy(dfile, "/etc/magic"); 1734 } 1735 } 1736 1737 /* 1738 * add_to_mlist - 1739 * Add the given magic_file filename string to the list of magic 1740 * files (mlist). This list of files will later be examined, and 1741 * each magic file's entries will be added in order to 1742 * the mtab table. 1743 * 1744 * The first flag is set to 1 to add to the first list, mlist1. 1745 * The first flag is set to 0 to add to the second list, mlist2. 1746 */ 1747 1748 static void 1749 add_to_mlist(char *magic_file, int first) 1750 { 1751 char **mlist; /* ordered list of magic files */ 1752 size_t mlist_sz; /* number of pointers allocated for mlist */ 1753 char **mlistp; /* next entry in mlist */ 1754 size_t mlistp_off; 1755 1756 if (first) { 1757 mlist = mlist1; 1758 mlist_sz = mlist1_sz; 1759 mlistp = mlist1p; 1760 } else { 1761 mlist = mlist2; 1762 mlist_sz = mlist2_sz; 1763 mlistp = mlist2p; 1764 } 1765 1766 if (mlist == NULL) { /* initial mlist allocation */ 1767 if ((mlist = calloc(MLIST_SZ, sizeof (char *))) == NULL) { 1768 int err = errno; 1769 (void) fprintf(stderr, gettext("%s: malloc " 1770 "failed: %s\n"), File, strerror(err)); 1771 exit(2); 1772 } 1773 mlist_sz = MLIST_SZ; 1774 mlistp = mlist; 1775 } 1776 if ((mlistp - mlist) >= mlist_sz) { 1777 mlistp_off = mlistp - mlist; 1778 mlist_sz *= 2; 1779 if ((mlist = realloc(mlist, 1780 mlist_sz * sizeof (char *))) == NULL) { 1781 int err = errno; 1782 (void) fprintf(stderr, gettext("%s: malloc " 1783 "failed: %s\n"), File, strerror(err)); 1784 exit(2); 1785 } 1786 mlistp = mlist + mlistp_off; 1787 } 1788 /* 1789 * now allocate memory for and copy the 1790 * magic file name string 1791 */ 1792 if ((*mlistp = malloc(strlen(magic_file) + 1)) == NULL) { 1793 int err = errno; 1794 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1795 File, strerror(err)); 1796 exit(2); 1797 } 1798 (void) strlcpy(*mlistp, magic_file, strlen(magic_file) + 1); 1799 mlistp++; 1800 1801 if (first) { 1802 mlist1 = mlist; 1803 mlist1_sz = mlist_sz; 1804 mlist1p = mlistp; 1805 } else { 1806 mlist2 = mlist; 1807 mlist2_sz = mlist_sz; 1808 mlist2p = mlistp; 1809 } 1810 } 1811 1812 static void 1813 fd_cleanup(void) 1814 { 1815 if (ifd != -1) { 1816 (void) close(ifd); 1817 ifd = -1; 1818 } 1819 if (elffd != -1) { 1820 (void) close(elffd); 1821 elffd = -1; 1822 } 1823 } --- EOF ---