xref: /openbmc/linux/fs/ioctl.c (revision 545e4006)
1 /*
2  *  linux/fs/ioctl.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6 
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>
16 
17 #include <asm/ioctls.h>
18 
19 /**
20  * vfs_ioctl - call filesystem specific ioctl methods
21  * @filp:	open file to invoke ioctl method on
22  * @cmd:	ioctl command to execute
23  * @arg:	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  */
31 static long vfs_ioctl(struct file *filp, unsigned int cmd,
32 		      unsigned long arg)
33 {
34 	int error = -ENOTTY;
35 
36 	if (!filp->f_op)
37 		goto out;
38 
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();
49 	}
50 
51  out:
52 	return error;
53 }
54 
55 static 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 
74 static int file_ioctl(struct file *filp, unsigned int cmd,
75 		unsigned long arg)
76 {
77 	struct inode *inode = filp->f_path.dentry->d_inode;
78 	int __user *p = (int __user *)arg;
79 
80 	switch (cmd) {
81 	case FIBMAP:
82 		return ioctl_fibmap(filp, p);
83 	case FIGETBSZ:
84 		return put_user(inode->i_sb->s_blocksize, p);
85 	case FIONREAD:
86 		return put_user(i_size_read(inode) - filp->f_pos, p);
87 	}
88 
89 	return vfs_ioctl(filp, cmd, arg);
90 }
91 
92 static 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 
113 static 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) {
127 			lock_kernel();
128 			error = filp->f_op->fasync(fd, filp, on);
129 			unlock_kernel();
130 		} else
131 			error = -ENOTTY;
132 	}
133 	if (error)
134 		return error;
135 
136 	if (on)
137 		filp->f_flags |= FASYNC;
138 	else
139 		filp->f_flags &= ~FASYNC;
140 	return error;
141 }
142 
143 /*
144  * When you add any new common ioctls to the switches above and below
145  * please update compat_sys_ioctl() too.
146  *
147  * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
148  * It's just a simple helper for sys_ioctl and compat_sys_ioctl.
149  */
150 int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
151 	     unsigned long arg)
152 {
153 	int error = 0;
154 	int __user *argp = (int __user *)arg;
155 
156 	switch (cmd) {
157 	case FIOCLEX:
158 		set_close_on_exec(fd, 1);
159 		break;
160 
161 	case FIONCLEX:
162 		set_close_on_exec(fd, 0);
163 		break;
164 
165 	case FIONBIO:
166 		error = ioctl_fionbio(filp, argp);
167 		break;
168 
169 	case FIOASYNC:
170 		error = ioctl_fioasync(fd, filp, argp);
171 		break;
172 
173 	case FIOQSIZE:
174 		if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
175 		    S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
176 		    S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
177 			loff_t res =
178 				inode_get_bytes(filp->f_path.dentry->d_inode);
179 			error = copy_to_user((loff_t __user *)arg, &res,
180 					     sizeof(res)) ? -EFAULT : 0;
181 		} else
182 			error = -ENOTTY;
183 		break;
184 	default:
185 		if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
186 			error = file_ioctl(filp, cmd, arg);
187 		else
188 			error = vfs_ioctl(filp, cmd, arg);
189 		break;
190 	}
191 	return error;
192 }
193 
194 asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
195 {
196 	struct file *filp;
197 	int error = -EBADF;
198 	int fput_needed;
199 
200 	filp = fget_light(fd, &fput_needed);
201 	if (!filp)
202 		goto out;
203 
204 	error = security_file_ioctl(filp, cmd, arg);
205 	if (error)
206 		goto out_fput;
207 
208 	error = do_vfs_ioctl(filp, fd, cmd, arg);
209  out_fput:
210 	fput_light(filp, fput_needed);
211  out:
212 	return error;
213 }
214