aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ioctl.c')
-rw-r--r--fs/ioctl.c223
1 files changed, 130 insertions, 93 deletions
diff --git a/fs/ioctl.c b/fs/ioctl.c
index c2a773e8620b..683002fefa55 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -12,12 +12,24 @@
12#include <linux/fs.h> 12#include <linux/fs.h>
13#include <linux/security.h> 13#include <linux/security.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/uaccess.h>
15 16
16#include <asm/uaccess.h>
17#include <asm/ioctls.h> 17#include <asm/ioctls.h>
18 18
19static long do_ioctl(struct file *filp, unsigned int cmd, 19/**
20 unsigned long arg) 20 * vfs_ioctl - call filesystem specific ioctl methods
21 * @filp: [in] open file to invoke ioctl method on
22 * @cmd: [in] ioctl command to execute
23 * @arg: [in/out] command-specific argument for ioctl
24 *
25 * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise
26 * invokes * filesystem specific ->ioctl method. If neither method exists,
27 * returns -ENOTTY.
28 *
29 * Returns 0 on success, -errno on error.
30 */
31long vfs_ioctl(struct file *filp, unsigned int cmd,
32 unsigned long arg)
21{ 33{
22 int error = -ENOTTY; 34 int error = -ENOTTY;
23 35
@@ -40,123 +52,148 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
40 return error; 52 return error;
41} 53}
42 54
55static int ioctl_fibmap(struct file *filp, int __user *p)
56{
57 struct address_space *mapping = filp->f_mapping;
58 int res, block;
59
60 /* do we support this mess? */
61 if (!mapping->a_ops->bmap)
62 return -EINVAL;
63 if (!capable(CAP_SYS_RAWIO))
64 return -EPERM;
65 res = get_user(block, p);
66 if (res)
67 return res;
68 lock_kernel();
69 res = mapping->a_ops->bmap(mapping, block);
70 unlock_kernel();
71 return put_user(res, p);
72}
73
43static int file_ioctl(struct file *filp, unsigned int cmd, 74static int file_ioctl(struct file *filp, unsigned int cmd,
44 unsigned long arg) 75 unsigned long arg)
45{ 76{
46 int error; 77 struct inode *inode = filp->f_path.dentry->d_inode;
47 int block;
48 struct inode * inode = filp->f_path.dentry->d_inode;
49 int __user *p = (int __user *)arg; 78 int __user *p = (int __user *)arg;
50 79
51 switch (cmd) { 80 switch (cmd) {
52 case FIBMAP: 81 case FIBMAP:
53 { 82 return ioctl_fibmap(filp, p);
54 struct address_space *mapping = filp->f_mapping; 83 case FIGETBSZ:
55 int res; 84 return put_user(inode->i_sb->s_blocksize, p);
56 /* do we support this mess? */ 85 case FIONREAD:
57 if (!mapping->a_ops->bmap) 86 return put_user(i_size_read(inode) - filp->f_pos, p);
58 return -EINVAL; 87 }
59 if (!capable(CAP_SYS_RAWIO))
60 return -EPERM;
61 if ((error = get_user(block, p)) != 0)
62 return error;
63 88
89 return vfs_ioctl(filp, cmd, arg);
90}
91
92static int ioctl_fionbio(struct file *filp, int __user *argp)
93{
94 unsigned int flag;
95 int on, error;
96
97 error = get_user(on, argp);
98 if (error)
99 return error;
100 flag = O_NONBLOCK;
101#ifdef __sparc__
102 /* SunOS compatibility item. */
103 if (O_NONBLOCK != O_NDELAY)
104 flag |= O_NDELAY;
105#endif
106 if (on)
107 filp->f_flags |= flag;
108 else
109 filp->f_flags &= ~flag;
110 return error;
111}
112
113static int ioctl_fioasync(unsigned int fd, struct file *filp,
114 int __user *argp)
115{
116 unsigned int flag;
117 int on, error;
118
119 error = get_user(on, argp);
120 if (error)
121 return error;
122 flag = on ? FASYNC : 0;
123
124 /* Did FASYNC state change ? */
125 if ((flag ^ filp->f_flags) & FASYNC) {
126 if (filp->f_op && filp->f_op->fasync) {
64 lock_kernel(); 127 lock_kernel();
65 res = mapping->a_ops->bmap(mapping, block); 128 error = filp->f_op->fasync(fd, filp, on);
66 unlock_kernel(); 129 unlock_kernel();
67 return put_user(res, p); 130 } else
68 } 131 error = -ENOTTY;
69 case FIGETBSZ:
70 return put_user(inode->i_sb->s_blocksize, p);
71 case FIONREAD:
72 return put_user(i_size_read(inode) - filp->f_pos, p);
73 } 132 }
133 if (error)
134 return error;
74 135
75 return do_ioctl(filp, cmd, arg); 136 if (on)
137 filp->f_flags |= FASYNC;
138 else
139 filp->f_flags &= ~FASYNC;
140 return error;
76} 141}
77 142
78/* 143/*
79 * When you add any new common ioctls to the switches above and below 144 * When you add any new common ioctls to the switches above and below
80 * please update compat_sys_ioctl() too. 145 * please update compat_sys_ioctl() too.
81 * 146 *
82 * vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. 147 * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
83 * It's just a simple helper for sys_ioctl and compat_sys_ioctl. 148 * It's just a simple helper for sys_ioctl and compat_sys_ioctl.
84 */ 149 */
85int vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg) 150int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
151 unsigned long arg)
86{ 152{
87 unsigned int flag; 153 int error = 0;
88 int on, error = 0; 154 int __user *argp = (int __user *)arg;
89 155
90 switch (cmd) { 156 switch (cmd) {
91 case FIOCLEX: 157 case FIOCLEX:
92 set_close_on_exec(fd, 1); 158 set_close_on_exec(fd, 1);
93 break; 159 break;
94 160
95 case FIONCLEX: 161 case FIONCLEX:
96 set_close_on_exec(fd, 0); 162 set_close_on_exec(fd, 0);
97 break; 163 break;
98 164
99 case FIONBIO: 165 case FIONBIO:
100 if ((error = get_user(on, (int __user *)arg)) != 0) 166 error = ioctl_fionbio(filp, argp);
101 break; 167 break;
102 flag = O_NONBLOCK; 168
103#ifdef __sparc__ 169 case FIOASYNC:
104 /* SunOS compatibility item. */ 170 error = ioctl_fioasync(fd, filp, argp);
105 if(O_NONBLOCK != O_NDELAY) 171 break;
106 flag |= O_NDELAY; 172
107#endif 173 case FIOQSIZE:
108 if (on) 174 if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
109 filp->f_flags |= flag; 175 S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
110 else 176 S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
111 filp->f_flags &= ~flag; 177 loff_t res =
112 break; 178 inode_get_bytes(filp->f_path.dentry->d_inode);
113 179 error = copy_to_user((loff_t __user *)arg, &res,
114 case FIOASYNC: 180 sizeof(res)) ? -EFAULT : 0;
115 if ((error = get_user(on, (int __user *)arg)) != 0) 181 } else
116 break; 182 error = -ENOTTY;
117 flag = on ? FASYNC : 0; 183 break;
118 184 default:
119 /* Did FASYNC state change ? */ 185 if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
120 if ((flag ^ filp->f_flags) & FASYNC) { 186 error = file_ioctl(filp, cmd, arg);
121 if (filp->f_op && filp->f_op->fasync) { 187 else
122 lock_kernel(); 188 error = vfs_ioctl(filp, cmd, arg);
123 error = filp->f_op->fasync(fd, filp, on); 189 break;
124 unlock_kernel();
125 }
126 else error = -ENOTTY;
127 }
128 if (error != 0)
129 break;
130
131 if (on)
132 filp->f_flags |= FASYNC;
133 else
134 filp->f_flags &= ~FASYNC;
135 break;
136
137 case FIOQSIZE:
138 if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
139 S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
140 S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
141 loff_t res = inode_get_bytes(filp->f_path.dentry->d_inode);
142 error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0;
143 }
144 else
145 error = -ENOTTY;
146 break;
147 default:
148 if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
149 error = file_ioctl(filp, cmd, arg);
150 else
151 error = do_ioctl(filp, cmd, arg);
152 break;
153 } 190 }
154 return error; 191 return error;
155} 192}
156 193
157asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 194asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
158{ 195{
159 struct file * filp; 196 struct file *filp;
160 int error = -EBADF; 197 int error = -EBADF;
161 int fput_needed; 198 int fput_needed;
162 199
@@ -168,7 +205,7 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
168 if (error) 205 if (error)
169 goto out_fput; 206 goto out_fput;
170 207
171 error = vfs_ioctl(filp, fd, cmd, arg); 208 error = do_vfs_ioctl(filp, fd, cmd, arg);
172 out_fput: 209 out_fput:
173 fput_light(filp, fput_needed); 210 fput_light(filp, fput_needed);
174 out: 211 out: