pagecache-zeroing-zero_user_segment-zero_user_segments-and-zero_user
[linux-2.6/linux-trees-mm.git] / fs / ioctl.c
blob4ca348e18f60c22215d93cbd0e5b60098f736735
1 /*
2 * linux/fs/ioctl.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/syscalls.h>
8 #include <linux/mm.h>
9 #include <linux/smp_lock.h>
10 #include <linux/capability.h>
11 #include <linux/file.h>
12 #include <linux/fs.h>
13 #include <linux/security.h>
14 #include <linux/module.h>
15 #include <linux/uaccess.h>
17 #include <asm/ioctls.h>
19 /**
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
25 * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise
26 * invokes * filesystem specific ->ioctl method. If neither method exists,
27 * returns -ENOTTY.
29 * Returns 0 on success, -errno on error.
31 long vfs_ioctl(struct file *filp, unsigned int cmd,
32 unsigned long arg)
34 int error = -ENOTTY;
36 if (!filp->f_op)
37 goto out;
39 if (filp->f_op->unlocked_ioctl) {
40 error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
41 if (error == -ENOIOCTLCMD)
42 error = -EINVAL;
43 goto out;
44 } else if (filp->f_op->ioctl) {
45 lock_kernel();
46 error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
47 filp, cmd, arg);
48 unlock_kernel();
51 out:
52 return error;
54 EXPORT_SYMBOL_GPL(vfs_ioctl);
56 static int ioctl_fibmap(struct file *filp, int __user *p)
58 struct address_space *mapping = filp->f_mapping;
59 int res, block;
61 /* do we support this mess? */
62 if (!mapping->a_ops->bmap)
63 return -EINVAL;
64 if (!capable(CAP_SYS_RAWIO))
65 return -EPERM;
66 res = get_user(block, p);
67 if (res)
68 return res;
69 lock_kernel();
70 res = mapping->a_ops->bmap(mapping, block);
71 unlock_kernel();
72 return put_user(res, p);
75 static int file_ioctl(struct file *filp, unsigned int cmd,
76 unsigned long arg)
78 struct inode *inode = filp->f_path.dentry->d_inode;
79 int __user *p = (int __user *)arg;
81 switch (cmd) {
82 case FIBMAP:
83 return ioctl_fibmap(filp, p);
84 case FIGETBSZ:
85 return put_user(inode->i_sb->s_blocksize, p);
86 case FIONREAD:
87 return put_user(i_size_read(inode) - filp->f_pos, p);
90 return vfs_ioctl(filp, cmd, arg);
93 static int ioctl_fionbio(struct file *filp, int __user *argp)
95 unsigned int flag;
96 int on, error;
98 error = get_user(on, argp);
99 if (error)
100 return error;
101 flag = O_NONBLOCK;
102 #ifdef __sparc__
103 /* SunOS compatibility item. */
104 if (O_NONBLOCK != O_NDELAY)
105 flag |= O_NDELAY;
106 #endif
107 if (on)
108 filp->f_flags |= flag;
109 else
110 filp->f_flags &= ~flag;
111 return error;
114 static int ioctl_fioasync(unsigned int fd, struct file *filp,
115 int __user *argp)
117 unsigned int flag;
118 int on, error;
120 error = get_user(on, argp);
121 if (error)
122 return error;
123 flag = on ? FASYNC : 0;
125 /* Did FASYNC state change ? */
126 if ((flag ^ filp->f_flags) & FASYNC) {
127 if (filp->f_op && filp->f_op->fasync) {
128 lock_kernel();
129 error = filp->f_op->fasync(fd, filp, on);
130 unlock_kernel();
131 } else
132 error = -ENOTTY;
134 if (error)
135 return error;
137 if (on)
138 filp->f_flags |= FASYNC;
139 else
140 filp->f_flags &= ~FASYNC;
141 return error;
145 * When you add any new common ioctls to the switches above and below
146 * please update compat_sys_ioctl() too.
148 * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
149 * It's just a simple helper for sys_ioctl and compat_sys_ioctl.
151 int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
152 unsigned long arg)
154 int error = 0;
155 int __user *argp = (int __user *)arg;
157 switch (cmd) {
158 case FIOCLEX:
159 set_close_on_exec(fd, 1);
160 break;
162 case FIONCLEX:
163 set_close_on_exec(fd, 0);
164 break;
166 case FIONBIO:
167 error = ioctl_fionbio(filp, argp);
168 break;
170 case FIOASYNC:
171 error = ioctl_fioasync(fd, filp, argp);
172 break;
174 case FIOQSIZE:
175 if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
176 S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
177 S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
178 loff_t res =
179 inode_get_bytes(filp->f_path.dentry->d_inode);
180 error = copy_to_user((loff_t __user *)arg, &res,
181 sizeof(res)) ? -EFAULT : 0;
182 } else
183 error = -ENOTTY;
184 break;
185 default:
186 if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
187 error = file_ioctl(filp, cmd, arg);
188 else
189 error = vfs_ioctl(filp, cmd, arg);
190 break;
192 return error;
195 asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
197 struct file *filp;
198 int error = -EBADF;
199 int fput_needed;
201 filp = fget_light(fd, &fput_needed);
202 if (!filp)
203 goto out;
205 error = security_file_ioctl(filp, cmd, arg);
206 if (error)
207 goto out_fput;
209 error = do_vfs_ioctl(filp, fd, cmd, arg);
210 out_fput:
211 fput_light(filp, fput_needed);
212 out:
213 return error;