PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/cmd/file/file.c

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