elf2coff isn't a generic tool for all linux ports
[linux-2.6/linux-mips.git] / fs / binfmt_misc.c
blob22d928648ec2ee3a00ff81ccfca171d69c40925f
1 /*
2 * binfmt_misc.c
4 * Copyright (C) 1997 Richard Günther
6 * binfmt_misc detects binaries via a magic or filename extension and invokes
7 * a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
8 * binfmt_mz.
10 * 1997-04-25 first version
11 * [...]
12 * 1997-05-19 cleanup
13 * 1997-06-26 hpa: pass the real filename rather than argv[0]
14 * 1997-06-30 minor cleanup
17 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/fs.h>
22 #include <linux/malloc.h>
23 #include <linux/binfmts.h>
24 #include <linux/init.h>
25 #include <linux/proc_fs.h>
26 #include <linux/string.h>
27 #include <linux/ctype.h>
28 #include <asm/uaccess.h>
29 #include <asm/spinlock.h>
32 #define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
34 #ifndef MIN
35 #define MIN(x,y) (((x)<(y))?(x):(y))
36 #endif
38 struct binfmt_entry {
39 struct binfmt_entry *next;
40 int id;
41 int flags; /* type, status, etc. */
42 int offset; /* offset of magic */
43 int size; /* size of magic/mask */
44 char *magic; /* magic or filename extension */
45 char *mask; /* mask, NULL for exact match */
46 char *interpreter; /* filename of interpreter */
47 char *proc_name;
48 struct proc_dir_entry *proc_dir;
51 #define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
52 #define ENTRY_MAGIC 8 /* not filename detection */
53 #define ENTRY_STRIP_EXT 32 /* strip off last filename extension */
55 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
56 static void entry_proc_cleanup(struct binfmt_entry *e);
57 static int entry_proc_setup(struct binfmt_entry *e);
59 static struct linux_binfmt misc_format = {
60 #ifndef MODULE
61 NULL, 0, load_misc_binary, NULL, NULL
62 #else
63 NULL, &__this_module, load_misc_binary, NULL, NULL
64 #endif
67 static struct proc_dir_entry *bm_dir = NULL;
69 static struct binfmt_entry *entries = NULL;
70 static int free_id = 1;
71 static int enabled = 1;
73 static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
77 * Unregister one entry
79 static void clear_entry(int id)
81 struct binfmt_entry **ep, *e;
83 write_lock(&entries_lock);
84 ep = &entries;
85 while (*ep && ((*ep)->id != id))
86 ep = &((*ep)->next);
87 if ((e = *ep)) {
88 *ep = e->next;
89 entry_proc_cleanup(e);
90 kfree(e);
92 write_unlock(&entries_lock);
96 * Clear all registered binary formats
98 static void clear_entries(void)
100 struct binfmt_entry *e;
102 write_lock(&entries_lock);
103 while ((e = entries)) {
104 entries = entries->next;
105 entry_proc_cleanup(e);
106 kfree(e);
108 write_unlock(&entries_lock);
112 * Find entry through id - caller has to do locking
114 static struct binfmt_entry *get_entry(int id)
116 struct binfmt_entry *e = entries;
118 while (e && (e->id != id))
119 e = e->next;
120 return e;
125 * Check if we support the binfmt
126 * if we do, return the binfmt_entry, else NULL
127 * locking is done in load_misc_binary
129 static struct binfmt_entry *check_file(struct linux_binprm *bprm)
131 struct binfmt_entry *e = entries;
132 char *p = strrchr(bprm->filename, '.');
133 int j;
135 while (e) {
136 if (e->flags & ENTRY_ENABLED) {
137 if (!(e->flags & ENTRY_MAGIC)) {
138 if (p && !strcmp(e->magic, p + 1))
139 return e;
140 } else {
141 j = 0;
142 while ((j < e->size) &&
143 !((bprm->buf[e->offset + j] ^ e->magic[j])
144 & (e->mask ? e->mask[j] : 0xff)))
145 j++;
146 if (j == e->size)
147 return e;
150 e = e->next;
152 return NULL;
156 * the loader itself
158 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
160 struct binfmt_entry *fmt;
161 struct dentry * dentry;
162 char iname[128];
163 char *iname_addr = iname, *p;
164 int retval, fmt_flags = 0;
166 MOD_INC_USE_COUNT;
167 if (!enabled) {
168 retval = -ENOEXEC;
169 goto _ret;
172 /* to keep locking time low, we copy the interpreter string */
173 read_lock(&entries_lock);
174 if ((fmt = check_file(bprm))) {
175 strncpy(iname, fmt->interpreter, 127);
176 iname[127] = '\0';
177 fmt_flags = fmt->flags;
179 read_unlock(&entries_lock);
180 if (!fmt) {
181 retval = -ENOEXEC;
182 goto _ret;
185 dput(bprm->dentry);
186 bprm->dentry = NULL;
188 /* Build args for interpreter */
189 if ((fmt_flags & ENTRY_STRIP_EXT) &&
190 (p = strrchr(bprm->filename, '.')))
191 *p = '\0';
192 remove_arg_zero(bprm);
193 bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
194 bprm->argc++;
195 bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2);
196 bprm->argc++;
197 if (!bprm->p) {
198 retval = -E2BIG;
199 goto _ret;
201 bprm->filename = iname; /* for binfmt_script */
203 dentry = open_namei(iname, 0, 0);
204 retval = PTR_ERR(dentry);
205 if (IS_ERR(dentry))
206 goto _ret;
207 bprm->dentry = dentry;
209 retval = prepare_binprm(bprm);
210 if (retval >= 0)
211 retval = search_binary_handler(bprm, regs);
212 _ret:
213 MOD_DEC_USE_COUNT;
214 return retval;
220 * /proc handling routines
224 * parses and copies one argument enclosed in del from *sp to *dp,
225 * recognising the \x special.
226 * returns pointer to the copied argument or NULL in case of an
227 * error (and sets err) or null argument length.
229 static char *copyarg(char **dp, const char **sp, int *count,
230 char del, int special, int *err)
232 char c, *res = *dp;
234 while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
235 switch (c) {
236 case '\\':
237 if (special && (**sp == 'x')) {
238 if (!isxdigit(c = toupper(*(++*sp))))
239 *err = -EINVAL;
240 **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
241 if (!isxdigit(c = toupper(*(++*sp))))
242 *err = -EINVAL;
243 *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
244 ++*sp;
245 *count -= 3;
246 break;
248 default:
249 *((*dp)++) = c;
252 if (*err || (c != del) || (res == *dp))
253 res = NULL;
254 else if (!special)
255 *((*dp)++) = '\0';
256 return res;
260 * This registers a new binary format, it recognises the syntax
261 * ':name:type:offset:magic:mask:interpreter:'
262 * where the ':' is the IFS, that can be chosen with the first char
264 static int proc_write_register(struct file *file, const char *buffer,
265 unsigned long count, void *data)
267 const char *sp;
268 char del, *dp;
269 struct binfmt_entry *e;
270 int memsize, cnt = count - 1, err = 0;
272 MOD_INC_USE_COUNT;
273 /* some sanity checks */
274 if ((count < 11) || (count > 256)) {
275 err = -EINVAL;
276 goto _err;
279 memsize = sizeof(struct binfmt_entry) + count;
280 if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
281 err = -ENOMEM;
282 goto _err;
285 sp = buffer + 1;
286 del = buffer[0];
287 dp = (char *)e + sizeof(struct binfmt_entry);
289 e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
291 /* we can use bit 3 and 5 of type for ext/magic and ext-strip
292 flag due to the nice encoding of E, M, e and m */
293 if ((*sp & 0x92) || (sp[1] != del))
294 err = -EINVAL;
295 else
296 e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_STRIP_EXT))
297 | ENTRY_ENABLED;
298 cnt -= 2; sp++;
300 e->offset = 0;
301 while (cnt-- && isdigit(*sp))
302 e->offset = e->offset * 10 + *sp++ - '0';
303 if (*sp++ != del)
304 err = -EINVAL;
306 e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
307 e->size = dp - e->magic;
308 e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
309 if (e->mask && ((dp - e->mask) != e->size))
310 err = -EINVAL;
311 e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
312 e->id = free_id++;
314 /* more sanity checks */
315 if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
316 (e->size < 1) || ((e->size + e->offset) > 127) ||
317 !(e->proc_name) || !(e->interpreter) ||
318 entry_proc_setup(e)) {
319 kfree(e);
320 err = -EINVAL;
321 goto _err;
324 write_lock(&entries_lock);
325 e->next = entries;
326 entries = e;
327 write_unlock(&entries_lock);
329 err = count;
330 _err:
331 MOD_DEC_USE_COUNT;
332 return err;
336 * Get status of entry/binfmt_misc
337 * FIXME? should an entry be marked disabled if binfmt_misc is disabled though
338 * entry is enabled?
340 static int proc_read_status(char *page, char **start, off_t off,
341 int count, int *eof, void *data)
343 struct binfmt_entry *e;
344 char *dp;
345 int elen, i;
347 MOD_INC_USE_COUNT;
348 #ifndef VERBOSE_STATUS
349 if (data) {
350 read_lock(&entries_lock);
351 if (!(e = get_entry((int) data)))
352 i = 0;
353 else
354 i = e->flags & ENTRY_ENABLED;
355 read_unlock(&entries_lock);
356 } else {
357 i = enabled;
359 sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
360 #else
361 if (!data)
362 sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
363 else {
364 read_lock(&entries_lock);
365 if (!(e = get_entry((int) data))) {
366 *page = '\0';
367 goto _out;
369 sprintf(page, "%s\ninterpreter %s\n",
370 (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
371 e->interpreter);
372 dp = page + strlen(page);
373 if (!(e->flags & ENTRY_MAGIC)) {
374 sprintf(dp, "extension .%s\n", e->magic);
375 dp = page + strlen(page);
376 } else {
377 sprintf(dp, "offset %i\nmagic ", e->offset);
378 dp = page + strlen(page);
379 for (i = 0; i < e->size; i++) {
380 sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
381 dp += 2;
383 if (e->mask) {
384 sprintf(dp, "\nmask ");
385 dp += 6;
386 for (i = 0; i < e->size; i++) {
387 sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
388 dp += 2;
391 *dp++ = '\n';
392 *dp = '\0';
394 if (e->flags & ENTRY_STRIP_EXT)
395 sprintf(dp, "extension stripped\n");
396 _out:
397 read_unlock(&entries_lock);
399 #endif
401 elen = strlen(page) - off;
402 if (elen < 0)
403 elen = 0;
404 *eof = (elen <= count) ? 1 : 0;
405 *start = page + off;
407 MOD_DEC_USE_COUNT;
408 return elen;
412 * Set status of entry/binfmt_misc:
413 * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
415 static int proc_write_status(struct file *file, const char *buffer,
416 unsigned long count, void *data)
418 struct binfmt_entry *e;
419 int res = count;
421 MOD_INC_USE_COUNT;
422 if (((buffer[0] == '1') || (buffer[0] == '0')) &&
423 ((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
424 if (data) {
425 read_lock(&entries_lock);
426 if ((e = get_entry((int) data)))
427 e->flags = (e->flags & -2) | (int) (buffer[0] - '0');
428 read_unlock(&entries_lock);
429 } else {
430 enabled = buffer[0] - '0';
432 } else if ((buffer[0] == '-') && (buffer[1] == '1') &&
433 ((count == 2) || ((count == 3) && (buffer[2] == '\n')))) {
434 if (data)
435 clear_entry((int) data);
436 else
437 clear_entries();
438 } else {
439 res = -EINVAL;
441 MOD_DEC_USE_COUNT;
442 return res;
446 * Remove the /proc-dir entries of one binfmt
448 static void entry_proc_cleanup(struct binfmt_entry *e)
450 remove_proc_entry(e->proc_name, bm_dir);
454 * Create the /proc-dir entry for binfmt
456 static int entry_proc_setup(struct binfmt_entry *e)
458 if (!(e->proc_dir = create_proc_entry(e->proc_name,
459 S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
460 return -ENOMEM;
462 e->proc_dir->data = (void *) (e->id);
463 e->proc_dir->read_proc = proc_read_status;
464 e->proc_dir->write_proc = proc_write_status;
466 return 0;
470 __initfunc(int init_misc_binfmt(void))
472 struct proc_dir_entry *status = NULL, *reg;
474 if (!(bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR,
475 NULL)) ||
476 !(status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
477 bm_dir)) ||
478 !(reg = create_proc_entry("register", S_IFREG | S_IWUSR,
479 bm_dir))) {
480 if (status)
481 remove_proc_entry("status", bm_dir);
482 if (bm_dir)
483 remove_proc_entry("sys/fs/binfmt_misc", NULL);
484 return -ENOMEM;
486 status->read_proc = proc_read_status;
487 status->write_proc = proc_write_status;
489 reg->write_proc = proc_write_register;
491 return register_binfmt(&misc_format);
494 #ifdef MODULE
495 EXPORT_NO_SYMBOLS;
496 int init_module(void)
498 return init_misc_binfmt();
501 void cleanup_module(void)
503 unregister_binfmt(&misc_format);
504 remove_proc_entry("register", bm_dir);
505 remove_proc_entry("status", bm_dir);
506 clear_entries();
507 remove_proc_entry("sys/fs/binfmt_misc", NULL);
509 #endif
510 #undef VERBOSE_STATUS