2 * softmagic - interpret variable magic from /etc/magic
4 * Copyright (c) Ian F. Darwin, 1987.
5 * Written by Ian F. Darwin.
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.
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:
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.
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.
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.
25 * 4. This notice may not be removed or altered.
29 static const char rcsid[] =
40 static int match __P((unsigned char *, int));
41 static int mget __P((union VALUETYPE *,
42 unsigned char *, struct magic *, int));
43 static int mcheck __P((union VALUETYPE *, struct magic *));
44 static int32 mprint __P((union VALUETYPE *, struct magic *));
45 static void mdebug __P((int32, char *, int));
46 static int mconvert __P((union VALUETYPE *, struct magic *));
49 * softmagic - lookup one file in database
50 * (already read from /etc/magic by apprentice.c).
51 * Passed the name and FILE * of one file to be typed.
53 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
55 softmagic(buf, nbytes)
59 if (match(buf, nbytes))
66 * Go through the whole list, stopping if you find a match. Process all
67 * the continuations of that match before returning.
69 * We support multi-level continuations:
71 * At any time when processing a successful top-level match, there is a
72 * current continuation level; it represents the level of the last
73 * successfully matched continuation.
75 * Continuations above that level are skipped as, if we see one, it
76 * means that the continuation that controls them - i.e, the
77 * lower-level continuation preceding them - failed to match.
79 * Continuations below that level are processed as, if we see one,
80 * it means we've finished processing or skipping higher-level
81 * continuations under the control of a successful or unsuccessful
82 * lower-level continuation, and are now seeing the next lower-level
83 * continuation and should process it. The current continuation
84 * level reverts to the level of the one we're seeing.
86 * Continuations at the current level are processed as, if we see
87 * one, there's no lower-level continuation that may have failed.
89 * If a continuation matches, we bump the current continuation level
90 * so that higher-level continuations are processed.
99 int need_separator = 0;
101 static int32 *tmpoff = NULL;
102 static size_t tmplen = 0;
106 if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
107 errx(1, "out of memory");
109 for (magindex = 0; magindex < nmagic; magindex++) {
110 /* if main entry matches, print it... */
111 if (!mget(&p, s, &magic[magindex], nbytes) ||
112 !mcheck(&p, &magic[magindex])) {
114 * main entry didn't match,
115 * flush its continuations
117 while (magindex < nmagic &&
118 magic[magindex + 1].cont_level != 0)
123 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
125 * If we printed something, we'll need to print
126 * a blank before we print something else.
128 if (magic[magindex].desc[0])
130 /* and any continuations that match */
131 if (++cont_level >= tmplen)
132 if ((tmpoff = (int32 *) realloc(tmpoff,
133 tmplen += 20)) == NULL)
134 errx(1, "out of memory");
135 while (magic[magindex+1].cont_level != 0 &&
136 ++magindex < nmagic) {
137 if (cont_level >= magic[magindex].cont_level) {
138 if (cont_level > magic[magindex].cont_level) {
140 * We're at the end of the level
141 * "cont_level" continuations.
143 cont_level = magic[magindex].cont_level;
145 if (magic[magindex].flag & ADD) {
146 oldoff=magic[magindex].offset;
147 magic[magindex].offset += tmpoff[cont_level-1];
149 if (mget(&p, s, &magic[magindex], nbytes) &&
150 mcheck(&p, &magic[magindex])) {
152 * This continuation matched.
153 * Print its message, with
154 * a blank before it if
155 * the previous item printed
156 * and this item isn't empty.
158 /* space if previous printed */
160 && (magic[magindex].nospflag == 0)
161 && (magic[magindex].desc[0] != '\0')
166 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
167 if (magic[magindex].desc[0])
171 * If we see any continuations
175 if (++cont_level >= tmplen)
177 (int32 *) realloc(tmpoff,
178 tmplen += 20)) == NULL)
179 errx(1, "out of memory");
181 if (magic[magindex].flag & ADD) {
182 magic[magindex].offset = oldoff;
186 return 1; /* all through */
188 return 0; /* no match at all */
204 v = signextend(m, v) & m->mask;
205 (void) printf(m->desc, (unsigned char) v);
206 t = m->offset + sizeof(char);
213 v = signextend(m, v) & m->mask;
214 (void) printf(m->desc, (unsigned short) v);
215 t = m->offset + sizeof(short);
222 v = signextend(m, v) & m->mask;
223 (void) printf(m->desc, (uint32) v);
224 t = m->offset + sizeof(int32);
228 if (m->reln == '=') {
229 (void) printf(m->desc, m->value.s);
230 t = m->offset + strlen(m->value.s);
233 if (*m->value.s == '\0') {
234 char *cp = strchr(p->s,'\n');
238 (void) printf(m->desc, p->s);
239 t = m->offset + strlen(p->s);
246 pp = ctime((time_t*) &p->l);
247 if ((rt = strchr(pp, '\n')) != NULL)
249 (void) printf(m->desc, pp);
250 t = m->offset + sizeof(time_t);
254 errx(1, "invalid m->type (%d) in mprint()", m->type);
261 * Convert the byte order of the data we are looking at
278 /* Null terminate and eat the return */
279 p->s[sizeof(p->s) - 1] = '\0';
280 if ((ptr = strchr(p->s, '\n')) != NULL)
285 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
290 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
293 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
298 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
301 errx(1, "invalid type %d in mconvert()", m->type);
308 mdebug(offset, str, len)
313 (void) fprintf(stderr, "mget @%d: ", offset);
314 showstr(stderr, (char *) str, len);
315 (void) fputc('\n', stderr);
316 (void) fputc('\n', stderr);
320 mget(p, s, m, nbytes)
326 int32 offset = m->offset;
328 if (offset + sizeof(union VALUETYPE) <= nbytes)
329 memcpy(p, s + offset, sizeof(union VALUETYPE));
332 * the usefulness of padding with zeroes eludes me, it
333 * might even cause problems
335 int32 have = nbytes - offset;
336 memset(p, 0, sizeof(union VALUETYPE));
338 memcpy(p, s + offset, have);
343 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
350 if (m->flag & INDIR) {
352 switch (m->in.type) {
354 offset = p->b + m->in.offset;
357 offset = p->h + m->in.offset;
360 offset = p->l + m->in.offset;
364 if (offset + sizeof(union VALUETYPE) > nbytes)
367 memcpy(p, s + offset, sizeof(union VALUETYPE));
370 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
385 register uint32 l = m->value.l;
389 if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
390 fprintf(stderr, "BOINK");
417 /* What we want here is:
418 * v = strncmp(m->value.s, p->s, m->vallen);
419 * but ignoring any nulls. bcmp doesn't give -/+/0
420 * and isn't universally available anyway.
424 register unsigned char *a = (unsigned char*)m->value.s;
425 register unsigned char *b = (unsigned char*)p->s;
426 register int len = m->vallen;
429 if ((v = *b++ - *a++) != '\0')
434 errx(1, "invalid type %d in mcheck()", m->type);
435 return 0;/*NOTREACHED*/
438 v = signextend(m, v) & m->mask;
443 (void) fprintf(stderr, "%u == *any* = 1\n", v);
450 (void) fprintf(stderr, "%u != %u = %d\n",
457 (void) fprintf(stderr, "%u == %u = %d\n",
462 if (m->flag & UNSIGNED) {
465 (void) fprintf(stderr, "%u > %u = %d\n",
469 matched = (int32) v > (int32) l;
471 (void) fprintf(stderr, "%d > %d = %d\n",
477 if (m->flag & UNSIGNED) {
480 (void) fprintf(stderr, "%u < %u = %d\n",
484 matched = (int32) v < (int32) l;
486 (void) fprintf(stderr, "%d < %d = %d\n",
492 matched = (v & l) == l;
494 (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
499 matched = (v & l) != l;
501 (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
507 errx(1, "mcheck: can't happen: invalid relation %d", m->reln);