DEVFS - remove dev_ops_add(), dev_ops_get(), and get_dev()
[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>
52
53static d_open_t cttyopen;
e4c9c0c8 54static d_close_t cttyclose;
984263bc
MD
55static d_read_t cttyread;
56static d_write_t cttywrite;
57static d_ioctl_t cttyioctl;
58static d_poll_t cttypoll;
59
60#define CDEV_MAJOR 1
61/* Don't make this static, since fdesc_vnops uses it. */
fef8985e
MD
62struct dev_ops ctty_ops = {
63 { "ctty", CDEV_MAJOR, D_TTY },
64 .d_open = cttyopen,
65 .d_close = cttyclose,
66 .d_read = cttyread,
67 .d_write = cttywrite,
68 .d_ioctl = cttyioctl,
69 .d_poll = cttypoll,
984263bc
MD
70};
71
72#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
73
84cca6ec
MD
74/*
75 * This opens /dev/tty. Because multiple opens of /dev/tty only
76 * generate a single open to the actual tty, the file modes are
77 * locked to FREAD|FWRITE.
78 */
984263bc 79static int
fef8985e 80cttyopen(struct dev_open_args *ap)
984263bc 81{
fef8985e 82 struct proc *p = curproc;
41c20dac 83 struct vnode *ttyvp;
984263bc
MD
84 int error;
85
dadab5e9 86 KKASSERT(p);
f1aeb0c0
MD
87retry:
88 if ((ttyvp = cttyvp(p)) == NULL)
89 return (ENXIO);
90 if (ttyvp->v_flag & VCTTYISOPEN)
91 return (0);
92
93 /*
94 * Messy interlock, don't let the vnode go away while we try to
95 * lock it and check for race after we might have blocked.
96 */
97 vhold(ttyvp);
98 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
99 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) {
100 kprintf("Warning: cttyopen: race avoided\n");
101 vn_unlock(ttyvp);
102 vdrop(ttyvp);
103 goto retry;
e4c9c0c8 104 }
f1aeb0c0
MD
105 vsetflags(ttyvp, VCTTYISOPEN);
106 error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL);
107 if (error)
108 vclrflags(ttyvp, VCTTYISOPEN);
109 vn_unlock(ttyvp);
110 vdrop(ttyvp);
111 return(error);
984263bc
MD
112}
113
84cca6ec
MD
114/*
115 * This closes /dev/tty. Because multiple opens of /dev/tty only
116 * generate a single open to the actual tty, the file modes are
117 * locked to FREAD|FWRITE.
118 */
e4c9c0c8 119static int
fef8985e 120cttyclose(struct dev_close_args *ap)
e4c9c0c8 121{
fef8985e 122 struct proc *p = curproc;
e4c9c0c8
MD
123 struct vnode *ttyvp;
124 int error;
125
126 KKASSERT(p);
f1aeb0c0
MD
127retry:
128 /*
129 * The tty may have been TIOCNOTTY'd, don't return an
130 * error on close. We just have nothing to do.
131 */
132 if ((ttyvp = cttyvp(p)) == NULL)
133 return(0);
134 if (ttyvp->v_flag & VCTTYISOPEN) {
5fd012e0 135 /*
f1aeb0c0 136 * Avoid a nasty race if we block while getting the lock.
5fd012e0 137 */
8e73fd39 138 vref(ttyvp);
ca466bae 139 error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
f1aeb0c0 140 if (error) {
8e73fd39 141 vrele(ttyvp);
f1aeb0c0
MD
142 goto retry;
143 }
144 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN) == 0) {
145 kprintf("Warning: cttyclose: race avoided\n");
a11aaa81 146 vn_unlock(ttyvp);
8e73fd39 147 vrele(ttyvp);
f1aeb0c0 148 goto retry;
5fd012e0 149 }
f1aeb0c0
MD
150 vclrflags(ttyvp, VCTTYISOPEN);
151 error = VOP_CLOSE(ttyvp, FREAD|FWRITE);
152 vn_unlock(ttyvp);
8e73fd39 153 vrele(ttyvp);
5fd012e0
MD
154 } else {
155 error = 0;
156 }
e4c9c0c8
MD
157 return(error);
158}
159
84cca6ec
MD
160/*
161 * Read from the controlling terminal (/dev/tty). The tty is refed as
162 * of the cttyvp(), but the ref can get ripped out from under us if
163 * the controlling terminal is revoked while we are blocked on the lock,
a11aaa81 164 * so use vget() instead of vn_lock().
84cca6ec 165 */
984263bc 166static int
fef8985e 167cttyread(struct dev_read_args *ap)
984263bc 168{
fef8985e 169 struct proc *p = curproc;
dadab5e9 170 struct vnode *ttyvp;
984263bc
MD
171 int error;
172
dadab5e9
MD
173 KKASSERT(p);
174 ttyvp = cttyvp(p);
984263bc
MD
175 if (ttyvp == NULL)
176 return (EIO);
87de5057 177 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
fef8985e 178 error = VOP_READ(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
84cca6ec
MD
179 vput(ttyvp);
180 }
984263bc
MD
181 return (error);
182}
183
84cca6ec
MD
184/*
185 * Read from the controlling terminal (/dev/tty). The tty is refed as
186 * of the cttyvp(), but the ref can get ripped out from under us if
187 * the controlling terminal is revoked while we are blocked on the lock,
a11aaa81 188 * so use vget() instead of vn_lock().
84cca6ec 189 */
984263bc 190static int
fef8985e 191cttywrite(struct dev_write_args *ap)
984263bc 192{
fef8985e 193 struct proc *p = curproc;
dadab5e9 194 struct vnode *ttyvp;
984263bc
MD
195 int error;
196
dadab5e9
MD
197 KKASSERT(p);
198 ttyvp = cttyvp(p);
984263bc
MD
199 if (ttyvp == NULL)
200 return (EIO);
87de5057 201 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
fef8985e 202 error = VOP_WRITE(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
84cca6ec
MD
203 vput(ttyvp);
204 }
984263bc
MD
205 return (error);
206}
207
208/*ARGSUSED*/
209static int
fef8985e 210cttyioctl(struct dev_ioctl_args *ap)
984263bc 211{
41c20dac 212 struct vnode *ttyvp;
fef8985e 213 struct proc *p = curproc;
984263bc 214
dadab5e9
MD
215 KKASSERT(p);
216 ttyvp = cttyvp(p);
984263bc
MD
217 if (ttyvp == NULL)
218 return (EIO);
fef8985e
MD
219 /*
220 * Don't allow controlling tty to be set to the controlling tty
221 * (infinite recursion).
222 */
223 if (ap->a_cmd == TIOCSCTTY)
224 return EINVAL;
225 if (ap->a_cmd == TIOCNOTTY) {
dadab5e9
MD
226 if (!SESS_LEADER(p)) {
227 p->p_flag &= ~P_CONTROLT;
984263bc 228 return (0);
fef8985e 229 } else {
984263bc 230 return (EINVAL);
fef8985e 231 }
984263bc 232 }
fef8985e 233 return (VOP_IOCTL(ttyvp, ap->a_cmd, ap->a_data, ap->a_fflag, ap->a_cred));
984263bc
MD
234}
235
236/*ARGSUSED*/
237static int
fef8985e 238cttypoll(struct dev_poll_args *ap)
984263bc 239{
b13267a5 240 cdev_t dev = ap->a_head.a_dev;
41c20dac 241 struct vnode *ttyvp;
fef8985e 242 struct proc *p = curproc;
984263bc 243
dadab5e9
MD
244 KKASSERT(p);
245 ttyvp = cttyvp(p);
fef8985e
MD
246 /*
247 * try operation to get EOF/failure
248 */
984263bc 249 if (ttyvp == NULL)
fef8985e
MD
250 ap->a_events = seltrue(dev, ap->a_events);
251 else
252 ap->a_events = VOP_POLL(ttyvp, ap->a_events, p->p_ucred);
253 return(0);
984263bc
MD
254}
255
984263bc 256static void
fef8985e 257ctty_drvinit(void *unused __unused)
984263bc 258{
fef8985e 259 make_dev(&ctty_ops, 0, 0, 0, 0666, "tty");
984263bc
MD
260}
261
262SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)