Commit | Line | Data |
---|---|---|
efd7318d WJ |
1 | /* |
2 | * apprentice - make one pass through /etc/magic, learning its secrets. | |
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> | |
29 | #include <ctype.h> | |
30 | #include "file.h" | |
31 | ||
32 | #ifndef lint | |
33 | static char *moduleid = | |
34 | "@(#)$Header: apprentice.c,v 1.8 87/11/06 21:14:34 ian Exp $"; | |
35 | #endif /* lint */ | |
36 | ||
37 | #define MAXSTR 500 | |
38 | #define EATAB {while (isascii(*l) && isspace(*l)) ++l;} | |
39 | ||
40 | extern char *progname; | |
41 | extern char *magicfile; | |
42 | extern int debug; /* option */ | |
43 | extern int nmagic; /* number of valid magic[]s */ | |
44 | extern long strtol(); | |
45 | ||
46 | struct magic magic[MAXMAGIS]; | |
47 | ||
48 | char *getstr(); | |
49 | ||
50 | apprentice(fn, check) | |
51 | char *fn; /* name of magic file */ | |
52 | int check; /* non-zero: checking-only run. */ | |
53 | { | |
54 | FILE *f; | |
55 | char line[MAXSTR+1]; | |
56 | int errs = 0; | |
57 | ||
58 | f = fopen(fn, "r"); | |
59 | if (f==NULL) { | |
60 | (void) fprintf(stderr, "%s: can't read magic file %s\n", | |
61 | progname, fn); | |
62 | if (check) | |
63 | return -1; | |
64 | else | |
65 | exit(1); | |
66 | } | |
67 | ||
68 | /* parse it */ | |
69 | if (check) /* print silly verbose header for USG compat. */ | |
70 | (void) printf("cont\toffset\ttype\topcode\tvalue\tdesc\n"); | |
71 | ||
72 | while (fgets(line, MAXSTR, f) != NULL) { | |
73 | if (line[0]=='#') /* comment, do not parse */ | |
74 | continue; | |
75 | if (strlen(line) <= 1) /* null line, garbage, etc */ | |
76 | continue; | |
77 | line[strlen(line)-1] = '\0'; /* delete newline */ | |
78 | if (parse(line, &nmagic, check) != 0) | |
79 | ++errs; | |
80 | } | |
81 | ||
82 | (void) fclose(f); | |
83 | return errs ? -1 : 0; | |
84 | } | |
85 | ||
86 | /* | |
87 | * parse one line from magic file, put into magic[index++] if valid | |
88 | */ | |
89 | int | |
90 | parse(l, ndx, check) | |
91 | char *l; | |
92 | int *ndx, check; | |
93 | { | |
94 | int i = 0, nd = *ndx; | |
95 | int slen; | |
96 | static int warned = 0; | |
97 | struct magic *m; | |
98 | extern int errno; | |
99 | ||
100 | /* | |
101 | * TODO malloc the magic structures (linked list?) so this can't happen | |
102 | */ | |
103 | if (nd+1 >= MAXMAGIS){ | |
104 | if (warned++ == 0) | |
105 | warning( | |
106 | "magic table overflow - increase MAXMAGIS beyond %d in file/apprentice.c\n", | |
107 | MAXMAGIS); | |
108 | return -1; | |
109 | } | |
110 | m = &magic[*ndx]; | |
111 | ||
112 | if (*l == '>') { | |
113 | ++l; /* step over */ | |
114 | m->contflag = 1; | |
115 | } else | |
116 | m->contflag = 0; | |
117 | ||
118 | /* get offset, then skip over it */ | |
119 | m->offset = atoi(l); | |
120 | while (isascii(*l) && isdigit(*l)) | |
121 | ++l; | |
122 | EATAB; | |
123 | ||
124 | #define NBYTE 4 | |
125 | #define NSHORT 5 | |
126 | #define NLONG 4 | |
127 | #define NSTRING 6 | |
128 | /* get type, skip it */ | |
129 | if (strncmp(l, "byte", NBYTE)==0) { | |
130 | m->type = BYTE; | |
131 | l += NBYTE; | |
132 | } else if (strncmp(l, "short", NSHORT)==0) { | |
133 | m->type = SHORT; | |
134 | l += NSHORT; | |
135 | } else if (strncmp(l, "long", NLONG)==0) { | |
136 | m->type = LONG; | |
137 | l += NLONG; | |
138 | } else if (strncmp(l, "string", NSTRING)==0) { | |
139 | m->type = STRING; | |
140 | l += NSTRING; | |
141 | } else { | |
142 | errno = 0; | |
143 | warning("type %s invalid", l); | |
144 | return -1; | |
145 | } | |
146 | EATAB; | |
147 | ||
148 | if (*l == '>' || *l == '<' || *l == '&' || *l == '=') { | |
149 | m->reln = *l; | |
150 | ++l; | |
151 | } else | |
152 | m->reln = '='; | |
153 | EATAB; | |
154 | ||
155 | /* | |
156 | * TODO finish this macro and start using it! | |
157 | * #define offsetcheck {if (offset > HOWMANY-1) warning("offset too big"); } | |
158 | */ | |
159 | switch(m->type) { | |
160 | /* | |
161 | * Do not remove the casts below. They are vital. | |
162 | * When later compared with the data, the sign extension must | |
163 | * have happened. | |
164 | */ | |
165 | case BYTE: | |
166 | m->value.l = (char) strtol(l,&l,0); | |
167 | break; | |
168 | case SHORT: | |
169 | m->value.l = (short) strtol(l,&l,0); | |
170 | break; | |
171 | case LONG: | |
172 | m->value.l = (long) strtol(l,&l,0); | |
173 | break; | |
174 | case STRING: | |
175 | l = getstr(l, m->value.s, sizeof(m->value.s), &slen); | |
176 | m->vallen = slen; | |
177 | break; | |
178 | default: | |
179 | warning("can't happen: m->type=%d\n", m->type); | |
180 | return -1; | |
181 | } | |
182 | ||
183 | /* | |
184 | * now get last part - the description | |
185 | */ | |
186 | EATAB; | |
187 | while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC) | |
188 | /* NULLBODY */; | |
189 | ||
190 | if (check) { | |
191 | mdump(m); | |
192 | } | |
193 | ++(*ndx); /* make room for next */ | |
194 | return 0; | |
195 | } | |
196 | ||
197 | /* | |
198 | * Convert a string containing C character escapes. Stop at an unescaped | |
199 | * space or tab. | |
200 | * Copy the converted version to "p", returning its length in *slen. | |
201 | * Return updated scan pointer as function result. | |
202 | */ | |
203 | char * | |
204 | getstr(s, p, plen, slen) | |
205 | register char *s; | |
206 | register char *p; | |
207 | int plen, *slen; | |
208 | { | |
209 | char *origs = s, *origp = p; | |
210 | char *pmax = p + plen - 1; | |
211 | register int c; | |
212 | register int val; | |
213 | ||
214 | while((c = *s++) != '\0') { | |
215 | if (isspace(c)) break; | |
216 | if (p >= pmax) { | |
217 | fprintf(stderr, "String too long: %s\n", origs); | |
218 | break; | |
219 | } | |
220 | if(c == '\\') { | |
221 | switch(c = *s++) { | |
222 | ||
223 | case '\0': | |
224 | goto out; | |
225 | ||
226 | default: | |
227 | *p++ = c; | |
228 | break; | |
229 | ||
230 | case 'n': | |
231 | *p++ = '\n'; | |
232 | break; | |
233 | ||
234 | case 'r': | |
235 | *p++ = '\r'; | |
236 | break; | |
237 | ||
238 | case 'b': | |
239 | *p++ = '\b'; | |
240 | break; | |
241 | ||
242 | case 't': | |
243 | *p++ = '\t'; | |
244 | break; | |
245 | ||
246 | case 'f': | |
247 | *p++ = '\f'; | |
248 | break; | |
249 | ||
250 | case 'v': | |
251 | *p++ = '\v'; | |
252 | break; | |
253 | ||
254 | /* \ and up to 3 octal digits */ | |
255 | case '0': | |
256 | case '1': | |
257 | case '2': | |
258 | case '3': | |
259 | case '4': | |
260 | case '5': | |
261 | case '6': | |
262 | case '7': | |
263 | val = c - '0'; | |
264 | c = *s++; /* try for 2 */ | |
265 | if(c >= '0' && c <= '7') { | |
266 | val = (val<<3) | (c - '0'); | |
267 | c = *s++; /* try for 3 */ | |
268 | if(c >= '0' && c <= '7') | |
269 | val = (val<<3) | (c-'0'); | |
270 | else | |
271 | --s; | |
272 | } | |
273 | else | |
274 | --s; | |
275 | *p++ = val; | |
276 | break; | |
277 | ||
278 | /* \x and up to 3 hex digits */ | |
279 | case 'x': | |
280 | val = 'x'; /* Default if no digits */ | |
281 | c = hextoint(*s++); /* Get next char */ | |
282 | if (c >= 0) { | |
283 | val = c; | |
284 | c = hextoint(*s++); | |
285 | if (c >= 0) { | |
286 | val = (val << 4) + c; | |
287 | c = hextoint(*s++); | |
288 | if (c >= 0) { | |
289 | val = (val << 4) + c; | |
290 | } else | |
291 | --s; | |
292 | } else | |
293 | --s; | |
294 | } else | |
295 | --s; | |
296 | *p++ = val; | |
297 | break; | |
298 | } | |
299 | } else | |
300 | *p++ = c; | |
301 | } | |
302 | out: | |
303 | *p = '\0'; | |
304 | *slen = p - origp; | |
305 | return(s); | |
306 | } | |
307 | ||
308 | ||
309 | /* Single hex char to int; -1 if not a hex char. */ | |
310 | int | |
311 | hextoint(c) | |
312 | char c; | |
313 | { | |
314 | if (!isascii(c)) return -1; | |
315 | if (isdigit(c)) return c - '0'; | |
316 | if ((c>='a')&(c<='f')) return c + 10 - 'a'; | |
317 | if ((c>='A')&(c<='F')) return c + 10 - 'A'; | |
318 | return -1; | |
319 | } | |
320 | ||
321 | ||
322 | /* | |
323 | * Print a string containing C character escapes. | |
324 | */ | |
325 | void | |
326 | showstr(s) | |
327 | register char *s; | |
328 | { | |
329 | register char c; | |
330 | ||
331 | while((c = *s++) != '\0') { | |
332 | if(c >= 040 && c <= 0176) | |
333 | putchar(c); | |
334 | else { | |
335 | putchar('\\'); | |
336 | switch (c) { | |
337 | ||
338 | case '\n': | |
339 | putchar('n'); | |
340 | break; | |
341 | ||
342 | case '\r': | |
343 | putchar('r'); | |
344 | break; | |
345 | ||
346 | case '\b': | |
347 | putchar('b'); | |
348 | break; | |
349 | ||
350 | case '\t': | |
351 | putchar('t'); | |
352 | break; | |
353 | ||
354 | case '\f': | |
355 | putchar('f'); | |
356 | break; | |
357 | ||
358 | case '\v': | |
359 | putchar('v'); | |
360 | break; | |
361 | ||
362 | default: | |
363 | printf("%.3o", c & 0377); | |
364 | break; | |
365 | } | |
366 | } | |
367 | } | |
368 | putchar('\t'); | |
369 | } |