diff options
author | Christoph Hellwig <hch@lst.de> | 2007-05-08 03:29:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:15:09 -0400 |
commit | 6272e2667965dfb5b59199f462cd0f001fb304a6 (patch) | |
tree | a14a4537dcd7af09863cc3a1c19a3efe386d67ab /fs/compat_ioctl.c | |
parent | 039b6b3ed84e45a6f8316358dd2bfdc83d59fc45 (diff) |
cleanup compat ioctl handling
Merge all compat ioctl handling into compat_ioctl.c instead of splitting it
over compat.c and compat_ioctl.c. This also allows to get rid of ioctl32.h
Signed-off-by: Christoph Hellwig <hch@lst.de>
Looks-good-to: Andi Kleen <ak@suse.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/compat_ioctl.c')
-rw-r--r-- | fs/compat_ioctl.c | 170 |
1 files changed, 165 insertions, 5 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index a0c3d2044e84..6972d242fbdf 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -57,7 +57,6 @@ | |||
57 | #include <linux/serial.h> | 57 | #include <linux/serial.h> |
58 | #include <linux/if_tun.h> | 58 | #include <linux/if_tun.h> |
59 | #include <linux/ctype.h> | 59 | #include <linux/ctype.h> |
60 | #include <linux/ioctl32.h> | ||
61 | #include <linux/syscalls.h> | 60 | #include <linux/syscalls.h> |
62 | #include <linux/i2c.h> | 61 | #include <linux/i2c.h> |
63 | #include <linux/i2c-dev.h> | 62 | #include <linux/i2c-dev.h> |
@@ -65,7 +64,6 @@ | |||
65 | #include <linux/atalk.h> | 64 | #include <linux/atalk.h> |
66 | #include <linux/blktrace_api.h> | 65 | #include <linux/blktrace_api.h> |
67 | 66 | ||
68 | #include <net/sock.h> /* siocdevprivate_ioctl */ | ||
69 | #include <net/bluetooth/bluetooth.h> | 67 | #include <net/bluetooth/bluetooth.h> |
70 | #include <net/bluetooth/hci.h> | 68 | #include <net/bluetooth/hci.h> |
71 | #include <net/bluetooth/rfcomm.h> | 69 | #include <net/bluetooth/rfcomm.h> |
@@ -474,7 +472,7 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
474 | }; | 472 | }; |
475 | } | 473 | } |
476 | 474 | ||
477 | int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | 475 | static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) |
478 | { | 476 | { |
479 | struct ifreq __user *u_ifreq64; | 477 | struct ifreq __user *u_ifreq64; |
480 | struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); | 478 | struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); |
@@ -2384,6 +2382,16 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
2384 | return sys_ioctl(fd, cmd, (unsigned long)tn); | 2382 | return sys_ioctl(fd, cmd, (unsigned long)tn); |
2385 | } | 2383 | } |
2386 | 2384 | ||
2385 | |||
2386 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, | ||
2387 | unsigned long, struct file *); | ||
2388 | |||
2389 | struct ioctl_trans { | ||
2390 | unsigned long cmd; | ||
2391 | ioctl_trans_handler_t handler; | ||
2392 | struct ioctl_trans *next; | ||
2393 | }; | ||
2394 | |||
2387 | #define HANDLE_IOCTL(cmd,handler) \ | 2395 | #define HANDLE_IOCTL(cmd,handler) \ |
2388 | { (cmd), (ioctl_trans_handler_t)(handler) }, | 2396 | { (cmd), (ioctl_trans_handler_t)(handler) }, |
2389 | 2397 | ||
@@ -2404,7 +2412,7 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
2404 | Most other reasons are not valid. */ | 2412 | Most other reasons are not valid. */ |
2405 | #define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd) | 2413 | #define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd) |
2406 | 2414 | ||
2407 | struct ioctl_trans ioctl_start[] = { | 2415 | static struct ioctl_trans ioctl_start[] = { |
2408 | /* compatible ioctls first */ | 2416 | /* compatible ioctls first */ |
2409 | COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ | 2417 | COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ |
2410 | COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ | 2418 | COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ |
@@ -3464,4 +3472,156 @@ IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32) | |||
3464 | IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32) | 3472 | IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32) |
3465 | }; | 3473 | }; |
3466 | 3474 | ||
3467 | int ioctl_table_size = ARRAY_SIZE(ioctl_start); | 3475 | #define IOCTL_HASHSIZE 256 |
3476 | static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; | ||
3477 | |||
3478 | static inline unsigned long ioctl32_hash(unsigned long cmd) | ||
3479 | { | ||
3480 | return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE; | ||
3481 | } | ||
3482 | |||
3483 | static void compat_ioctl_error(struct file *filp, unsigned int fd, | ||
3484 | unsigned int cmd, unsigned long arg) | ||
3485 | { | ||
3486 | char buf[10]; | ||
3487 | char *fn = "?"; | ||
3488 | char *path; | ||
3489 | |||
3490 | /* find the name of the device. */ | ||
3491 | path = (char *)__get_free_page(GFP_KERNEL); | ||
3492 | if (path) { | ||
3493 | fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE); | ||
3494 | if (IS_ERR(fn)) | ||
3495 | fn = "?"; | ||
3496 | } | ||
3497 | |||
3498 | sprintf(buf,"'%c'", (cmd>>_IOC_TYPESHIFT) & _IOC_TYPEMASK); | ||
3499 | if (!isprint(buf[1])) | ||
3500 | sprintf(buf, "%02x", buf[1]); | ||
3501 | compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) " | ||
3502 | "cmd(%08x){t:%s;sz:%u} arg(%08x) on %s\n", | ||
3503 | current->comm, current->pid, | ||
3504 | (int)fd, (unsigned int)cmd, buf, | ||
3505 | (cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK, | ||
3506 | (unsigned int)arg, fn); | ||
3507 | |||
3508 | if (path) | ||
3509 | free_page((unsigned long)path); | ||
3510 | } | ||
3511 | |||
3512 | asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | ||
3513 | unsigned long arg) | ||
3514 | { | ||
3515 | struct file *filp; | ||
3516 | int error = -EBADF; | ||
3517 | struct ioctl_trans *t; | ||
3518 | int fput_needed; | ||
3519 | |||
3520 | filp = fget_light(fd, &fput_needed); | ||
3521 | if (!filp) | ||
3522 | goto out; | ||
3523 | |||
3524 | /* RED-PEN how should LSM module know it's handling 32bit? */ | ||
3525 | error = security_file_ioctl(filp, cmd, arg); | ||
3526 | if (error) | ||
3527 | goto out_fput; | ||
3528 | |||
3529 | /* | ||
3530 | * To allow the compat_ioctl handlers to be self contained | ||
3531 | * we need to check the common ioctls here first. | ||
3532 | * Just handle them with the standard handlers below. | ||
3533 | */ | ||
3534 | switch (cmd) { | ||
3535 | case FIOCLEX: | ||
3536 | case FIONCLEX: | ||
3537 | case FIONBIO: | ||
3538 | case FIOASYNC: | ||
3539 | case FIOQSIZE: | ||
3540 | break; | ||
3541 | |||
3542 | case FIBMAP: | ||
3543 | case FIGETBSZ: | ||
3544 | case FIONREAD: | ||
3545 | if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) | ||
3546 | break; | ||
3547 | /*FALL THROUGH*/ | ||
3548 | |||
3549 | default: | ||
3550 | if (filp->f_op && filp->f_op->compat_ioctl) { | ||
3551 | error = filp->f_op->compat_ioctl(filp, cmd, arg); | ||
3552 | if (error != -ENOIOCTLCMD) | ||
3553 | goto out_fput; | ||
3554 | } | ||
3555 | |||
3556 | if (!filp->f_op || | ||
3557 | (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl)) | ||
3558 | goto do_ioctl; | ||
3559 | break; | ||
3560 | } | ||
3561 | |||
3562 | for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) { | ||
3563 | if (t->cmd == cmd) | ||
3564 | goto found_handler; | ||
3565 | } | ||
3566 | |||
3567 | if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) && | ||
3568 | cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { | ||
3569 | error = siocdevprivate_ioctl(fd, cmd, arg); | ||
3570 | } else { | ||
3571 | static int count; | ||
3572 | |||
3573 | if (++count <= 50) | ||
3574 | compat_ioctl_error(filp, fd, cmd, arg); | ||
3575 | error = -EINVAL; | ||
3576 | } | ||
3577 | |||
3578 | goto out_fput; | ||
3579 | |||
3580 | found_handler: | ||
3581 | if (t->handler) { | ||
3582 | lock_kernel(); | ||
3583 | error = t->handler(fd, cmd, arg, filp); | ||
3584 | unlock_kernel(); | ||
3585 | goto out_fput; | ||
3586 | } | ||
3587 | |||
3588 | do_ioctl: | ||
3589 | error = vfs_ioctl(filp, fd, cmd, arg); | ||
3590 | out_fput: | ||
3591 | fput_light(filp, fput_needed); | ||
3592 | out: | ||
3593 | return error; | ||
3594 | } | ||
3595 | |||
3596 | static void ioctl32_insert_translation(struct ioctl_trans *trans) | ||
3597 | { | ||
3598 | unsigned long hash; | ||
3599 | struct ioctl_trans *t; | ||
3600 | |||
3601 | hash = ioctl32_hash (trans->cmd); | ||
3602 | if (!ioctl32_hash_table[hash]) | ||
3603 | ioctl32_hash_table[hash] = trans; | ||
3604 | else { | ||
3605 | t = ioctl32_hash_table[hash]; | ||
3606 | while (t->next) | ||
3607 | t = t->next; | ||
3608 | trans->next = NULL; | ||
3609 | t->next = trans; | ||
3610 | } | ||
3611 | } | ||
3612 | |||
3613 | static int __init init_sys32_ioctl(void) | ||
3614 | { | ||
3615 | int i; | ||
3616 | |||
3617 | for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) { | ||
3618 | if (ioctl_start[i].next != 0) { | ||
3619 | printk("ioctl translation %d bad\n",i); | ||
3620 | return -1; | ||
3621 | } | ||
3622 | |||
3623 | ioctl32_insert_translation(&ioctl_start[i]); | ||
3624 | } | ||
3625 | return 0; | ||
3626 | } | ||
3627 | __initcall(init_sys32_ioctl); | ||