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