Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * softmagic - interpret variable magic from /etc/magic | |
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 | #include <stdio.h> | |
78ed81a3 | 29 | #include <string.h> |
30 | #include <time.h> | |
31 | #include <sys/types.h> | |
32 | ||
15637ed4 RG |
33 | #include "file.h" |
34 | ||
35 | #ifndef lint | |
36 | static char *moduleid = | |
78ed81a3 | 37 | "@(#)softmagic.c,v 1.2 1993/06/10 00:38:18 jtc Exp"; |
15637ed4 RG |
38 | #endif /* lint */ |
39 | ||
78ed81a3 | 40 | static int match __P((unsigned char *)); |
41 | static int mcheck __P((unsigned char *, struct magic *)); | |
42 | static void mprint __P((struct magic *, unsigned char *)); | |
15637ed4 RG |
43 | |
44 | /* | |
45 | * softmagic - lookup one file in database | |
46 | * (already read from /etc/magic by apprentice.c). | |
47 | * Passed the name and FILE * of one file to be typed. | |
48 | */ | |
78ed81a3 | 49 | /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ |
50 | int | |
51 | softmagic(buf, nbytes) | |
52 | unsigned char *buf; | |
53 | int nbytes; | |
15637ed4 | 54 | { |
15637ed4 RG |
55 | if (match(buf)) |
56 | return 1; | |
57 | ||
58 | return 0; | |
59 | } | |
60 | ||
61 | /* | |
78ed81a3 | 62 | * Go through the whole list, stopping if you find a match. Process all |
63 | * the continuations of that match before returning. | |
64 | * | |
65 | * We support multi-level continuations: | |
66 | * | |
67 | * At any time when processing a successful top-level match, there is a | |
68 | * current continuation level; it represents the level of the last | |
69 | * successfully matched continuation. | |
70 | * | |
71 | * Continuations above that level are skipped as, if we see one, it | |
72 | * means that the continuation that controls them - i.e, the | |
73 | * lower-level continuation preceding them - failed to match. | |
74 | * | |
75 | * Continuations below that level are processed as, if we see one, | |
76 | * it means we've finished processing or skipping higher-level | |
77 | * continuations under the control of a successful or unsuccessful | |
78 | * lower-level continuation, and are now seeing the next lower-level | |
79 | * continuation and should process it. The current continuation | |
80 | * level reverts to the level of the one we're seeing. | |
81 | * | |
82 | * Continuations at the current level are processed as, if we see | |
83 | * one, there's no lower-level continuation that may have failed. | |
84 | * | |
85 | * If a continuation matches, we bump the current continuation level | |
86 | * so that higher-level continuations are processed. | |
15637ed4 | 87 | */ |
78ed81a3 | 88 | static int |
15637ed4 | 89 | match(s) |
78ed81a3 | 90 | unsigned char *s; |
15637ed4 | 91 | { |
78ed81a3 | 92 | int magindex = 0; |
93 | int cont_level = 0; | |
94 | int need_separator = 0; | |
95 | ||
15637ed4 RG |
96 | while (magindex < nmagic) { |
97 | /* if main entry matches, print it... */ | |
98 | if (mcheck(s, &magic[magindex])) { | |
99 | mprint(&magic[magindex],s); | |
78ed81a3 | 100 | /* |
101 | * If we printed something, we'll need to print | |
102 | * a blank before we print something else. | |
103 | */ | |
104 | if (magic[magindex].desc[0]) | |
105 | need_separator = 1; | |
15637ed4 | 106 | /* and any continuations that match */ |
78ed81a3 | 107 | cont_level++; |
108 | while (magic[magindex+1].cont_level != 0 && | |
15637ed4 RG |
109 | magindex < nmagic) { |
110 | ++magindex; | |
78ed81a3 | 111 | if (cont_level >= |
112 | magic[magindex].cont_level) { | |
113 | if (cont_level > | |
114 | magic[magindex].cont_level) { | |
115 | /* | |
116 | * We're at the end of the | |
117 | * level-"cont_level" | |
118 | * continuations. | |
119 | */ | |
120 | cont_level = | |
121 | magic[magindex].cont_level; | |
122 | } | |
123 | if (mcheck(s, &magic[magindex])) { | |
124 | /* | |
125 | * This continuation matched. | |
126 | * Print its message, with | |
127 | * a blank before it if | |
128 | * the previous item printed | |
129 | * and this item isn't empty. | |
130 | */ | |
131 | /* space if previous printed */ | |
132 | if (need_separator | |
133 | && (magic[magindex].nospflag == 0) | |
134 | && (magic[magindex].desc[0] != '\0') | |
135 | ) { | |
136 | (void) putchar(' '); | |
137 | need_separator = 0; | |
138 | } | |
139 | mprint(&magic[magindex],s); | |
140 | if (magic[magindex].desc[0]) | |
141 | need_separator = 1; | |
142 | ||
143 | /* | |
144 | * If we see any continuations | |
145 | * at a higher level, | |
146 | * process them. | |
147 | */ | |
148 | cont_level++; | |
149 | } | |
15637ed4 RG |
150 | } |
151 | } | |
152 | return 1; /* all through */ | |
153 | } else { | |
78ed81a3 | 154 | /* main entry didn't match, flush its continuation */ |
155 | while (magic[magindex+1].cont_level != 0 && | |
15637ed4 RG |
156 | magindex < nmagic) { |
157 | ++magindex; | |
158 | } | |
159 | } | |
160 | ++magindex; /* on to the next */ | |
161 | } | |
162 | return 0; /* no match at all */ | |
163 | } | |
164 | ||
78ed81a3 | 165 | static void |
166 | mprint(m, s) | |
15637ed4 | 167 | struct magic *m; |
78ed81a3 | 168 | unsigned char *s; |
15637ed4 RG |
169 | { |
170 | register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset); | |
78ed81a3 | 171 | char *pp, *rt; |
15637ed4 | 172 | |
78ed81a3 | 173 | /* correct byte order dependancies */ |
15637ed4 | 174 | switch (m->type) { |
78ed81a3 | 175 | case BESHORT: |
176 | p->h = (short)((p->hs[0]<<8)|(p->hs[1])); | |
15637ed4 | 177 | break; |
78ed81a3 | 178 | case BELONG: |
179 | case BEDATE: | |
180 | p->l = (long) | |
181 | ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3])); | |
15637ed4 | 182 | break; |
78ed81a3 | 183 | case LESHORT: |
184 | p->h = (short)((p->hs[1]<<8)|(p->hs[0])); | |
15637ed4 | 185 | break; |
78ed81a3 | 186 | case LELONG: |
187 | case LEDATE: | |
188 | p->l = (long) | |
189 | ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0])); | |
190 | break; | |
191 | } | |
192 | ||
193 | switch (m->type) { | |
194 | case BYTE: | |
195 | (void) printf(m->desc, | |
196 | (m->reln & MASK) ? p->b & m->mask : p->b); | |
197 | break; | |
198 | case SHORT: | |
199 | case BESHORT: | |
200 | case LESHORT: | |
201 | (void) printf(m->desc, | |
202 | (m->reln & MASK) ? p->h & m->mask : p->h); | |
203 | break; | |
204 | case LONG: | |
205 | case BELONG: | |
206 | case LELONG: | |
207 | (void) printf(m->desc, | |
208 | (m->reln & MASK) ? p->l & m->mask : p->l); | |
209 | break; | |
210 | case STRING: | |
211 | if ((rt=strchr(p->s, '\n')) != NULL) | |
212 | *rt = '\0'; | |
15637ed4 | 213 | (void) printf(m->desc, p->s); |
78ed81a3 | 214 | if (rt) |
215 | *rt = '\n'; | |
216 | break; | |
217 | case DATE: | |
218 | case BEDATE: | |
219 | case LEDATE: | |
220 | pp = ctime((time_t*) &p->l); | |
221 | if ((rt = strchr(pp, '\n')) != NULL) | |
222 | *rt = '\0'; | |
223 | (void) printf(m->desc, pp); | |
224 | if (rt) | |
225 | *rt = '\n'; | |
15637ed4 RG |
226 | break; |
227 | default: | |
78ed81a3 | 228 | error("invalid m->type (%d) in mprint().\n", m->type); |
229 | /*NOTREACHED*/ | |
15637ed4 RG |
230 | } |
231 | } | |
232 | ||
78ed81a3 | 233 | static int |
15637ed4 | 234 | mcheck(s, m) |
78ed81a3 | 235 | unsigned char *s; |
15637ed4 RG |
236 | struct magic *m; |
237 | { | |
238 | register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset); | |
239 | register long l = m->value.l; | |
78ed81a3 | 240 | register long mask = m->mask; |
15637ed4 RG |
241 | register long v; |
242 | ||
243 | if (debug) { | |
244 | (void) printf("mcheck: %10.10s ", s); | |
245 | mdump(m); | |
246 | } | |
78ed81a3 | 247 | |
248 | if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) { | |
249 | printf("BOINK"); | |
250 | return 1; | |
251 | } | |
252 | ||
15637ed4 RG |
253 | switch (m->type) { |
254 | case BYTE: | |
255 | v = p->b; break; | |
256 | case SHORT: | |
257 | v = p->h; break; | |
258 | case LONG: | |
78ed81a3 | 259 | case DATE: |
15637ed4 RG |
260 | v = p->l; break; |
261 | case STRING: | |
262 | l = 0; | |
263 | /* What we want here is: | |
264 | * v = strncmp(m->value.s, p->s, m->vallen); | |
265 | * but ignoring any nulls. bcmp doesn't give -/+/0 | |
266 | * and isn't universally available anyway. | |
267 | */ | |
78ed81a3 | 268 | v = 0; |
15637ed4 RG |
269 | { |
270 | register unsigned char *a = (unsigned char*)m->value.s; | |
271 | register unsigned char *b = (unsigned char*)p->s; | |
272 | register int len = m->vallen; | |
273 | ||
274 | while (--len >= 0) | |
275 | if ((v = *b++ - *a++) != 0) | |
276 | break; | |
277 | } | |
278 | break; | |
78ed81a3 | 279 | case BESHORT: |
280 | v = (short)((p->hs[0]<<8)|(p->hs[1])); | |
281 | break; | |
282 | case BELONG: | |
283 | case BEDATE: | |
284 | v = (long) | |
285 | ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3])); | |
286 | break; | |
287 | case LESHORT: | |
288 | v = (short)((p->hs[1]<<8)|(p->hs[0])); | |
289 | break; | |
290 | case LELONG: | |
291 | case LEDATE: | |
292 | v = (long) | |
293 | ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0])); | |
294 | break; | |
15637ed4 | 295 | default: |
78ed81a3 | 296 | error("invalid type %d in mcheck().\n", m->type); |
297 | return -1;/*NOTREACHED*/ | |
15637ed4 RG |
298 | } |
299 | ||
78ed81a3 | 300 | if (m->mask != 0L) |
301 | v &= m->mask; | |
302 | ||
15637ed4 | 303 | switch (m->reln) { |
78ed81a3 | 304 | case 'x': |
305 | return 1; | |
306 | case '!': | |
307 | return v != l; | |
15637ed4 RG |
308 | case '=': |
309 | return v == l; | |
310 | case '>': | |
311 | return v > l; | |
312 | case '<': | |
313 | return v < l; | |
314 | case '&': | |
78ed81a3 | 315 | return (v & l) == l; |
316 | case '^': | |
317 | return (v & l) != l; | |
318 | case MASK | '=': | |
319 | return (v & mask) == l; | |
320 | case MASK | '>': | |
321 | return (v & mask) > l; | |
322 | case MASK | '<': | |
323 | return (v & mask) < l; | |
15637ed4 | 324 | default: |
78ed81a3 | 325 | error("mcheck: can't happen: invalid relation %d.\n", m->reln); |
326 | return -1;/*NOTREACHED*/ | |
15637ed4 RG |
327 | } |
328 | } |