1 /*
2 * linux/fs/fcntl.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7 #include <asm/segment.h>
8
9 #include <linux/sched.h>
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/stat.h>
13 #include <linux/fcntl.h>
14 #include <linux/string.h>
15
16 extern int fcntl_getlk(unsigned int, struct flock *);
17 extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
18 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
19
20 static int dupfd(unsigned int fd, unsigned int arg)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
21 {
22 if (fd >= NR_OPEN || !current->files->fd[fd])
23 return -EBADF;
24 if (arg >= NR_OPEN)
25 return -EINVAL;
26 while (arg < NR_OPEN)
27 if (current->files->fd[arg])
28 arg++;
29 else
30 break;
31 if (arg >= NR_OPEN)
32 return -EMFILE;
33 FD_CLR(arg, ¤t->files->close_on_exec);
34 (current->files->fd[arg] = current->files->fd[fd])->f_count++;
35 return arg;
36 }
37
38 asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
39 {
40 if (oldfd >= NR_OPEN || !current->files->fd[oldfd])
41 return -EBADF;
42 if (newfd == oldfd)
43 return newfd;
44 /*
45 * errno's for dup2() are slightly different than for fcntl(F_DUPFD)
46 * for historical reasons.
47 */
48 if (newfd > NR_OPEN) /* historical botch - should have been >= */
49 return -EBADF; /* dupfd() would return -EINVAL */
50 #if 1
51 if (newfd == NR_OPEN)
52 return -EBADF; /* dupfd() does return -EINVAL and that may
53 * even be the standard! But that is too
54 * weird for now.
55 */
56 #endif
57 sys_close(newfd);
58 return dupfd(oldfd,newfd);
59 }
60
61 asmlinkage int sys_dup(unsigned int fildes)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
62 {
63 return dupfd(fildes,0);
64 }
65
66 asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
67 {
68 struct file * filp;
69 struct task_struct *p;
70 int task_found = 0;
71
72 if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
73 return -EBADF;
74 switch (cmd) {
75 case F_DUPFD:
76 return dupfd(fd,arg);
77 case F_GETFD:
78 return FD_ISSET(fd, ¤t->files->close_on_exec);
79 case F_SETFD:
80 if (arg&1)
81 FD_SET(fd, ¤t->files->close_on_exec);
82 else
83 FD_CLR(fd, ¤t->files->close_on_exec);
84 return 0;
85 case F_GETFL:
86 return filp->f_flags;
87 case F_SETFL:
88 /*
89 * In the case of an append-only file, O_APPEND
90 * cannot be cleared
91 */
92 if (IS_APPEND(filp->f_inode) && !(arg & O_APPEND))
93 return -EPERM;
94 if ((arg & FASYNC) && !(filp->f_flags & FASYNC) &&
95 filp->f_op->fasync)
96 filp->f_op->fasync(filp->f_inode, filp, 1);
97 if (!(arg & FASYNC) && (filp->f_flags & FASYNC) &&
98 filp->f_op->fasync)
99 filp->f_op->fasync(filp->f_inode, filp, 0);
100 filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC);
101 filp->f_flags |= arg & (O_APPEND | O_NONBLOCK |
102 FASYNC);
103 return 0;
104 case F_GETLK:
105 return fcntl_getlk(fd, (struct flock *) arg);
106 case F_SETLK:
107 return fcntl_setlk(fd, cmd, (struct flock *) arg);
108 case F_SETLKW:
109 return fcntl_setlk(fd, cmd, (struct flock *) arg);
110 case F_GETOWN:
111 /*
112 * XXX If f_owner is a process group, the
113 * negative return value will get converted
114 * into an error. Oops. If we keep the the
115 * current syscall conventions, the only way
116 * to fix this will be in libc.
117 */
118 return filp->f_owner;
119 case F_SETOWN:
120 /*
121 * Add the security checks - AC. Without
122 * this there is a massive Linux security
123 * hole here - consider what happens if
124 * you do something like
125 *
126 * fcntl(0,F_SETOWN,some_root_process);
127 * getchar();
128 *
129 * and input a line!
130 *
131 * BTW: Don't try this for fun. Several Unix
132 * systems I tried this on fall for the
133 * trick!
134 *
135 * I had to fix this botch job as Linux
136 * kill_fasync asserts priv making it a
137 * free all user process killer!
138 *
139 * Changed to make the security checks more
140 * liberal. -- TYT
141 */
142 if (current->pgrp == -arg || current->pid == arg)
143 goto fasync_ok;
144
145 for_each_task(p) {
146 if ((p->pid == arg) || (p->pid == -arg) ||
147 (p->pgrp == -arg)) {
148 task_found++;
149 if ((p->session != current->session) &&
150 (p->uid != current->uid) &&
151 (p->euid != current->euid) &&
152 !suser())
153 return -EPERM;
154 break;
155 }
156 }
157 if ((task_found == 0) && !suser())
158 return -EINVAL;
159 fasync_ok:
160 filp->f_owner = arg;
161 if (S_ISSOCK (filp->f_inode->i_mode))
162 sock_fcntl (filp, F_SETOWN, arg);
163 return 0;
164 default:
165 /* sockets need a few special fcntls. */
166 if (S_ISSOCK (filp->f_inode->i_mode))
167 {
168 return (sock_fcntl (filp, cmd, arg));
169 }
170 return -EINVAL;
171 }
172 }
173
174 void kill_fasync(struct fasync_struct *fa, int sig)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
175 {
176 while (fa) {
177 if (fa->magic != FASYNC_MAGIC) {
178 printk("kill_fasync: bad magic number in "
179 "fasync_struct!\n");
180 return;
181 }
182 if (fa->fa_file->f_owner > 0)
183 kill_proc(fa->fa_file->f_owner, sig, 1);
184 else
185 kill_pg(-fa->fa_file->f_owner, sig, 1);
186 fa = fa->fa_next;
187 }
188 }