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