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