1
2
3
4
5
6
7#include <linux/mm.h>
8#include <linux/file.h>
9#include <linux/smp_lock.h>
10
11#include <asm/uaccess.h>
12
13extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
14
15static inline int dupfd(unsigned int fd, unsigned int start)
16{
17 struct files_struct * files = current->files;
18 struct file * file;
19 unsigned int newfd;
20 int error;
21
22 error = -EINVAL;
23 if (start >= NR_OPEN)
24 goto out;
25
26 error = -EBADF;
27 file = fget(fd);
28 if (!file)
29 goto out;
30
31repeat:
32 error = -EMFILE;
33 if (start < files->next_fd)
34 start = files->next_fd;
35
36#if 1
37 if (start > files->max_fdset)
38 printk (KERN_ERR "dupfd: fd %d, max %d\n",
39 start, files->max_fdset);
40#endif
41 newfd = find_next_zero_bit(files->open_fds->fds_bits,
42 files->max_fdset,
43 start);
44 if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
45 goto out_putf;
46
47 error = expand_files(files, newfd);
48 if (error < 0)
49 goto out_putf;
50 if (error)
51 goto repeat;
52
53 FD_SET(newfd, files->open_fds);
54 FD_CLR(newfd, files->close_on_exec);
55 if (start <= files->next_fd)
56 files->next_fd = newfd + 1;
57 fd_install(newfd, file);
58 error = newfd;
59out:
60#ifdef FDSET_DEBUG
61 if (error < 0)
62 printk (KERN_ERR __FUNCTION__ ": return %d\n", error);
63#endif
64 return error;
65
66out_putf:
67 fput(file);
68 goto out;
69}
70
71asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
72{
73 int err = -EBADF;
74
75 lock_kernel();
76#ifdef FDSET_DEBUG
77 printk (KERN_ERR __FUNCTION__ " 0: oldfd = %d, newfd = %d\n",
78 oldfd, newfd);
79#endif
80 if (!fcheck(oldfd))
81 goto out;
82 if (newfd >= NR_OPEN)
83 goto out;
84
85 err = newfd;
86 if (newfd == oldfd)
87 goto out;
88
89
90
91 if ((err = expand_files(current->files, newfd)) < 0)
92 goto out;
93
94 sys_close(newfd);
95 err = dupfd(oldfd, newfd);
96out:
97#ifdef FDSET_DEBUG
98 printk (KERN_ERR __FUNCTION__ ": return %d\n", err);
99#endif
100 unlock_kernel();
101 return err;
102}
103
104asmlinkage int sys_dup(unsigned int fildes)
105{
106 int ret;
107
108 lock_kernel();
109 ret = dupfd(fildes, 0);
110 unlock_kernel();
111#ifdef FDSET_DEBUG
112 if (ret < 0)
113 printk (KERN_ERR __FUNCTION__ ": return %d\n", ret);
114#endif
115 return ret;
116}
117
118#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
119
120static int setfl(int fd, struct file * filp, unsigned long arg)
121{
122 struct inode * inode = filp->f_dentry->d_inode;
123
124
125
126
127
128 if (!(arg & O_APPEND) && IS_APPEND(inode))
129 return -EPERM;
130
131
132 if ((arg ^ filp->f_flags) & FASYNC) {
133 if (filp->f_op && filp->f_op->fasync)
134 filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
135 }
136
137
138 if (O_NONBLOCK != O_NDELAY)
139 if (arg & O_NDELAY)
140 arg |= O_NONBLOCK;
141
142 filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
143 return 0;
144}
145
146asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
147{
148 struct file * filp;
149 long err = -EBADF;
150
151 lock_kernel();
152 filp = fget(fd);
153 if (!filp)
154 goto out;
155
156 err = 0;
157 switch (cmd) {
158 case F_DUPFD:
159 err = dupfd(fd, arg);
160 break;
161 case F_GETFD:
162 err = FD_ISSET(fd, current->files->close_on_exec);
163 break;
164 case F_SETFD:
165 if (arg&1)
166 FD_SET(fd, current->files->close_on_exec);
167 else
168 FD_CLR(fd, current->files->close_on_exec);
169 break;
170 case F_GETFL:
171 err = filp->f_flags;
172 break;
173 case F_SETFL:
174 err = setfl(fd, filp, arg);
175 break;
176 case F_GETLK:
177 err = fcntl_getlk(fd, (struct flock *) arg);
178 break;
179 case F_SETLK:
180 err = fcntl_setlk(fd, cmd, (struct flock *) arg);
181 break;
182 case F_SETLKW:
183 err = fcntl_setlk(fd, cmd, (struct flock *) arg);
184 break;
185 case F_GETOWN:
186
187
188
189
190
191
192
193 err = filp->f_owner.pid;
194 break;
195 case F_SETOWN:
196 filp->f_owner.pid = arg;
197 filp->f_owner.uid = current->uid;
198 filp->f_owner.euid = current->euid;
199 if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
200 err = sock_fcntl (filp, F_SETOWN, arg);
201 break;
202 case F_GETSIG:
203 err = filp->f_owner.signum;
204 break;
205 case F_SETSIG:
206 if (arg <= 0 || arg > _NSIG) {
207 err = -EINVAL;
208 break;
209 }
210 err = 0;
211 filp->f_owner.signum = arg;
212 break;
213 default:
214
215 err = -EINVAL;
216 if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
217 err = sock_fcntl (filp, cmd, arg);
218 break;
219 }
220 fput(filp);
221out:
222 unlock_kernel();
223 return err;
224}
225
226static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
227{
228 struct task_struct * p;
229 int pid = fown->pid;
230 uid_t uid = fown->uid;
231 uid_t euid = fown->euid;
232
233 read_lock(&tasklist_lock);
234 for_each_task(p) {
235 int match = p->pid;
236 if (pid < 0)
237 match = -p->pgrp;
238 if (pid != match)
239 continue;
240 if ((euid != 0) &&
241 (euid ^ p->suid) && (euid ^ p->uid) &&
242 (uid ^ p->suid) && (uid ^ p->uid))
243 continue;
244 switch (fown->signum) {
245 siginfo_t si;
246 default:
247
248
249
250
251
252
253 si.si_signo = fown->signum;
254 si.si_errno = 0;
255 si.si_code = SI_SIGIO;
256 si.si_pid = pid;
257 si.si_uid = uid;
258 si.si_fd = fa->fa_fd;
259 if (!send_sig_info(fown->signum, &si, p))
260 break;
261
262 case 0:
263 send_sig(SIGIO, p, 1);
264 }
265 }
266 read_unlock(&tasklist_lock);
267}
268
269void kill_fasync(struct fasync_struct *fa, int sig)
270{
271 while (fa) {
272 struct fown_struct * fown;
273 if (fa->magic != FASYNC_MAGIC) {
274 printk("kill_fasync: bad magic number in "
275 "fasync_struct!\n");
276 return;
277 }
278 fown = &fa->fa_file->f_owner;
279 if (fown->pid)
280 send_sigio(fown, fa);
281 fa = fa->fa_next;
282 }
283}
284