1/*
2 *  linux/fs/ioctl.c
3 *
4 *  Copyright (C) 1991, 1992  Linus Torvalds
5 */
6
7#include <linux/mm.h>
8#include <linux/smp_lock.h>
9#include <linux/file.h>
10
11#include <asm/uaccess.h>
12#include <asm/ioctls.h>
13
14static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
15{
16	int error;
17	int block;
18	struct inode * inode = filp->f_dentry->d_inode;
19
20	switch (cmd) {
21		case FIBMAP:
22		{
23			struct address_space *mapping = inode->i_mapping;
24			int res;
25			/* do we support this mess? */
26			if (!mapping->a_ops->bmap)
27				return -EINVAL;
28			if (!capable(CAP_SYS_RAWIO))
29				return -EPERM;
30			if ((error = get_user(block, (int *) arg)) != 0)
31				return error;
32
33			res = mapping->a_ops->bmap(mapping, block);
34			return put_user(res, (int *) arg);
35		}
36		case FIGETBSZ:
37			if (inode->i_sb == NULL)
38				return -EBADF;
39			return put_user(inode->i_sb->s_blocksize, (int *) arg);
40		case FIONREAD:
41			return put_user(inode->i_size - filp->f_pos, (int *) arg);
42	}
43	if (filp->f_op && filp->f_op->ioctl)
44		return filp->f_op->ioctl(inode, filp, cmd, arg);
45	return -ENOTTY;
46}
47
48
49asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
50{
51	struct file * filp;
52	unsigned int flag;
53	int on, error = -EBADF;
54
55	filp = fget(fd);
56	if (!filp)
57		goto out;
58	error = 0;
59	lock_kernel();
60	switch (cmd) {
61		case FIOCLEX:
62			set_close_on_exec(fd, 1);
63			break;
64
65		case FIONCLEX:
66			set_close_on_exec(fd, 0);
67			break;
68
69		case FIONBIO:
70			if ((error = get_user(on, (int *)arg)) != 0)
71				break;
72			flag = O_NONBLOCK;
73#ifdef __sparc__
74			/* SunOS compatibility item. */
75			if(O_NONBLOCK != O_NDELAY)
76				flag |= O_NDELAY;
77#endif
78			if (on)
79				filp->f_flags |= flag;
80			else
81				filp->f_flags &= ~flag;
82			break;
83
84		case FIOASYNC:
85			if ((error = get_user(on, (int *)arg)) != 0)
86				break;
87			flag = on ? FASYNC : 0;
88
89			/* Did FASYNC state change ? */
90			if ((flag ^ filp->f_flags) & FASYNC) {
91				if (filp->f_op && filp->f_op->fasync)
92					error = filp->f_op->fasync(fd, filp, on);
93				else error = -ENOTTY;
94			}
95			if (error != 0)
96				break;
97
98			if (on)
99				filp->f_flags |= FASYNC;
100			else
101				filp->f_flags &= ~FASYNC;
102			break;
103
104		default:
105			error = -ENOTTY;
106			if (S_ISREG(filp->f_dentry->d_inode->i_mode))
107				error = file_ioctl(filp, cmd, arg);
108			else if (filp->f_op && filp->f_op->ioctl)
109				error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
110	}
111	unlock_kernel();
112	fput(filp);
113
114out:
115	return error;
116}
117