]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/file/softmagic.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / usr.bin / file / softmagic.c
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 #ifndef lint
29 static const char rcsid[] =
30   "$FreeBSD$";
31 #endif /* not lint */
32
33 #include <err.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <time.h>
37
38 #include "file.h"
39
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 *));
47
48 /*
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.
52  */
53 /*ARGSUSED1*/           /* nbytes passed for regularity, maybe need later */
54 int
55 softmagic(buf, nbytes)
56 unsigned char *buf;
57 int nbytes;
58 {
59         if (match(buf, nbytes))
60                 return 1;
61
62         return 0;
63 }
64
65 /*
66  * Go through the whole list, stopping if you find a match.  Process all
67  * the continuations of that match before returning.
68  *
69  * We support multi-level continuations:
70  *
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.
74  *
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.
78  *
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.
85  *
86  *      Continuations at the current level are processed as, if we see
87  *      one, there's no lower-level continuation that may have failed.
88  *
89  *      If a continuation matches, we bump the current continuation level
90  *      so that higher-level continuations are processed.
91  */
92 static int
93 match(s, nbytes)
94 unsigned char   *s;
95 int nbytes;
96 {
97         int magindex = 0;
98         int cont_level = 0;
99         int need_separator = 0;
100         union VALUETYPE p;
101         static int32 *tmpoff = NULL;
102         static size_t tmplen = 0;
103         int32 oldoff = 0;
104
105         if (tmpoff == NULL)
106                 if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
107                         errx(1, "out of memory");
108
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])) {
113                             /*
114                              * main entry didn't match,
115                              * flush its continuations
116                              */
117                             while (magindex < nmagic &&
118                                    magic[magindex + 1].cont_level != 0)
119                                    magindex++;
120                             continue;
121                 }
122
123                 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
124                 /*
125                  * If we printed something, we'll need to print
126                  * a blank before we print something else.
127                  */
128                 if (magic[magindex].desc[0])
129                         need_separator = 1;
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) {
139                                         /*
140                                          * We're at the end of the level
141                                          * "cont_level" continuations.
142                                          */
143                                         cont_level = magic[magindex].cont_level;
144                                 }
145                                 if (magic[magindex].flag & ADD) {
146                                         oldoff=magic[magindex].offset;
147                                         magic[magindex].offset += tmpoff[cont_level-1];
148                                 }
149                                 if (mget(&p, s, &magic[magindex], nbytes) &&
150                                     mcheck(&p, &magic[magindex])) {
151                                         /*
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.
157                                          */
158                                         /* space if previous printed */
159                                         if (need_separator
160                                            && (magic[magindex].nospflag == 0)
161                                            && (magic[magindex].desc[0] != '\0')
162                                            ) {
163                                                 (void) putchar(' ');
164                                                 need_separator = 0;
165                                         }
166                                         tmpoff[cont_level] = mprint(&p, &magic[magindex]);
167                                         if (magic[magindex].desc[0])
168                                                 need_separator = 1;
169
170                                         /*
171                                          * If we see any continuations
172                                          * at a higher level,
173                                          * process them.
174                                          */
175                                         if (++cont_level >= tmplen)
176                                                 if ((tmpoff = 
177                                                     (int32 *) realloc(tmpoff,
178                                                     tmplen += 20)) == NULL)
179                                                 errx(1, "out of memory");
180                                 }
181                                 if (magic[magindex].flag & ADD) {
182                                          magic[magindex].offset = oldoff;
183                                 }
184                         }
185                 }
186                 return 1;               /* all through */
187         }
188         return 0;                       /* no match at all */
189 }
190
191 static int32
192 mprint(p, m)
193 union VALUETYPE *p;
194 struct magic *m;
195 {
196         char *pp, *rt;
197         uint32 v;
198         int32 t=0 ;
199
200
201         switch (m->type) {
202         case BYTE:
203                 v = p->b;
204                 v = signextend(m, v) & m->mask;
205                 (void) printf(m->desc, (unsigned char) v);
206                 t = m->offset + sizeof(char);
207                 break;
208
209         case SHORT:
210         case BESHORT:
211         case LESHORT:
212                 v = p->h;
213                 v = signextend(m, v) & m->mask;
214                 (void) printf(m->desc, (unsigned short) v);
215                 t = m->offset + sizeof(short);
216                 break;
217
218         case LONG:
219         case BELONG:
220         case LELONG:
221                 v = p->l;
222                 v = signextend(m, v) & m->mask;
223                 (void) printf(m->desc, (uint32) v);
224                 t = m->offset + sizeof(int32);
225                 break;
226
227         case STRING:
228                 if (m->reln == '=') {
229                         (void) printf(m->desc, m->value.s);
230                         t = m->offset + strlen(m->value.s);
231                 }
232                 else {
233                         if (*m->value.s == '\0') {
234                                 char *cp = strchr(p->s,'\n');
235                                 if (cp)
236                                         *cp = '\0';
237                         }
238                         (void) printf(m->desc, p->s);
239                         t = m->offset + strlen(p->s);
240                 }
241                 break;
242
243         case DATE:
244         case BEDATE:
245         case LEDATE:
246                 pp = ctime((time_t*) &p->l);
247                 if ((rt = strchr(pp, '\n')) != NULL)
248                         *rt = '\0';
249                 (void) printf(m->desc, pp);
250                 t = m->offset + sizeof(time_t);
251                 break;
252
253         default:
254                 errx(1, "invalid m->type (%d) in mprint()", m->type);
255                 /*NOTREACHED*/
256         }
257         return(t);
258 }
259
260 /*
261  * Convert the byte order of the data we are looking at
262  */
263 static int
264 mconvert(p, m)
265 union VALUETYPE *p;
266 struct magic *m;
267 {
268         switch (m->type) {
269         case BYTE:
270         case SHORT:
271         case LONG:
272         case DATE:
273                 return 1;
274         case STRING:
275                 {
276                         char *ptr;
277
278                         /* Null terminate and eat the return */
279                         p->s[sizeof(p->s) - 1] = '\0';
280                         if ((ptr = strchr(p->s, '\n')) != NULL)
281                                 *ptr = '\0';
282                         return 1;
283                 }
284         case BESHORT:
285                 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
286                 return 1;
287         case BELONG:
288         case BEDATE:
289                 p->l = (int32)
290                     ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
291                 return 1;
292         case LESHORT:
293                 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
294                 return 1;
295         case LELONG:
296         case LEDATE:
297                 p->l = (int32)
298                     ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
299                 return 1;
300         default:
301                 errx(1, "invalid type %d in mconvert()", m->type);
302                 return 0;
303         }
304 }
305
306
307 static void
308 mdebug(offset, str, len)
309 int32 offset;
310 char *str;
311 int len;
312 {
313         (void) fprintf(stderr, "mget @%d: ", offset);
314         showstr(stderr, (char *) str, len);
315         (void) fputc('\n', stderr);
316         (void) fputc('\n', stderr);
317 }
318
319 static int
320 mget(p, s, m, nbytes)
321 union VALUETYPE* p;
322 unsigned char   *s;
323 struct magic *m;
324 int nbytes;
325 {
326         int32 offset = m->offset;
327
328         if (offset + sizeof(union VALUETYPE) <= nbytes)
329                 memcpy(p, s + offset, sizeof(union VALUETYPE));
330         else {
331                 /*
332                  * the usefulness of padding with zeroes eludes me, it
333                  * might even cause problems
334                  */
335                 int32 have = nbytes - offset;
336                 memset(p, 0, sizeof(union VALUETYPE));
337                 if (have > 0)
338                         memcpy(p, s + offset, have);
339         }
340
341
342         if (debug) {
343                 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
344                 mdump(m);
345         }
346
347         if (!mconvert(p, m))
348                 return 0;
349
350         if (m->flag & INDIR) {
351
352                 switch (m->in.type) {
353                 case BYTE:
354                         offset = p->b + m->in.offset;
355                         break;
356                 case SHORT:
357                         offset = p->h + m->in.offset;
358                         break;
359                 case LONG:
360                         offset = p->l + m->in.offset;
361                         break;
362                 }
363
364                 if (offset + sizeof(union VALUETYPE) > nbytes)
365                         return 0;
366
367                 memcpy(p, s + offset, sizeof(union VALUETYPE));
368
369                 if (debug) {
370                         mdebug(offset, (char *) p, sizeof(union VALUETYPE));
371                         mdump(m);
372                 }
373
374                 if (!mconvert(p, m))
375                         return 0;
376         }
377         return 1;
378 }
379
380 static int
381 mcheck(p, m)
382 union VALUETYPE* p;
383 struct magic *m;
384 {
385         register uint32 l = m->value.l;
386         register uint32 v;
387         int matched;
388
389         if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
390                 fprintf(stderr, "BOINK");
391                 return 1;
392         }
393
394
395         switch (m->type) {
396         case BYTE:
397                 v = p->b;
398                 break;
399
400         case SHORT:
401         case BESHORT:
402         case LESHORT:
403                 v = p->h;
404                 break;
405
406         case LONG:
407         case BELONG:
408         case LELONG:
409         case DATE:
410         case BEDATE:
411         case LEDATE:
412                 v = p->l;
413                 break;
414
415         case STRING:
416                 l = 0;
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.
421                  */
422                 v = 0;
423                 {
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;
427
428                         while (--len >= 0)
429                                 if ((v = *b++ - *a++) != '\0')
430                                         break;
431                 }
432                 break;
433         default:
434                 errx(1, "invalid type %d in mcheck()", m->type);
435                 return 0;/*NOTREACHED*/
436         }
437
438         v = signextend(m, v) & m->mask;
439
440         switch (m->reln) {
441         case 'x':
442                 if (debug)
443                         (void) fprintf(stderr, "%u == *any* = 1\n", v);
444                 matched = 1;
445                 break;
446
447         case '!':
448                 matched = v != l;
449                 if (debug)
450                         (void) fprintf(stderr, "%u != %u = %d\n",
451                                        v, l, matched);
452                 break;
453
454         case '=':
455                 matched = v == l;
456                 if (debug)
457                         (void) fprintf(stderr, "%u == %u = %d\n",
458                                        v, l, matched);
459                 break;
460
461         case '>':
462                 if (m->flag & UNSIGNED) {
463                         matched = v > l;
464                         if (debug)
465                                 (void) fprintf(stderr, "%u > %u = %d\n",
466                                                v, l, matched);
467                 }
468                 else {
469                         matched = (int32) v > (int32) l;
470                         if (debug)
471                                 (void) fprintf(stderr, "%d > %d = %d\n",
472                                                v, l, matched);
473                 }
474                 break;
475
476         case '<':
477                 if (m->flag & UNSIGNED) {
478                         matched = v < l;
479                         if (debug)
480                                 (void) fprintf(stderr, "%u < %u = %d\n",
481                                                v, l, matched);
482                 }
483                 else {
484                         matched = (int32) v < (int32) l;
485                         if (debug)
486                                 (void) fprintf(stderr, "%d < %d = %d\n",
487                                                v, l, matched);
488                 }
489                 break;
490
491         case '&':
492                 matched = (v & l) == l;
493                 if (debug)
494                         (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
495                                        v, l, l, matched);
496                 break;
497
498         case '^':
499                 matched = (v & l) != l;
500                 if (debug)
501                         (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
502                                        v, l, l, matched);
503                 break;
504
505         default:
506                 matched = 0;
507                 errx(1, "mcheck: can't happen: invalid relation %d", m->reln);
508                 break;/*NOTREACHED*/
509         }
510
511         return matched;
512 }