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