| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
#include <linux/mm.h> |
|---|
| 8 |
#include <linux/smp_lock.h> |
|---|
| 9 |
#include <linux/file.h> |
|---|
| 10 |
#include <linux/fs.h> |
|---|
| 11 |
#include <linux/security.h> |
|---|
| 12 |
|
|---|
| 13 |
#include <asm/uaccess.h> |
|---|
| 14 |
#include <asm/ioctls.h> |
|---|
| 15 |
#include <asm/callgate.h> |
|---|
| 16 |
|
|---|
| 17 |
static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) |
|---|
| 18 |
{ |
|---|
| 19 |
int error; |
|---|
| 20 |
int block; |
|---|
| 21 |
struct inode * inode = filp->f_dentry->d_inode; |
|---|
| 22 |
int __user *p = (int __user *)arg; |
|---|
| 23 |
|
|---|
| 24 |
switch (cmd) { |
|---|
| 25 |
case FIBMAP: |
|---|
| 26 |
{ |
|---|
| 27 |
struct address_space *mapping = filp->f_mapping; |
|---|
| 28 |
int res; |
|---|
| 29 |
|
|---|
| 30 |
if (!mapping->a_ops->bmap) |
|---|
| 31 |
return -EINVAL; |
|---|
| 32 |
if (!capable(CAP_SYS_RAWIO)) |
|---|
| 33 |
return -EPERM; |
|---|
| 34 |
if ((error = get_user(block, p)) != 0) |
|---|
| 35 |
return error; |
|---|
| 36 |
|
|---|
| 37 |
res = mapping->a_ops->bmap(mapping, block); |
|---|
| 38 |
return put_user(res, p); |
|---|
| 39 |
} |
|---|
| 40 |
case FIGETBSZ: |
|---|
| 41 |
if (inode->i_sb == NULL) |
|---|
| 42 |
return -EBADF; |
|---|
| 43 |
return put_user(inode->i_sb->s_blocksize, p); |
|---|
| 44 |
case FIONREAD: |
|---|
| 45 |
return put_user(i_size_read(inode) - filp->f_pos, p); |
|---|
| 46 |
} |
|---|
| 47 |
if (filp->f_op && filp->f_op->ioctl) { |
|---|
| 48 |
if ((unsigned long) filp->f_op->ioctl > PAGE_OFFSET) |
|---|
| 49 |
return filp->f_op->ioctl(inode, filp, cmd, arg); |
|---|
| 50 |
else { |
|---|
| 51 |
CALLDRIVER_PREP4(ioctl, inode, filp, cmd, arg) |
|---|
| 52 |
return calldriver((unsigned long) filp->f_op->ioctl, ioctl_args, ioctl_sizes, 4, current->mm, 3, 0); |
|---|
| 53 |
} |
|---|
| 54 |
} |
|---|
| 55 |
return -ENOTTY; |
|---|
| 56 |
} |
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) |
|---|
| 60 |
{ |
|---|
| 61 |
struct file * filp; |
|---|
| 62 |
unsigned int flag; |
|---|
| 63 |
int on, error = -EBADF; |
|---|
| 64 |
|
|---|
| 65 |
filp = fget(fd); |
|---|
| 66 |
if (!filp) |
|---|
| 67 |
goto out; |
|---|
| 68 |
|
|---|
| 69 |
error = security_file_ioctl(filp, cmd, arg); |
|---|
| 70 |
if (error) { |
|---|
| 71 |
fput(filp); |
|---|
| 72 |
goto out; |
|---|
| 73 |
} |
|---|
| 74 |
|
|---|
| 75 |
lock_kernel(); |
|---|
| 76 |
switch (cmd) { |
|---|
| 77 |
case FIOCLEX: |
|---|
| 78 |
set_close_on_exec(fd, 1); |
|---|
| 79 |
break; |
|---|
| 80 |
|
|---|
| 81 |
case FIONCLEX: |
|---|
| 82 |
set_close_on_exec(fd, 0); |
|---|
| 83 |
break; |
|---|
| 84 |
|
|---|
| 85 |
case FIONBIO: |
|---|
| 86 |
if ((error = get_user(on, (int __user *)arg)) != 0) |
|---|
| 87 |
break; |
|---|
| 88 |
flag = O_NONBLOCK; |
|---|
| 89 |
#ifdef __sparc__ |
|---|
| 90 |
|
|---|
| 91 |
if(O_NONBLOCK != O_NDELAY) |
|---|
| 92 |
flag |= O_NDELAY; |
|---|
| 93 |
#endif |
|---|
| 94 |
if (on) |
|---|
| 95 |
filp->f_flags |= flag; |
|---|
| 96 |
else |
|---|
| 97 |
filp->f_flags &= ~flag; |
|---|
| 98 |
break; |
|---|
| 99 |
|
|---|
| 100 |
case FIOASYNC: |
|---|
| 101 |
if ((error = get_user(on, (int __user *)arg)) != 0) |
|---|
| 102 |
break; |
|---|
| 103 |
flag = on ? FASYNC : 0; |
|---|
| 104 |
|
|---|
| 105 |
|
|---|
| 106 |
if ((flag ^ filp->f_flags) & FASYNC) { |
|---|
| 107 |
if (filp->f_op && filp->f_op->fasync) |
|---|
| 108 |
error = filp->f_op->fasync(fd, filp, on); |
|---|
| 109 |
else error = -ENOTTY; |
|---|
| 110 |
} |
|---|
| 111 |
if (error != 0) |
|---|
| 112 |
break; |
|---|
| 113 |
|
|---|
| 114 |
if (on) |
|---|
| 115 |
filp->f_flags |= FASYNC; |
|---|
| 116 |
else |
|---|
| 117 |
filp->f_flags &= ~FASYNC; |
|---|
| 118 |
break; |
|---|
| 119 |
|
|---|
| 120 |
case FIOQSIZE: |
|---|
| 121 |
if (S_ISDIR(filp->f_dentry->d_inode->i_mode) || |
|---|
| 122 |
S_ISREG(filp->f_dentry->d_inode->i_mode) || |
|---|
| 123 |
S_ISLNK(filp->f_dentry->d_inode->i_mode)) { |
|---|
| 124 |
loff_t res = inode_get_bytes(filp->f_dentry->d_inode); |
|---|
| 125 |
error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0; |
|---|
| 126 |
} |
|---|
| 127 |
else |
|---|
| 128 |
error = -ENOTTY; |
|---|
| 129 |
break; |
|---|
| 130 |
default: |
|---|
| 131 |
error = -ENOTTY; |
|---|
| 132 |
if (S_ISREG(filp->f_dentry->d_inode->i_mode)) |
|---|
| 133 |
error = file_ioctl(filp, cmd, arg); |
|---|
| 134 |
else if (filp->f_op && filp->f_op->ioctl) { |
|---|
| 135 |
if ((unsigned long) filp->f_op->ioctl > PAGE_OFFSET) |
|---|
| 136 |
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); |
|---|
| 137 |
else { |
|---|
| 138 |
CALLDRIVER_PREP4(ioctl, filp->f_dentry->d_inode, filp, cmd, arg) |
|---|
| 139 |
error=calldriver((unsigned long) filp->f_op->ioctl, ioctl_args, ioctl_sizes, 4, current->mm, 3, 0); |
|---|
| 140 |
} |
|---|
| 141 |
} |
|---|
| 142 |
|
|---|
| 143 |
} |
|---|
| 144 |
unlock_kernel(); |
|---|
| 145 |
fput(filp); |
|---|
| 146 |
|
|---|
| 147 |
out: |
|---|
| 148 |
return error; |
|---|
| 149 |
} |
|---|