Change the kernel dev_t, representing a pointer to a specinfo structure,
[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 $
b13267a5 35 * $DragonFly: src/sys/kern/tty_tty.c,v 1.18 2006/09/10 01:26:39 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
MD
86 KKASSERT(p);
87 ttyvp = cttyvp(p);
e4c9c0c8 88 if (ttyvp) {
5fd012e0
MD
89 if (ttyvp->v_flag & VCTTYISOPEN) {
90 error = 0;
91 } else {
92 vsetflags(ttyvp, VCTTYISOPEN);
ca466bae 93 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
fef8985e 94 error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL);
9e08e2dd
MD
95 if (error)
96 vclrflags(ttyvp, VCTTYISOPEN);
a11aaa81 97 vn_unlock(ttyvp);
5fd012e0 98 }
e4c9c0c8
MD
99 } else {
100 error = ENXIO;
101 }
984263bc
MD
102 return (error);
103}
104
84cca6ec
MD
105/*
106 * This closes /dev/tty. Because multiple opens of /dev/tty only
107 * generate a single open to the actual tty, the file modes are
108 * locked to FREAD|FWRITE.
109 */
e4c9c0c8 110static int
fef8985e 111cttyclose(struct dev_close_args *ap)
e4c9c0c8 112{
fef8985e 113 struct proc *p = curproc;
e4c9c0c8
MD
114 struct vnode *ttyvp;
115 int error;
116
117 KKASSERT(p);
118 ttyvp = cttyvp(p);
5fd012e0
MD
119 if (ttyvp == NULL) {
120 /*
121 * The tty may have been TIOCNOTTY'd, don't return an
122 * error on close. We just have nothing to do.
123 */
124 /* error = EIO; */
125 error = 0;
126 } else if (ttyvp->v_flag & VCTTYISOPEN) {
127 vclrflags(ttyvp, VCTTYISOPEN);
ca466bae 128 error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
5fd012e0 129 if (error == 0) {
87de5057 130 error = VOP_CLOSE(ttyvp, FREAD|FWRITE);
a11aaa81 131 vn_unlock(ttyvp);
5fd012e0
MD
132 }
133 } else {
134 error = 0;
135 }
e4c9c0c8
MD
136 return(error);
137}
138
84cca6ec
MD
139/*
140 * Read from the controlling terminal (/dev/tty). The tty is refed as
141 * of the cttyvp(), but the ref can get ripped out from under us if
142 * the controlling terminal is revoked while we are blocked on the lock,
a11aaa81 143 * so use vget() instead of vn_lock().
84cca6ec 144 */
984263bc 145static int
fef8985e 146cttyread(struct dev_read_args *ap)
984263bc 147{
fef8985e 148 struct proc *p = curproc;
dadab5e9 149 struct vnode *ttyvp;
984263bc
MD
150 int error;
151
dadab5e9
MD
152 KKASSERT(p);
153 ttyvp = cttyvp(p);
984263bc
MD
154 if (ttyvp == NULL)
155 return (EIO);
87de5057 156 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
fef8985e 157 error = VOP_READ(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
84cca6ec
MD
158 vput(ttyvp);
159 }
984263bc
MD
160 return (error);
161}
162
84cca6ec
MD
163/*
164 * Read from the controlling terminal (/dev/tty). The tty is refed as
165 * of the cttyvp(), but the ref can get ripped out from under us if
166 * the controlling terminal is revoked while we are blocked on the lock,
a11aaa81 167 * so use vget() instead of vn_lock().
84cca6ec 168 */
984263bc 169static int
fef8985e 170cttywrite(struct dev_write_args *ap)
984263bc 171{
fef8985e 172 struct proc *p = curproc;
dadab5e9 173 struct vnode *ttyvp;
984263bc
MD
174 int error;
175
dadab5e9
MD
176 KKASSERT(p);
177 ttyvp = cttyvp(p);
984263bc
MD
178 if (ttyvp == NULL)
179 return (EIO);
87de5057 180 if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
fef8985e 181 error = VOP_WRITE(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
84cca6ec
MD
182 vput(ttyvp);
183 }
984263bc
MD
184 return (error);
185}
186
187/*ARGSUSED*/
188static int
fef8985e 189cttyioctl(struct dev_ioctl_args *ap)
984263bc 190{
41c20dac 191 struct vnode *ttyvp;
fef8985e 192 struct proc *p = curproc;
984263bc 193
dadab5e9
MD
194 KKASSERT(p);
195 ttyvp = cttyvp(p);
984263bc
MD
196 if (ttyvp == NULL)
197 return (EIO);
fef8985e
MD
198 /*
199 * Don't allow controlling tty to be set to the controlling tty
200 * (infinite recursion).
201 */
202 if (ap->a_cmd == TIOCSCTTY)
203 return EINVAL;
204 if (ap->a_cmd == TIOCNOTTY) {
dadab5e9
MD
205 if (!SESS_LEADER(p)) {
206 p->p_flag &= ~P_CONTROLT;
984263bc 207 return (0);
fef8985e 208 } else {
984263bc 209 return (EINVAL);
fef8985e 210 }
984263bc 211 }
fef8985e 212 return (VOP_IOCTL(ttyvp, ap->a_cmd, ap->a_data, ap->a_fflag, ap->a_cred));
984263bc
MD
213}
214
215/*ARGSUSED*/
216static int
fef8985e 217cttypoll(struct dev_poll_args *ap)
984263bc 218{
b13267a5 219 cdev_t dev = ap->a_head.a_dev;
41c20dac 220 struct vnode *ttyvp;
fef8985e 221 struct proc *p = curproc;
984263bc 222
dadab5e9
MD
223 KKASSERT(p);
224 ttyvp = cttyvp(p);
fef8985e
MD
225 /*
226 * try operation to get EOF/failure
227 */
984263bc 228 if (ttyvp == NULL)
fef8985e
MD
229 ap->a_events = seltrue(dev, ap->a_events);
230 else
231 ap->a_events = VOP_POLL(ttyvp, ap->a_events, p->p_ucred);
232 return(0);
984263bc
MD
233}
234
984263bc 235static void
fef8985e 236ctty_drvinit(void *unused __unused)
984263bc 237{
fef8985e
MD
238 dev_ops_add(&ctty_ops, 0, 0);
239 make_dev(&ctty_ops, 0, 0, 0, 0666, "tty");
984263bc
MD
240}
241
242SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)