This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.bin / file / softmagic.c
CommitLineData
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
36static char *moduleid =
78ed81a3 37 "@(#)softmagic.c,v 1.2 1993/06/10 00:38:18 jtc Exp";
15637ed4
RG
38#endif /* lint */
39
78ed81a3 40static int match __P((unsigned char *));
41static int mcheck __P((unsigned char *, struct magic *));
42static 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 */
50int
51softmagic(buf, nbytes)
52unsigned char *buf;
53int 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 88static int
15637ed4 89match(s)
78ed81a3 90unsigned 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 165static void
166mprint(m, s)
15637ed4 167struct magic *m;
78ed81a3 168unsigned 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 233static int
15637ed4 234mcheck(s, m)
78ed81a3 235unsigned char *s;
15637ed4
RG
236struct 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}