Import 2.1.112pre1
[davej-history.git] / fs / fcntl.c
bloba35db83a864942d6bffdd22921a256c525e3abc8
1 /*
2 * linux/fs/fcntl.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/sched.h>
8 #include <linux/kernel.h>
9 #include <linux/errno.h>
10 #include <linux/stat.h>
11 #include <linux/fcntl.h>
12 #include <linux/file.h>
13 #include <linux/string.h>
14 #include <linux/mm.h>
15 #include <linux/smp.h>
16 #include <linux/smp_lock.h>
18 #include <asm/bitops.h>
19 #include <asm/uaccess.h>
21 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
23 static inline int dupfd(unsigned int fd, unsigned int arg)
25 struct files_struct * files = current->files;
26 struct file * file;
27 int error;
29 error = -EINVAL;
30 if (arg >= NR_OPEN)
31 goto out;
33 error = -EBADF;
34 file = fget(fd);
35 if (!file)
36 goto out;
38 error = -EMFILE;
39 arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
40 if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
41 goto out_putf;
42 FD_SET(arg, &files->open_fds);
43 FD_CLR(arg, &files->close_on_exec);
44 fd_install(arg, file);
45 error = arg;
46 out:
47 return error;
49 out_putf:
50 fput(file);
51 goto out;
54 asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
56 int err = -EBADF;
58 lock_kernel();
59 if (!fcheck(oldfd))
60 goto out;
61 err = newfd;
62 if (newfd == oldfd)
63 goto out;
64 err = -EBADF;
65 if (newfd >= NR_OPEN)
66 goto out; /* following POSIX.1 6.2.1 */
68 sys_close(newfd);
69 err = dupfd(oldfd, newfd);
70 out:
71 unlock_kernel();
72 return err;
75 asmlinkage int sys_dup(unsigned int fildes)
77 int ret;
79 lock_kernel();
80 ret = dupfd(fildes, 0);
81 unlock_kernel();
82 return ret;
85 #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
87 static int setfl(struct file * filp, unsigned long arg)
89 struct inode * inode = filp->f_dentry->d_inode;
92 * In the case of an append-only file, O_APPEND
93 * cannot be cleared
95 if (!(arg & O_APPEND) && IS_APPEND(inode))
96 return -EPERM;
98 /* Did FASYNC state change? */
99 if ((arg ^ filp->f_flags) & FASYNC) {
100 if (filp->f_op->fasync)
101 filp->f_op->fasync(filp, (arg & FASYNC) != 0);
104 /* required for strict SunOS emulation */
105 if (O_NONBLOCK != O_NDELAY)
106 if (arg & O_NDELAY)
107 arg |= O_NONBLOCK;
109 filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
110 return 0;
113 asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
115 struct file * filp;
116 long err = -EBADF;
118 lock_kernel();
119 filp = fget(fd);
120 if (!filp)
121 goto out;
122 err = 0;
123 switch (cmd) {
124 case F_DUPFD:
125 err = dupfd(fd, arg);
126 break;
127 case F_GETFD:
128 err = FD_ISSET(fd, &current->files->close_on_exec);
129 break;
130 case F_SETFD:
131 if (arg&1)
132 FD_SET(fd, &current->files->close_on_exec);
133 else
134 FD_CLR(fd, &current->files->close_on_exec);
135 break;
136 case F_GETFL:
137 err = filp->f_flags;
138 break;
139 case F_SETFL:
140 err = setfl(filp, arg);
141 break;
142 case F_GETLK:
143 err = fcntl_getlk(fd, (struct flock *) arg);
144 break;
145 case F_SETLK:
146 err = fcntl_setlk(fd, cmd, (struct flock *) arg);
147 break;
148 case F_SETLKW:
149 err = fcntl_setlk(fd, cmd, (struct flock *) arg);
150 break;
151 case F_GETOWN:
153 * XXX If f_owner is a process group, the
154 * negative return value will get converted
155 * into an error. Oops. If we keep the
156 * current syscall conventions, the only way
157 * to fix this will be in libc.
159 err = filp->f_owner.pid;
160 break;
161 case F_SETOWN:
162 err = 0;
163 filp->f_owner.pid = arg;
164 filp->f_owner.uid = current->uid;
165 filp->f_owner.euid = current->euid;
166 if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
167 err = sock_fcntl (filp, F_SETOWN, arg);
168 break;
169 default:
170 /* sockets need a few special fcntls. */
171 if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
172 err = sock_fcntl (filp, cmd, arg);
173 else
174 err = -EINVAL;
175 break;
177 fput(filp);
178 out:
179 unlock_kernel();
180 return err;
183 static void send_sigio(int pid, uid_t uid, uid_t euid)
185 struct task_struct * p;
187 read_lock(&tasklist_lock);
188 for_each_task(p) {
189 int match = p->pid;
190 if (pid < 0)
191 match = -p->pgrp;
192 if (pid != match)
193 continue;
194 if ((euid != 0) &&
195 (euid ^ p->suid) && (euid ^ p->uid) &&
196 (uid ^ p->suid) && (uid ^ p->uid))
197 continue;
198 send_sig(SIGIO, p, 1);
199 if (p->state == TASK_INTERRUPTIBLE && signal_pending(p))
200 wake_up_process(p);
202 read_unlock(&tasklist_lock);
205 void kill_fasync(struct fasync_struct *fa, int sig)
207 while (fa) {
208 struct fown_struct * fown;
209 if (fa->magic != FASYNC_MAGIC) {
210 printk("kill_fasync: bad magic number in "
211 "fasync_struct!\n");
212 return;
214 fown = &fa->fa_file->f_owner;
215 if (fown->pid)
216 send_sigio(fown->pid, fown->uid, fown->euid);
217 fa = fa->fa_next;