file.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /*
  2. * file - find type of a file or files - main program.
  3. *
  4. * Copyright (c) Ian F. Darwin, 1987.
  5. * Written by Ian F. Darwin.
  6. *
  7. * This software is not subject to any license of the American Telephone
  8. * and Telegraph Company or of the Regents of the University of California.
  9. *
  10. * Permission is granted to anyone to use this software for any purpose on
  11. * any computer system, and to alter it and redistribute it freely, subject
  12. * to the following restrictions:
  13. *
  14. * 1. The author is not responsible for the consequences of use of this
  15. * software, no matter how awful, even if they arise from flaws in it.
  16. *
  17. * 2. The origin of this software must not be misrepresented, either by
  18. * explicit claim or by omission. Since few users ever read sources,
  19. * credits must appear in the documentation.
  20. *
  21. * 3. Altered versions must be plainly marked as such, and must not be
  22. * misrepresented as being the original software. Since few users
  23. * ever read sources, credits must appear in the documentation.
  24. *
  25. * 4. This notice may not be removed or altered.
  26. */
  27. #include "file.h"
  28. #ifdef __CYGWIN__
  29. #include <errno.h>
  30. #endif
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/types.h>
  35. #include <sys/param.h> /* for MAXPATHLEN */
  36. #include <sys/stat.h>
  37. #include <fcntl.h> /* for open() */
  38. #ifdef RESTORE_TIME
  39. # if (__COHERENT__ >= 0x420)
  40. # include <sys/utime.h>
  41. # else
  42. # ifdef USE_UTIMES
  43. # include <sys/time.h>
  44. # else
  45. # include <utime.h>
  46. # endif
  47. # endif
  48. #endif
  49. #ifdef HAVE_UNISTD_H
  50. #include <unistd.h> /* for read() */
  51. #endif
  52. #include <getopt.h> /* for long options (is this portable?)*/
  53. #include <netinet/in.h> /* for byte swapping */
  54. #include "patchlevel.h"
  55. #ifndef lint
  56. FILE_RCSID("@(#)$Id: file.c,v 1.47 1999/10/31 22:23:03 christos Exp $")
  57. #endif /* lint */
  58. #ifdef S_IFLNK
  59. # define USAGE "Usage: %s [-bcnvzL] [-f namefile] [-m magicfiles] file...\n"
  60. #else
  61. # define USAGE "Usage: %s [-bcnvz] [-f namefile] [-m magicfiles] file...\n"
  62. #endif
  63. #ifndef MAGIC
  64. # define MAGIC "/etc/magic"
  65. #endif
  66. #ifndef MAXPATHLEN
  67. #define MAXPATHLEN 512
  68. #endif
  69. int /* Global command-line options */
  70. debug = 0, /* debugging */
  71. lflag = 0, /* follow Symlinks (BSD only) */
  72. bflag = 0, /* brief output format */
  73. zflag = 0, /* follow (uncompress) compressed files */
  74. sflag = 0, /* read block special files */
  75. nobuffer = 0; /* Do not buffer stdout */
  76. int /* Misc globals */
  77. nmagic = 0; /* number of valid magic[]s */
  78. struct magic *magic; /* array of magic entries */
  79. const char *magicfile; /* where magic be found */
  80. char *progname; /* used throughout */
  81. int lineno; /* line number in the magic file */
  82. static void unwrap __P((char *fn));
  83. #if 0
  84. static int byteconv4 __P((int, int, int));
  85. static short byteconv2 __P((int, int, int));
  86. #endif
  87. int main __P((int, char *[]));
  88. void help()
  89. {
  90. puts(
  91. "Usage: file [OPTION]... [FILE]...
  92. Determine file type of FILEs.
  93. -m, --magic-file LIST use LIST as a colon-separated list of magic
  94. number files
  95. -z, --uncompress try to look inside compressed files
  96. -b, --brief do not prepend filenames to output lines
  97. -c, --checking-printout print the parsed form of the magic file, use in
  98. conjunction with -m to debug a new magic file
  99. before installing it
  100. -f, --files-from FILE read the filenames to be examined from FILE
  101. -L, --dereference causes symlinks to be followed
  102. -n, --no-buffer do not buffer output
  103. -s, --special-files treat special (block/char devices) files as
  104. ordinary ones
  105. --help display this help and exit
  106. --version output version information and exit");
  107. exit(0);
  108. }
  109. /*
  110. * main - parse arguments and handle options
  111. */
  112. int
  113. main(argc, argv)
  114. int argc;
  115. char *argv[];
  116. {
  117. int c,longindex;
  118. int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
  119. static struct option long_options[] =
  120. {
  121. {"version", 0, 0, 'v'},
  122. {"help", 0, 0, 0},
  123. {"brief", 0, 0, 'b'},
  124. {"checking-printout", 0, 0, 'c'},
  125. {"debug", 0, 0, 'd'},
  126. {"files-from", 1, 0, 'f'},
  127. #ifdef S_IFLNK
  128. {"dereference", 0, 0, 'L'},
  129. #endif
  130. {"magic-file", 1, 0, 'm'},
  131. {"uncompress", 0, 0, 'z'},
  132. {"no-buffer", 0, 0, 'n'},
  133. {"special-files", 0, 0, 's'},
  134. {0, 0, 0, 0},
  135. };
  136. if ((progname = strrchr(argv[0], '/')) != NULL)
  137. progname++;
  138. else
  139. progname = argv[0];
  140. if (!(magicfile = getenv("MAGIC")))
  141. magicfile = MAGIC;
  142. while ((c = getopt_long(argc, argv, "bcdnf:m:svzL",long_options,&longindex)) != EOF)
  143. switch (c) {
  144. case 0 :
  145. if (longindex==1)
  146. help();
  147. break;
  148. case 'v':
  149. (void) fprintf(stdout, "%s-"VERSION"\n", progname);
  150. (void) fprintf(stdout, "magic data from %s\n",
  151. magicfile);
  152. return 1;
  153. case 'b':
  154. ++bflag;
  155. break;
  156. case 'c':
  157. ++check;
  158. break;
  159. case 'n':
  160. ++nobuffer;
  161. break;
  162. case 'd':
  163. ++debug;
  164. break;
  165. case 'f':
  166. if (!app) {
  167. ret = apprentice(magicfile, check);
  168. if (check)
  169. exit(ret);
  170. app = 1;
  171. }
  172. unwrap(optarg);
  173. ++didsomefiles;
  174. break;
  175. #ifdef S_IFLNK
  176. case 'L':
  177. ++lflag;
  178. break;
  179. #endif
  180. case 'm':
  181. magicfile = optarg;
  182. break;
  183. case 'z':
  184. zflag++;
  185. break;
  186. case 's':
  187. sflag++;
  188. break;
  189. case '?':
  190. default:
  191. errflg++;
  192. break;
  193. }
  194. if (errflg) {
  195. (void) fprintf(stderr, USAGE, progname);
  196. fputs("Try `file --help' for more information.\n",stderr);
  197. exit(2);
  198. }
  199. if (!app) {
  200. ret = apprentice(magicfile, check);
  201. if (check)
  202. exit(ret);
  203. app = 1;
  204. }
  205. if (optind == argc) {
  206. if (!didsomefiles) {
  207. (void)fprintf(stderr, USAGE, progname);
  208. exit(2);
  209. }
  210. }
  211. else {
  212. int i, wid, nw;
  213. for (wid = 0, i = optind; i < argc; i++) {
  214. nw = strlen(argv[i]);
  215. if (nw > wid)
  216. wid = nw;
  217. }
  218. for (; optind < argc; optind++)
  219. process(argv[optind], wid);
  220. }
  221. return 0;
  222. }
  223. /*
  224. * unwrap -- read a file of filenames, do each one.
  225. */
  226. static void
  227. unwrap(fn)
  228. char *fn;
  229. {
  230. char buf[MAXPATHLEN];
  231. FILE *f;
  232. int wid = 0, cwid;
  233. if (strcmp("-", fn) == 0) {
  234. f = stdin;
  235. wid = 1;
  236. } else {
  237. if ((f = fopen(fn, "r")) == NULL) {
  238. error("Cannot open `%s' (%m).\n", fn);
  239. /*NOTREACHED*/
  240. }
  241. while (fgets(buf, MAXPATHLEN, f) != NULL) {
  242. cwid = strlen(buf) - 1;
  243. if (cwid > wid)
  244. wid = cwid;
  245. }
  246. rewind(f);
  247. }
  248. while (fgets(buf, MAXPATHLEN, f) != NULL) {
  249. buf[strlen(buf)-1] = '\0';
  250. process(buf, wid);
  251. if(nobuffer)
  252. (void) fflush(stdout);
  253. }
  254. (void) fclose(f);
  255. }
  256. #if 0
  257. /*
  258. * byteconv4
  259. * Input:
  260. * from 4 byte quantity to convert
  261. * same whether to perform byte swapping
  262. * big_endian whether we are a big endian host
  263. */
  264. static int
  265. byteconv4(from, same, big_endian)
  266. int from;
  267. int same;
  268. int big_endian;
  269. {
  270. if (same)
  271. return from;
  272. else if (big_endian) /* lsb -> msb conversion on msb */
  273. {
  274. union {
  275. int i;
  276. char c[4];
  277. } retval, tmpval;
  278. tmpval.i = from;
  279. retval.c[0] = tmpval.c[3];
  280. retval.c[1] = tmpval.c[2];
  281. retval.c[2] = tmpval.c[1];
  282. retval.c[3] = tmpval.c[0];
  283. return retval.i;
  284. }
  285. else
  286. return ntohl(from); /* msb -> lsb conversion on lsb */
  287. }
  288. /*
  289. * byteconv2
  290. * Same as byteconv4, but for shorts
  291. */
  292. static short
  293. byteconv2(from, same, big_endian)
  294. int from;
  295. int same;
  296. int big_endian;
  297. {
  298. if (same)
  299. return from;
  300. else if (big_endian) /* lsb -> msb conversion on msb */
  301. {
  302. union {
  303. short s;
  304. char c[2];
  305. } retval, tmpval;
  306. tmpval.s = (short) from;
  307. retval.c[0] = tmpval.c[1];
  308. retval.c[1] = tmpval.c[0];
  309. return retval.s;
  310. }
  311. else
  312. return ntohs(from); /* msb -> lsb conversion on lsb */
  313. }
  314. #endif
  315. /*
  316. * process - process input file
  317. */
  318. void
  319. process(inname, wid)
  320. const char *inname;
  321. int wid;
  322. {
  323. int fd = 0;
  324. static const char stdname[] = "standard input";
  325. unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
  326. struct stat sb;
  327. int nbytes = 0; /* number of bytes read from a datafile */
  328. char match = '\0';
  329. if (strcmp("-", inname) == 0) {
  330. if (fstat(0, &sb)<0) {
  331. error("cannot fstat `%s' (%m).\n", stdname);
  332. /*NOTREACHED*/
  333. }
  334. inname = stdname;
  335. }
  336. if (wid > 0 && !bflag)
  337. (void) printf("%s:%*s ", inname,
  338. (int) (wid - strlen(inname)), "");
  339. if (inname != stdname) {
  340. /*
  341. * first try judging the file based on its filesystem status
  342. */
  343. if (fsmagic(inname, &sb) != 0) {
  344. putchar('\n');
  345. return;
  346. }
  347. if ((fd = open(inname, O_RDONLY)) < 0) {
  348. /* We can't open it, but we were able to stat it. */
  349. if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
  350. if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
  351. ckfprintf(stdout, "can't read `%s' (%m).\n",
  352. inname);
  353. return;
  354. }
  355. }
  356. /*
  357. * try looking at the first HOWMANY bytes
  358. */
  359. if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
  360. error("read failed (%m).\n");
  361. /*NOTREACHED*/
  362. }
  363. if (nbytes == 0)
  364. ckfputs("empty", stdout);
  365. else {
  366. buf[nbytes++] = '\0'; /* null-terminate it */
  367. match = tryit(buf, nbytes, zflag);
  368. }
  369. #ifdef BUILTIN_ELF
  370. if (match == 's' && nbytes > 5)
  371. tryelf(fd, buf, nbytes);
  372. #endif
  373. if (inname != stdname) {
  374. #ifdef RESTORE_TIME
  375. /*
  376. * Try to restore access, modification times if read it.
  377. * This is really *bad* because it will modify the status
  378. * time of the file... And of course this will affect
  379. * backup programs
  380. */
  381. # ifdef USE_UTIMES
  382. struct timeval utsbuf[2];
  383. utsbuf[0].tv_sec = sb.st_atime;
  384. utsbuf[1].tv_sec = sb.st_mtime;
  385. (void) utimes(inname, utsbuf); /* don't care if loses */
  386. # else
  387. struct utimbuf utbuf;
  388. utbuf.actime = sb.st_atime;
  389. utbuf.modtime = sb.st_mtime;
  390. (void) utime(inname, &utbuf); /* don't care if loses */
  391. # endif
  392. #endif
  393. (void) close(fd);
  394. }
  395. (void) putchar('\n');
  396. }
  397. int
  398. tryit(buf, nb, zfl)
  399. unsigned char *buf;
  400. int nb, zfl;
  401. {
  402. /* try compression stuff */
  403. if (zfl && zmagic(buf, nb))
  404. return 'z';
  405. /* try tests in /etc/magic (or surrogate magic file) */
  406. if (softmagic(buf, nb))
  407. return 's';
  408. /* try known keywords, check whether it is ASCII */
  409. if (ascmagic(buf, nb))
  410. return 'a';
  411. /* see if it's international language text */
  412. if (internatmagic(buf, nb))
  413. return 'i';
  414. /* abandon hope, all ye who remain here */
  415. ckfputs("data", stdout);
  416. return '\0';
  417. }