]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/file/file.c
This commit was generated by cvs2svn to compensate for changes in r53660,
[FreeBSD/FreeBSD.git] / usr.bin / file / file.c
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
28 #ifndef lint
29 static const char rcsid[] =
30   "$FreeBSD$";
31 #endif /* not lint */
32
33 #include <err.h>
34 #include <fcntl.h>      /* for open() */
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/param.h>  /* for MAXPATHLEN */
38 #include <sys/stat.h>
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 #include <unistd.h>     /* for read() */
49
50 #include "patchlevel.h"
51 #include "file.h"
52
53 #ifdef S_IFLNK
54 # define USAGE  "usage: file [-vczL] [-f namefile] [-m magicfiles] file...\n"
55 #else
56 # define USAGE  "usage: file [-vcz] [-f namefile] [-m magicfiles] file...\n"
57 #endif
58
59 #ifndef MAGIC
60 # define MAGIC "/etc/magic"
61 #endif
62
63 int                     /* Global command-line options          */
64         debug = 0,      /* debugging                            */
65         lflag = 0,      /* follow Symlinks (BSD only)           */
66         zflag = 0;      /* follow (uncompress) compressed files */
67
68 int                     /* Misc globals                         */
69         nmagic = 0;     /* number of valid magic[]s             */
70
71 struct  magic *magic;   /* array of magic entries               */
72
73 char *magicfile;        /* where magic be found                 */
74
75 int lineno;             /* line number in the magic file        */
76
77
78 static void     unwrap          __P((char *fn));
79 static void     usage           __P((void));
80 #if 0
81 static int      byteconv4       __P((int, int, int));
82 static short    byteconv2       __P((int, int, int));
83 #endif
84
85 /*
86  * main - parse arguments and handle options
87  */
88 int
89 main(argc, argv)
90 int argc;
91 char *argv[];
92 {
93         int c;
94         int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
95
96         if (!(magicfile = getenv("MAGIC")))
97                 magicfile = MAGIC;
98
99         while ((c = getopt(argc, argv, "vcdf:Lm:z")) != -1)
100                 switch (c) {
101                 case 'v':
102                         (void) fprintf(stdout, "file-%d.%d\n",
103                                        FILE_VERSION_MAJOR, patchlevel);
104                         return 1;
105                 case 'c':
106                         ++check;
107                         break;
108                 case 'd':
109                         ++debug;
110                         break;
111                 case 'f':
112                         if (!app) {
113                                 ret = apprentice(magicfile, check);
114                                 if (check)
115                                         exit(ret);
116                                 app = 1;
117                         }
118                         unwrap(optarg);
119                         ++didsomefiles;
120                         break;
121 #ifdef S_IFLNK
122                 case 'L':
123                         ++lflag;
124                         break;
125 #endif
126                 case 'm':
127                         magicfile = optarg;
128                         break;
129                 case 'z':
130                         zflag++;
131                         break;
132                 case '?':
133                 default:
134                         errflg++;
135                         break;
136                 }
137
138         if (errflg)
139                 usage();
140
141         if (!app) {
142                 ret = apprentice(magicfile, check);
143                 if (check)
144                         exit(ret);
145                 app = 1;
146         }
147
148         if (optind == argc) {
149                 if (!didsomefiles)
150                         usage();
151         }
152         else {
153                 int i, wid, nw;
154                 for (wid = 0, i = optind; i < argc; i++) {
155                         nw = strlen(argv[i]);
156                         if (nw > wid)
157                                 wid = nw;
158                 }
159                 for (; optind < argc; optind++)
160                         process(argv[optind], wid);
161         }
162
163         return 0;
164 }
165
166 static void
167 usage()
168 {
169         fprintf(stderr, USAGE);
170         exit(2);
171 }
172
173 /*
174  * unwrap -- read a file of filenames, do each one.
175  */
176 static void
177 unwrap(fn)
178 char *fn;
179 {
180         char buf[MAXPATHLEN];
181         FILE *f;
182         int wid = 0, cwid;
183
184         if (strcmp("-", fn) == 0) {
185                 f = stdin;
186                 wid = 1;
187         } else {
188                 if ((f = fopen(fn, "r")) == NULL) {
189                         err(1, "cannot open `%s'", fn);
190                         /*NOTREACHED*/
191                 }
192
193                 while (fgets(buf, MAXPATHLEN, f) != NULL) {
194                         cwid = strlen(buf) - 1;
195                         if (cwid > wid)
196                                 wid = cwid;
197                 }
198
199                 rewind(f);
200         }
201
202         while (fgets(buf, MAXPATHLEN, f) != NULL) {
203                 buf[strlen(buf)-1] = '\0';
204                 process(buf, wid);
205         }
206
207         (void) fclose(f);
208 }
209
210
211 #if 0
212 /*
213  * byteconv4
214  * Input:
215  *      from            4 byte quantity to convert
216  *      same            whether to perform byte swapping
217  *      big_endian      whether we are a big endian host
218  */
219 static int
220 byteconv4(from, same, big_endian)
221     int from;
222     int same;
223     int big_endian;
224 {
225   if (same)
226     return from;
227   else if (big_endian)          /* lsb -> msb conversion on msb */
228   {
229     union {
230       int i;
231       char c[4];
232     } retval, tmpval;
233
234     tmpval.i = from;
235     retval.c[0] = tmpval.c[3];
236     retval.c[1] = tmpval.c[2];
237     retval.c[2] = tmpval.c[1];
238     retval.c[3] = tmpval.c[0];
239
240     return retval.i;
241   }
242   else
243     return ntohl(from);         /* msb -> lsb conversion on lsb */
244 }
245
246 /*
247  * byteconv2
248  * Same as byteconv4, but for shorts
249  */
250 static short
251 byteconv2(from, same, big_endian)
252         int from;
253         int same;
254         int big_endian;
255 {
256   if (same)
257     return from;
258   else if (big_endian)          /* lsb -> msb conversion on msb */
259   {
260     union {
261       short s;
262       char c[2];
263     } retval, tmpval;
264
265     tmpval.s = (short) from;
266     retval.c[0] = tmpval.c[1];
267     retval.c[1] = tmpval.c[0];
268
269     return retval.s;
270   }
271   else
272     return ntohs(from);         /* msb -> lsb conversion on lsb */
273 }
274 #endif
275
276 /*
277  * process - process input file
278  */
279 void
280 process(inname, wid)
281 const char      *inname;
282 int wid;
283 {
284         int     fd = 0;
285         static  const char stdname[] = "standard input";
286         unsigned char   buf[HOWMANY+1]; /* one extra for terminating '\0' */
287         struct stat     sb;
288         int nbytes = 0; /* number of bytes read from a datafile */
289         char match = '\0';
290
291         if (strcmp("-", inname) == 0) {
292                 if (fstat(0, &sb)<0) {
293                         err(1, "cannot fstat `%s'", stdname);
294                         /*NOTREACHED*/
295                 }
296                 inname = stdname;
297         }
298
299         if (wid > 0)
300              (void) printf("%s:%*s ", inname,
301                            (int) (wid - strlen(inname)), "");
302
303         if (inname != stdname) {
304             /*
305              * first try judging the file based on its filesystem status
306              */
307             if (fsmagic(inname, &sb) != 0) {
308                     putchar('\n');
309                     return;
310             }
311
312             if ((fd = open(inname, O_RDONLY)) < 0) {
313                     /* We can't open it, but we were able to stat it. */
314                     if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
315                     if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
316                     ckfprintf(stdout, "can't read `%s': %s.\n",
317                         inname, strerror(errno));
318                     return;
319             }
320         }
321
322
323         /*
324          * try looking at the first HOWMANY bytes
325          */
326         if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
327                 err(1, "read failed");
328                 /*NOTREACHED*/
329         }
330
331         if (nbytes == 0)
332                 ckfputs("empty", stdout);
333         else {
334                 buf[nbytes++] = '\0';   /* null-terminate it */
335                 match = tryit(buf, nbytes, zflag);
336         }
337
338 #ifdef BUILTIN_ELF
339         if (match == 's' && nbytes > 5)
340                 tryelf(fd, buf, nbytes);
341 #endif
342
343         if (inname != stdname) {
344 #ifdef RESTORE_TIME
345                 /*
346                  * Try to restore access, modification times if read it.
347                  */
348 # ifdef USE_UTIMES
349                 struct timeval  utsbuf[2];
350                 utsbuf[0].tv_sec = sb.st_atime;
351                 utsbuf[1].tv_sec = sb.st_mtime;
352
353                 (void) utimes(inname, utsbuf); /* don't care if loses */
354 # else
355                 struct utimbuf  utbuf;
356
357                 utbuf.actime = sb.st_atime;
358                 utbuf.modtime = sb.st_mtime;
359                 (void) utime(inname, &utbuf); /* don't care if loses */
360 # endif
361 #endif
362                 (void) close(fd);
363         }
364         (void) putchar('\n');
365 }
366
367
368 int
369 tryit(buf, nb, lzflag)
370 unsigned char *buf;
371 int nb, lzflag;
372 {
373         /* try compression stuff */
374         if (lzflag && zmagic(buf, nb))
375                 return 'z';
376
377         /* try tests in /etc/magic (or surrogate magic file) */
378         if (softmagic(buf, nb))
379                 return 's';
380
381         /* try known keywords, check whether it is ASCII */
382         if (ascmagic(buf, nb))
383                 return 'a';
384
385         /* see if it's international language text */
386         if (internatmagic(buf, nb))
387                 return 'i';
388
389         /* abandon hope, all ye who remain here */
390         ckfputs("data", stdout);
391                 return '\0';
392 }