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