Import 2.3.7pre9
[davej-history.git] / fs / fcntl.c
blob666d88881d9f366cdf64d07e122799c3125cb979
1 /*
2 * linux/fs/fcntl.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/mm.h>
8 #include <linux/file.h>
9 #include <linux/smp_lock.h>
11 #include <asm/uaccess.h>
13 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
15 static inline int dupfd(unsigned int fd, unsigned int arg)
17 struct files_struct * files = current->files;
18 struct file * file;
19 int error;
21 error = -EINVAL;
22 if (arg >= NR_OPEN)
23 goto out;
25 error = -EBADF;
26 file = fget(fd);
27 if (!file)
28 goto out;
30 error = -EMFILE;
31 arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
32 if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
33 goto out_putf;
34 FD_SET(arg, &files->open_fds);
35 FD_CLR(arg, &files->close_on_exec);
36 fd_install(arg, file);
37 error = arg;
38 out:
39 return error;
41 out_putf:
42 fput(file);
43 goto out;
46 asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
48 int err = -EBADF;
50 lock_kernel();
51 if (!fcheck(oldfd))
52 goto out;
53 err = newfd;
54 if (newfd == oldfd)
55 goto out;
56 err = -EBADF;
57 if (newfd >= NR_OPEN)
58 goto out; /* following POSIX.1 6.2.1 */
60 sys_close(newfd);
61 err = dupfd(oldfd, newfd);
62 out:
63 unlock_kernel();
64 return err;
67 asmlinkage int sys_dup(unsigned int fildes)
69 int ret;
71 lock_kernel();
72 ret = dupfd(fildes, 0);
73 unlock_kernel();
74 return ret;
77 #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
79 static int setfl(int fd, struct file * filp, unsigned long arg)
81 struct inode * inode = filp->f_dentry->d_inode;
84 * In the case of an append-only file, O_APPEND
85 * cannot be cleared
87 if (!(arg & O_APPEND) && IS_APPEND(inode))
88 return -EPERM;
90 /* Did FASYNC state change? */
91 if ((arg ^ filp->f_flags) & FASYNC) {
92 if (filp->f_op && filp->f_op->fasync)
93 filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
96 /* required for strict SunOS emulation */
97 if (O_NONBLOCK != O_NDELAY)
98 if (arg & O_NDELAY)
99 arg |= O_NONBLOCK;
101 filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
102 return 0;
105 asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
107 struct file * filp;
108 long err = -EBADF;
110 lock_kernel();
111 filp = fget(fd);
112 if (!filp)
113 goto out;
114 err = 0;
115 switch (cmd) {
116 case F_DUPFD:
117 err = dupfd(fd, arg);
118 break;
119 case F_GETFD:
120 err = FD_ISSET(fd, &current->files->close_on_exec);
121 break;
122 case F_SETFD:
123 if (arg&1)
124 FD_SET(fd, &current->files->close_on_exec);
125 else
126 FD_CLR(fd, &current->files->close_on_exec);
127 break;
128 case F_GETFL:
129 err = filp->f_flags;
130 break;
131 case F_SETFL:
132 err = setfl(fd, filp, arg);
133 break;
134 case F_GETLK:
135 err = fcntl_getlk(fd, (struct flock *) arg);
136 break;
137 case F_SETLK:
138 err = fcntl_setlk(fd, cmd, (struct flock *) arg);
139 break;
140 case F_SETLKW:
141 err = fcntl_setlk(fd, cmd, (struct flock *) arg);
142 break;
143 case F_GETOWN:
145 * XXX If f_owner is a process group, the
146 * negative return value will get converted
147 * into an error. Oops. If we keep the
148 * current syscall conventions, the only way
149 * to fix this will be in libc.
151 err = filp->f_owner.pid;
152 break;
153 case F_SETOWN:
154 err = 0;
155 filp->f_owner.pid = arg;
156 filp->f_owner.uid = current->uid;
157 filp->f_owner.euid = current->euid;
158 if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
159 err = sock_fcntl (filp, F_SETOWN, arg);
160 break;
161 case F_GETSIG:
162 err = filp->f_owner.signum;
163 break;
164 case F_SETSIG:
165 if (arg <= 0 || arg > _NSIG) {
166 err = -EINVAL;
167 break;
169 err = 0;
170 filp->f_owner.signum = arg;
171 break;
172 default:
173 /* sockets need a few special fcntls. */
174 if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
175 err = sock_fcntl (filp, cmd, arg);
176 else
177 err = -EINVAL;
178 break;
180 fput(filp);
181 out:
182 unlock_kernel();
183 return err;
186 static void send_sigio_to_task(struct task_struct *p,
187 struct fown_struct *fown, struct fasync_struct *fa)
189 if ((fown->euid != 0) &&
190 (fown->euid ^ p->suid) && (fown->euid ^ p->uid) &&
191 (fown->uid ^ p->suid) && (fown->uid ^ p->uid))
192 return;
193 switch (fown->signum) {
194 siginfo_t si;
195 default:
196 /* Queue a rt signal with the appropriate fd as its
197 value. We use SI_SIGIO as the source, not
198 SI_KERNEL, since kernel signals always get
199 delivered even if we can't queue. Failure to
200 queue in this case _should_ be reported; we fall
201 back to SIGIO in that case. --sct */
202 si.si_signo = fown->signum;
203 si.si_errno = 0;
204 si.si_code = SI_SIGIO;
205 si.si_pid = fown->pid;
206 si.si_uid = fown->uid;
207 si.si_fd = fa->fa_fd;
208 if (!send_sig_info(fown->signum, &si, p))
209 break;
210 /* fall-through: fall back on the old plain SIGIO signal */
211 case 0:
212 send_sig(SIGIO, p, 1);
216 static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
218 struct task_struct * p;
219 int pid = fown->pid;
221 read_lock(&tasklist_lock);
222 if ( (pid > 0) && (p = find_task_by_pid(pid)) ) {
223 send_sigio_to_task(p, fown, fa);
224 goto out;
226 for_each_task(p) {
227 int match = p->pid;
228 if (pid < 0)
229 match = -p->pgrp;
230 if (pid != match)
231 continue;
232 send_sigio_to_task(p, fown, fa);
234 out:
235 read_unlock(&tasklist_lock);
238 void kill_fasync(struct fasync_struct *fa, int sig)
240 while (fa) {
241 struct fown_struct * fown;
242 if (fa->magic != FASYNC_MAGIC) {
243 printk("kill_fasync: bad magic number in "
244 "fasync_struct!\n");
245 return;
247 fown = &fa->fa_file->f_owner;
248 if (fown->pid)
249 send_sigio(fown, fa);
250 fa = fa->fa_next;