Commit | Line | Data |
---|---|---|
15637ed4 RG |
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 | */ | |
286a6f32 C |
27 | #ifndef lint |
28 | static char *moduleid = | |
29 | "@(#)file.c,v 1.2 1993/06/10 00:38:08 jtc Exp"; | |
30 | #endif /* lint */ | |
15637ed4 RG |
31 | |
32 | #include <stdio.h> | |
286a6f32 C |
33 | #include <stdlib.h> |
34 | #include <string.h> | |
15637ed4 | 35 | #include <sys/types.h> |
286a6f32 | 36 | #include <sys/param.h> /* for MAXPATHLEN */ |
15637ed4 | 37 | #include <sys/stat.h> |
286a6f32 C |
38 | #include <fcntl.h> /* for open() */ |
39 | #include <utime.h> | |
40 | #include <unistd.h> /* for read() */ | |
15637ed4 | 41 | |
286a6f32 | 42 | #include "file.h" |
15637ed4 | 43 | |
286a6f32 C |
44 | #ifdef S_IFLNK |
45 | # define USAGE "Usage: %s [-czL] [-f namefile] [-m magicfile] file...\n" | |
15637ed4 | 46 | #else |
286a6f32 | 47 | # define USAGE "Usage: %s [-cz] [-f namefile] [-m magicfile] file...\n" |
15637ed4 | 48 | #endif |
286a6f32 C |
49 | |
50 | #ifndef MAGIC | |
51 | # define MAGIC "/etc/magic" | |
52 | #endif | |
53 | ||
54 | int /* Global command-line options */ | |
55 | debug = 0, /* debugging */ | |
56 | lflag = 0, /* follow Symlinks (BSD only) */ | |
57 | zflag = 0; /* follow (uncompress) compressed files */ | |
58 | ||
59 | int /* Misc globals */ | |
60 | nmagic = 0; /* number of valid magic[]s */ | |
61 | ||
62 | struct magic *magic; /* array of magic entries */ | |
63 | ||
64 | char *magicfile = MAGIC;/* where magic be found */ | |
65 | ||
66 | char *progname; /* used throughout */ | |
67 | int lineno; /* line number in the magic file */ | |
68 | ||
69 | ||
70 | static void unwrap __P((char *fn)); | |
15637ed4 RG |
71 | |
72 | /* | |
73 | * main - parse arguments and handle options | |
74 | */ | |
286a6f32 | 75 | int |
15637ed4 RG |
76 | main(argc, argv) |
77 | int argc; | |
78 | char *argv[]; | |
79 | { | |
80 | int c; | |
81 | int check = 0, didsomefiles = 0, errflg = 0, ret = 0; | |
15637ed4 | 82 | |
286a6f32 C |
83 | if ((progname = strrchr(argv[0], '/')) != NULL) |
84 | progname++; | |
85 | else | |
86 | progname = argv[0]; | |
15637ed4 | 87 | |
286a6f32 | 88 | while ((c = getopt(argc, argv, "cdf:Lm:z")) != EOF) |
15637ed4 RG |
89 | switch (c) { |
90 | case 'c': | |
91 | ++check; | |
92 | break; | |
93 | case 'd': | |
94 | ++debug; | |
95 | break; | |
96 | case 'f': | |
97 | unwrap(optarg); | |
98 | ++didsomefiles; | |
99 | break; | |
286a6f32 C |
100 | #ifdef S_IFLNK |
101 | case 'L': | |
102 | ++lflag; | |
103 | break; | |
104 | #endif | |
15637ed4 RG |
105 | case 'm': |
106 | magicfile = optarg; | |
107 | break; | |
286a6f32 C |
108 | case 'z': |
109 | zflag++; | |
110 | break; | |
15637ed4 RG |
111 | case '?': |
112 | default: | |
113 | errflg++; | |
114 | break; | |
115 | } | |
116 | if (errflg) { | |
117 | (void) fprintf(stderr, USAGE, progname); | |
118 | exit(2); | |
119 | } | |
120 | ||
121 | ret = apprentice(magicfile, check); | |
122 | if (check) | |
123 | exit(ret); | |
124 | ||
125 | if (optind == argc) { | |
286a6f32 | 126 | if (!didsomefiles) { |
15637ed4 | 127 | (void)fprintf(stderr, USAGE, progname); |
286a6f32 C |
128 | exit(2); |
129 | } | |
15637ed4 | 130 | } |
286a6f32 C |
131 | else { |
132 | int i, wid, nw; | |
133 | for (wid = 0, i = optind; i < argc; i++) { | |
134 | nw = strlen(argv[i]); | |
135 | if (nw > wid) | |
136 | wid = nw; | |
137 | } | |
15637ed4 | 138 | for (; optind < argc; optind++) |
286a6f32 C |
139 | process(argv[optind], wid); |
140 | } | |
15637ed4 | 141 | |
286a6f32 | 142 | return 0; |
15637ed4 RG |
143 | } |
144 | ||
286a6f32 | 145 | |
15637ed4 RG |
146 | /* |
147 | * unwrap -- read a file of filenames, do each one. | |
148 | */ | |
286a6f32 | 149 | static void |
15637ed4 RG |
150 | unwrap(fn) |
151 | char *fn; | |
152 | { | |
286a6f32 | 153 | char buf[MAXPATHLEN]; |
15637ed4 | 154 | FILE *f; |
286a6f32 | 155 | int wid = 0, cwid; |
15637ed4 | 156 | |
286a6f32 C |
157 | if ((f = fopen(fn, "r")) == NULL) { |
158 | error("Cannot open `%s' (%s).\n", fn, strerror(errno)); | |
159 | /*NOTREACHED*/ | |
15637ed4 | 160 | } |
286a6f32 C |
161 | |
162 | while (fgets(buf, MAXPATHLEN, f) != NULL) { | |
163 | cwid = strlen(buf) - 1; | |
164 | if (cwid > wid) | |
165 | wid = cwid; | |
166 | } | |
167 | ||
168 | rewind(f); | |
169 | ||
170 | while (fgets(buf, MAXPATHLEN, f) != NULL) { | |
171 | buf[strlen(buf)-1] = '\0'; | |
172 | process(buf, wid); | |
173 | } | |
174 | ||
175 | (void) fclose(f); | |
15637ed4 RG |
176 | } |
177 | ||
286a6f32 | 178 | |
15637ed4 RG |
179 | /* |
180 | * process - process input file | |
181 | */ | |
286a6f32 C |
182 | void |
183 | process(inname, wid) | |
184 | const char *inname; | |
185 | int wid; | |
15637ed4 | 186 | { |
286a6f32 C |
187 | int fd = 0; |
188 | static const char stdname[] = "standard input"; | |
189 | unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */ | |
190 | struct utimbuf utbuf; | |
191 | struct stat sb; | |
192 | int nbytes = 0; /* number of bytes read from a datafile */ | |
15637ed4 RG |
193 | |
194 | if (strcmp("-", inname) == 0) { | |
286a6f32 C |
195 | if (fstat(0, &sb)<0) { |
196 | error("cannot fstat `%s' (%s).\n", stdname, | |
197 | strerror(errno)); | |
198 | /*NOTREACHED*/ | |
199 | } | |
200 | inname = stdname; | |
15637ed4 | 201 | } |
286a6f32 C |
202 | |
203 | if (wid > 0) | |
204 | (void) printf("%s:%*s ", inname, wid - strlen(inname), ""); | |
205 | ||
206 | if (inname != stdname) { | |
207 | /* | |
208 | * first try judging the file based on its filesystem status | |
209 | */ | |
210 | if (fsmagic(inname, &sb) != 0) { | |
211 | putchar('\n'); | |
212 | return; | |
213 | } | |
15637ed4 | 214 | |
286a6f32 C |
215 | if ((fd = open(inname, O_RDONLY)) < 0) { |
216 | /* We can't open it, but we were able to stat it. */ | |
217 | if (sb.st_mode & 0002) ckfputs("writeable, ", stdout); | |
218 | if (sb.st_mode & 0111) ckfputs("executable, ", stdout); | |
219 | ckfprintf(stdout, "can't read `%s' (%s).\n", | |
220 | inname, strerror(errno)); | |
221 | return; | |
222 | } | |
223 | } | |
224 | ||
15637ed4 RG |
225 | |
226 | /* | |
286a6f32 | 227 | * try looking at the first HOWMANY bytes |
15637ed4 | 228 | */ |
286a6f32 C |
229 | if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { |
230 | error("read failed (%s).\n", strerror(errno)); | |
231 | /*NOTREACHED*/ | |
232 | } | |
233 | ||
234 | if (nbytes == 0) | |
235 | ckfputs("empty", stdout); | |
236 | else { | |
237 | buf[nbytes] = '\0'; /* null-terminate it */ | |
238 | tryit(buf, nbytes); | |
239 | } | |
240 | ||
241 | if (inname != stdname) { | |
15637ed4 | 242 | /* |
286a6f32 | 243 | * Try to restore access, modification times if read it. |
15637ed4 | 244 | */ |
286a6f32 C |
245 | utbuf.actime = sb.st_atime; |
246 | utbuf.modtime = sb.st_mtime; | |
247 | (void) utime(inname, &utbuf); /* don't care if loses */ | |
248 | (void) close(fd); | |
15637ed4 | 249 | } |
15637ed4 RG |
250 | (void) putchar('\n'); |
251 | } | |
252 | ||
253 | ||
286a6f32 C |
254 | void |
255 | tryit(buf, nb) | |
256 | unsigned char *buf; | |
257 | int nb; | |
258 | { | |
259 | /* | |
260 | * try tests in /etc/magic (or surrogate magic file) | |
261 | */ | |
262 | if (softmagic(buf, nb) != 1) | |
263 | /* | |
264 | * try known keywords, check for ascii-ness too. | |
265 | */ | |
266 | if (ascmagic(buf, nb) != 1) | |
267 | /* | |
268 | * abandon hope, all ye who remain here | |
269 | */ | |
270 | ckfputs("data", stdout); | |
271 | } | |
272 |