4 * Copyright (c) 1982, 1986, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)tty_tty.c 8.2 (Berkeley) 9/23/93
32 * $FreeBSD: src/sys/kern/tty_tty.c,v 1.30 1999/09/25 18:24:24 phk Exp $
36 * Indirect driver for controlling tty.
39 #include <sys/param.h>
40 #include <sys/systm.h>
42 #include <sys/device.h>
44 #include <sys/fcntl.h>
46 #include <sys/ttycom.h>
47 #include <sys/vnode.h>
48 #include <sys/kernel.h>
49 #include <sys/poll.h> /* XXX: poll args used in KQ filters */
50 #include <sys/event.h>
52 static d_open_t cttyopen
;
53 static d_close_t cttyclose
;
54 static d_read_t cttyread
;
55 static d_write_t cttywrite
;
56 static d_ioctl_t cttyioctl
;
57 static d_kqfilter_t cttykqfilter
;
59 static void cttyfilt_detach(struct knote
*);
60 static int cttyfilt_read(struct knote
*, long);
61 static int cttyfilt_write(struct knote
*, long);
64 static struct dev_ops ctty_ops
= {
65 { "ctty", 0, D_TTY
| D_MPSAFE
},
71 .d_kqfilter
= cttykqfilter
74 #define cttyvp(p) (((p)->p_flags & P_CONTROLT) ? \
75 (p)->p_session->s_ttyvp : NULL)
78 * This opens /dev/tty. Because multiple opens of /dev/tty only
79 * generate a single open to the actual tty, the file modes are
80 * locked to FREAD|FWRITE.
83 cttyopen(struct dev_open_args
*ap
)
85 struct proc
*p
= curproc
;
91 if ((ttyvp
= cttyvp(p
)) == NULL
)
93 if (ttyvp
->v_flag
& VCTTYISOPEN
)
97 * Messy interlock, don't let the vnode go away while we try to
98 * lock it and check for race after we might have blocked.
100 * WARNING! The device open (devfs_spec_open()) temporarily
101 * releases the vnode lock on ttyvp when issuing the
102 * dev_dopen(), which means that the VCTTYISOPEn flag
103 * can race during the VOP_OPEN().
105 * If something does race we have to undo our potentially
109 vn_lock(ttyvp
, LK_EXCLUSIVE
| LK_RETRY
);
110 if (ttyvp
!= cttyvp(p
) || (ttyvp
->v_flag
& VCTTYISOPEN
)) {
111 kprintf("Warning: cttyopen: race-1 avoided\n");
116 error
= VOP_OPEN(ttyvp
, FREAD
|FWRITE
, ap
->a_cred
, NULL
);
117 if (ttyvp
!= cttyvp(p
) || (ttyvp
->v_flag
& VCTTYISOPEN
)) {
118 kprintf("Warning: cttyopen: race-2 avoided\n");
120 VOP_CLOSE(ttyvp
, FREAD
|FWRITE
, NULL
);
126 vsetflags(ttyvp
, VCTTYISOPEN
);
133 * This closes /dev/tty. Because multiple opens of /dev/tty only
134 * generate a single open to the actual tty, the file modes are
135 * locked to FREAD|FWRITE.
138 cttyclose(struct dev_close_args
*ap
)
140 struct proc
*p
= curproc
;
147 * The tty may have been TIOCNOTTY'd, don't return an
148 * error on close. We just have nothing to do.
150 if ((ttyvp
= cttyvp(p
)) == NULL
)
152 if (ttyvp
->v_flag
& VCTTYISOPEN
) {
154 * Avoid a nasty race if we block while getting the lock.
157 error
= vn_lock(ttyvp
, LK_EXCLUSIVE
| LK_RETRY
|
163 if (ttyvp
!= cttyvp(p
) || (ttyvp
->v_flag
& VCTTYISOPEN
) == 0) {
164 kprintf("Warning: cttyclose: race avoided\n");
169 vclrflags(ttyvp
, VCTTYISOPEN
);
170 error
= VOP_CLOSE(ttyvp
, FREAD
|FWRITE
, NULL
);
180 * Read from the controlling terminal (/dev/tty). The tty is refed as
181 * of the cttyvp(), but the ref can get ripped out from under us if
182 * the controlling terminal is revoked while we are blocked on the lock,
183 * so use vget() instead of vn_lock().
186 cttyread(struct dev_read_args
*ap
)
188 struct proc
*p
= curproc
;
196 if ((error
= vget(ttyvp
, LK_EXCLUSIVE
| LK_RETRY
)) == 0) {
197 error
= VOP_READ(ttyvp
, ap
->a_uio
, ap
->a_ioflag
, NOCRED
);
204 * Read from the controlling terminal (/dev/tty). The tty is refed as
205 * of the cttyvp(), but the ref can get ripped out from under us if
206 * the controlling terminal is revoked while we are blocked on the lock,
207 * so use vget() instead of vn_lock().
210 cttywrite(struct dev_write_args
*ap
)
212 struct proc
*p
= curproc
;
220 if ((error
= vget(ttyvp
, LK_EXCLUSIVE
| LK_RETRY
)) == 0) {
221 error
= VOP_WRITE(ttyvp
, ap
->a_uio
, ap
->a_ioflag
, NOCRED
);
229 cttyioctl(struct dev_ioctl_args
*ap
)
232 struct proc
*p
= curproc
;
235 lwkt_gettoken(&p
->p_token
);
238 lwkt_reltoken(&p
->p_token
);
242 * Don't allow controlling tty to be set to the controlling tty
243 * (infinite recursion).
245 if (ap
->a_cmd
== TIOCSCTTY
) {
246 lwkt_reltoken(&p
->p_token
);
249 if (ap
->a_cmd
== TIOCNOTTY
) {
250 if (!SESS_LEADER(p
)) {
251 p
->p_flags
&= ~P_CONTROLT
;
252 lwkt_reltoken(&p
->p_token
);
255 lwkt_reltoken(&p
->p_token
);
259 lwkt_reltoken(&p
->p_token
);
261 return (VOP_IOCTL(ttyvp
, ap
->a_cmd
, ap
->a_data
, ap
->a_fflag
,
262 ap
->a_cred
, ap
->a_sysmsg
));
265 static struct filterops cttyfiltops_read
=
266 { FILTEROP_ISFD
| FILTEROP_MPSAFE
, NULL
,
267 cttyfilt_detach
, cttyfilt_read
};
268 static struct filterops cttyfiltops_write
=
269 { FILTEROP_ISFD
| FILTEROP_MPSAFE
, NULL
,
270 cttyfilt_detach
, cttyfilt_write
};
273 cttykqfilter(struct dev_kqfilter_args
*ap
)
275 cdev_t dev
= ap
->a_head
.a_dev
;
276 struct proc
*p
= curproc
;
277 struct knote
*kn
= ap
->a_kn
;
284 return (VOP_KQFILTER(ttyvp
, kn
));
288 switch (kn
->kn_filter
) {
290 kn
->kn_fop
= &cttyfiltops_read
;
291 kn
->kn_hook
= (caddr_t
)dev
;
294 kn
->kn_fop
= &cttyfiltops_write
;
295 kn
->kn_hook
= (caddr_t
)dev
;
298 ap
->a_result
= EOPNOTSUPP
;
306 cttyfilt_detach(struct knote
*kn
) {}
309 cttyfilt_read(struct knote
*kn
, long hint
)
311 cdev_t dev
= (cdev_t
)kn
->kn_hook
;
313 if (seltrue(dev
, POLLIN
| POLLRDNORM
))
320 cttyfilt_write(struct knote
*kn
, long hint
)
322 cdev_t dev
= (cdev_t
)kn
->kn_hook
;
324 if (seltrue(dev
, POLLOUT
| POLLWRNORM
))
331 ctty_drvinit(void *unused __unused
)
333 make_dev(&ctty_ops
, 0, 0, 0, 0666, "tty");
336 SYSINIT(cttydev
, SI_SUB_DRIVERS
, SI_ORDER_MIDDLE
+ CDEV_MAJOR
,