Import 2.2.8pre2
[davej-history.git] / fs / fcntl.c
blob036c9eb1fe968da2dd54d6cb400c699820ce3714
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(struct fown_struct *fown, struct fasync_struct *fa)
188 struct task_struct * p;
189 int pid = fown->pid;
190 uid_t uid = fown->uid;
191 uid_t euid = fown->euid;
193 read_lock(&tasklist_lock);
194 for_each_task(p) {
195 int match = p->pid;
196 if (pid < 0)
197 match = -p->pgrp;
198 if (pid != match)
199 continue;
200 if ((euid != 0) &&
201 (euid ^ p->suid) && (euid ^ p->uid) &&
202 (uid ^ p->suid) && (uid ^ p->uid))
203 continue;
204 switch (fown->signum) {
205 siginfo_t si;
206 default:
207 /* Queue a rt signal with the appropriate fd as its
208 value. We use SI_SIGIO as the source, not
209 SI_KERNEL, since kernel signals always get
210 delivered even if we can't queue. Failure to
211 queue in this case _should_ be reported; we fall
212 back to SIGIO in that case. --sct */
213 si.si_signo = fown->signum;
214 si.si_errno = 0;
215 si.si_code = SI_SIGIO;
216 si.si_pid = pid;
217 si.si_uid = uid;
218 si.si_fd = fa->fa_fd;
219 if (!send_sig_info(fown->signum, &si, p))
220 break;
221 /* fall-through: fall back on the old plain SIGIO signal */
222 case 0:
223 send_sig(SIGIO, p, 1);
226 read_unlock(&tasklist_lock);
229 void kill_fasync(struct fasync_struct *fa, int sig)
231 while (fa) {
232 struct fown_struct * fown;
233 if (fa->magic != FASYNC_MAGIC) {
234 printk("kill_fasync: bad magic number in "
235 "fasync_struct!\n");
236 return;
238 fown = &fa->fa_file->f_owner;
239 if (fown->pid)
240 send_sigio(fown, fa);
241 fa = fa->fa_next;