kernel - Remove D_KQFILTER flag
[dragonfly.git] / sys / kern / tty_tty.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 1982, 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)tty_tty.c 8.2 (Berkeley) 9/23/93
34 * $FreeBSD: src/sys/kern/tty_tty.c,v 1.30 1999/09/25 18:24:24 phk Exp $
f1aeb0c0 35 * $DragonFly: src/sys/kern/tty_tty.c,v 1.19 2007/07/03 17:22:14 dillon Exp $
984263bc
MD
36 */
37
38/*
39 * Indirect driver for controlling tty.
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/conf.h>
fef8985e 45#include <sys/device.h>
984263bc 46#include <sys/lock.h>
84cca6ec 47#include <sys/fcntl.h>
984263bc
MD
48#include <sys/proc.h>
49#include <sys/ttycom.h>
50#include <sys/vnode.h>
51#include <sys/kernel.h>
163625b9 52#include <sys/poll.h> /* XXX: poll args used in KQ filters */
7d1f168a 53#include <sys/event.h>
984263bc
MD
54
55static d_open_t cttyopen;
e4c9c0c8 56static d_close_t cttyclose;
984263bc
MD
57static d_read_t cttyread;
58static d_write_t cttywrite;
59static d_ioctl_t cttyioctl;
7d1f168a
SG
60static d_kqfilter_t cttykqfilter;
61
62static void cttyfilt_detach(struct knote *);
63static int cttyfilt_read(struct knote *, long);
64static int cttyfilt_write(struct knote *, long);
984263bc
MD
65
66#define CDEV_MAJOR 1
67/* Don't make this static, since fdesc_vnops uses it. */
fef8985e 68struct dev_ops ctty_ops = {
d4b8aec4 69 { "ctty", CDEV_MAJOR, D_TTY },
fef8985e
MD
70 .d_open = cttyopen,
71 .d_close = cttyclose,
72 .d_read = cttyread,
73 .d_write = cttywrite,
74 .d_ioctl = cttyioctl,
7d1f168a 75 .d_kqfilter = cttykqfilter
984263bc
MD
76};
77
78#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
79
84cca6ec
MD
80/*
81 * This opens /dev/tty. Because multiple opens of /dev/tty only
82 * generate a single open to the actual tty, the file modes are
83 * locked to FREAD|FWRITE.
84 */
984263bc 85static int
fef8985e 86cttyopen(struct dev_open_args *ap)
984263bc 87{
fef8985e 88 struct proc *p = curproc;
41c20dac 89 struct vnode *ttyvp;
984263bc
MD
90 int error;
91
dadab5e9 92 KKASSERT(p);
f1aeb0c0
MD
93retry:
94 if ((ttyvp = cttyvp(p)) == NULL)
95 return (ENXIO);
96 if (ttyvp->v_flag & VCTTYISOPEN)
97 return (0);
98
99 /*
100 * Messy interlock, don't let the vnode go away while we try to
101 * lock it and check for race after we might have blocked.
102 */
103 vhold(ttyvp);
104 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
105 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) {
106 kprintf("Warning: cttyopen: race avoided\n");
107 vn_unlock(ttyvp);
108 vdrop(ttyvp);
109 goto retry;
e4c9c0c8 110 }
f1aeb0c0
MD
111 vsetflags(ttyvp, VCTTYISOPEN);
112 error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL);
113 if (error)
114 vclrflags(ttyvp, VCTTYISOPEN);
115 vn_unlock(ttyvp);
116 vdrop(ttyvp);
117 return(error);
984263bc
MD
118}
119
84cca6ec
MD
120/*
121 * This closes /dev/tty. Because multiple opens of /dev/tty only
122 * generate a single open to the actual tty, the file modes are
123 * locked to FREAD|FWRITE.
124 */
e4c9c0c8 125static int
fef8985e 126cttyclose(struct dev_close_args *ap)
e4c9c0c8 127{
fef8985e 128 struct proc *p = curproc;
e4c9c0c8
MD
129 struct vnode *ttyvp;
130 int error;
131
132 KKASSERT(p);
f1aeb0c0
MD
133retry:
134 /*
135 * The tty may have been TIOCNOTTY'd, don't return an
136 * error on close. We just have nothing to do.
137 */
138 if ((ttyvp = cttyvp(p)) == NULL)
139 return(0);
140 if (ttyvp->v_flag & VCTTYISOPEN) {
5fd012e0 141 /*
f1aeb0c0 142 * Avoid a nasty race if we block while getting the lock.
5fd012e0 143 */
8e73fd39 144 vref(ttyvp);
ca466bae 145 error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
f1aeb0c0 146 if (error) {
8e73fd39 147 vrele(ttyvp);
f1aeb0c0
MD
148 goto retry;
149 }
150 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN) == 0) {
151 kprintf("Warning: cttyclose: race avoided\n");
a11aaa81 152 vn_unlock(ttyvp);
8e73fd39 153 vrele(ttyvp);
f1aeb0c0 154 goto retry;
5fd012e0 155 }
f1aeb0c0
MD
156 vclrflags(ttyvp, VCTTYISOPEN);
157 error = VOP_CLOSE(ttyvp, FREAD|FWRITE);
158 vn_unlock(ttyvp);
8e73fd39 159 vrele(ttyvp);
5fd012e0
MD
160 } else {
161 error = 0;
162 }
e4c9c0c8
MD
163 return(error);
164}
165
84cca6ec
MD
166/*
167 * Read from the controlling terminal (/dev/tty). The tty is refed as
168 * of the cttyvp(), but the ref can get ripped out from under us if
169 * the controlling terminal is revoked while we are blocked on the lock,
a11aaa81 170 * so use vget() instead of vn_lock().
84cca6ec 171 */
984263bc 172static int
fef8985e 173cttyread(struct dev_read_args *ap)
984263bc 174{
fef8985e 175 struct proc *p = curproc;
dadab5e9 176 struct vnode *ttyvp;
984263bc
MD
177 int error;
178
dadab5e9
MD
179 KKASSERT(p);
180 ttyvp = cttyvp(p);
984263bc
MD
181 if (ttyvp == NULL)
182 return (EIO);
87de5057 183 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
fef8985e 184 error = VOP_READ(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
84cca6ec
MD
185 vput(ttyvp);
186 }
984263bc
MD
187 return (error);
188}
189
84cca6ec
MD
190/*
191 * Read from the controlling terminal (/dev/tty). The tty is refed as
192 * of the cttyvp(), but the ref can get ripped out from under us if
193 * the controlling terminal is revoked while we are blocked on the lock,
a11aaa81 194 * so use vget() instead of vn_lock().
84cca6ec 195 */
984263bc 196static int
fef8985e 197cttywrite(struct dev_write_args *ap)
984263bc 198{
fef8985e 199 struct proc *p = curproc;
dadab5e9 200 struct vnode *ttyvp;
984263bc
MD
201 int error;
202
dadab5e9
MD
203 KKASSERT(p);
204 ttyvp = cttyvp(p);
984263bc
MD
205 if (ttyvp == NULL)
206 return (EIO);
87de5057 207 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
fef8985e 208 error = VOP_WRITE(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
84cca6ec
MD
209 vput(ttyvp);
210 }
984263bc
MD
211 return (error);
212}
213
214/*ARGSUSED*/
215static int
fef8985e 216cttyioctl(struct dev_ioctl_args *ap)
984263bc 217{
41c20dac 218 struct vnode *ttyvp;
fef8985e 219 struct proc *p = curproc;
984263bc 220
dadab5e9
MD
221 KKASSERT(p);
222 ttyvp = cttyvp(p);
984263bc
MD
223 if (ttyvp == NULL)
224 return (EIO);
fef8985e
MD
225 /*
226 * Don't allow controlling tty to be set to the controlling tty
227 * (infinite recursion).
228 */
229 if (ap->a_cmd == TIOCSCTTY)
230 return EINVAL;
231 if (ap->a_cmd == TIOCNOTTY) {
dadab5e9
MD
232 if (!SESS_LEADER(p)) {
233 p->p_flag &= ~P_CONTROLT;
984263bc 234 return (0);
fef8985e 235 } else {
984263bc 236 return (EINVAL);
fef8985e 237 }
984263bc 238 }
87baaf0c
MD
239 return (VOP_IOCTL(ttyvp, ap->a_cmd, ap->a_data, ap->a_fflag,
240 ap->a_cred, ap->a_sysmsg));
984263bc
MD
241}
242
7d1f168a 243static struct filterops cttyfiltops_read =
4c91dbc9 244 { FILTEROP_ISFD, NULL, cttyfilt_detach, cttyfilt_read };
7d1f168a 245static struct filterops cttyfiltops_write =
4c91dbc9 246 { FILTEROP_ISFD, NULL, cttyfilt_detach, cttyfilt_write };
7d1f168a
SG
247
248static int
249cttykqfilter(struct dev_kqfilter_args *ap)
250{
251 cdev_t dev = ap->a_head.a_dev;
252 struct proc *p = curproc;
253 struct knote *kn = ap->a_kn;
254 struct vnode *ttyvp;
255
256 KKASSERT(p);
257 ttyvp = cttyvp(p);
258
259 if (ttyvp != NULL)
260 return (VOP_KQFILTER(ttyvp, kn));
261
262 ap->a_result = 0;
263
264 switch (kn->kn_filter) {
265 case EVFILT_READ:
266 kn->kn_fop = &cttyfiltops_read;
267 kn->kn_hook = (caddr_t)dev;
268 break;
269 case EVFILT_WRITE:
270 kn->kn_fop = &cttyfiltops_write;
271 kn->kn_hook = (caddr_t)dev;
272 break;
273 default:
b287d649 274 ap->a_result = EOPNOTSUPP;
7d1f168a
SG
275 return (0);
276 }
277
278 return (0);
279}
280
281static void
282cttyfilt_detach(struct knote *kn) {}
283
284static int
285cttyfilt_read(struct knote *kn, long hint)
286{
287 cdev_t dev = (cdev_t)kn->kn_hook;
288
289 if (seltrue(dev, POLLIN | POLLRDNORM))
290 return (1);
291
292 return (0);
293}
294
295static int
296cttyfilt_write(struct knote *kn, long hint)
297{
298 cdev_t dev = (cdev_t)kn->kn_hook;
299
300 if (seltrue(dev, POLLOUT | POLLWRNORM))
301 return (1);
302
303 return (0);
304}
305
984263bc 306static void
fef8985e 307ctty_drvinit(void *unused __unused)
984263bc 308{
fef8985e 309 make_dev(&ctty_ops, 0, 0, 0, 0666, "tty");
984263bc
MD
310}
311
312SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)