afb140e7b8a97fe056d1fbf8c44ea7bc4ae9e3db
[dragonfly.git] / sys / kern / tty_tty.c
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 $
35  * $DragonFly: src/sys/kern/tty_tty.c,v 1.19 2007/07/03 17:22:14 dillon Exp $
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>
45 #include <sys/device.h>
46 #include <sys/lock.h>
47 #include <sys/fcntl.h>
48 #include <sys/proc.h>
49 #include <sys/ttycom.h>
50 #include <sys/vnode.h>
51 #include <sys/kernel.h>
52 #include <sys/event.h>
53 #include <sys/poll.h>
54
55 static  d_open_t        cttyopen;
56 static  d_close_t       cttyclose;
57 static  d_read_t        cttyread;
58 static  d_write_t       cttywrite;
59 static  d_ioctl_t       cttyioctl;
60 static  d_poll_t        cttypoll;
61 static  d_kqfilter_t    cttykqfilter;
62
63 static void cttyfilt_detach(struct knote *);
64 static int cttyfilt_read(struct knote *, long);
65 static int cttyfilt_write(struct knote *, long);
66
67 #define CDEV_MAJOR      1
68 /* Don't make this static, since fdesc_vnops uses it. */
69 struct dev_ops ctty_ops = {
70         { "ctty", CDEV_MAJOR, D_TTY | D_KQFILTER },
71         .d_open =       cttyopen,
72         .d_close =      cttyclose,
73         .d_read =       cttyread,
74         .d_write =      cttywrite,
75         .d_ioctl =      cttyioctl,
76         .d_poll =       cttypoll,
77         .d_kqfilter =   cttykqfilter
78 };
79
80 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
81
82 /*
83  * This opens /dev/tty.  Because multiple opens of /dev/tty only
84  * generate a single open to the actual tty, the file modes are
85  * locked to FREAD|FWRITE.
86  */
87 static  int
88 cttyopen(struct dev_open_args *ap)
89 {
90         struct proc *p = curproc;
91         struct vnode *ttyvp;
92         int error;
93
94         KKASSERT(p);
95 retry:
96         if ((ttyvp = cttyvp(p)) == NULL)
97                 return (ENXIO);
98         if (ttyvp->v_flag & VCTTYISOPEN)
99                 return (0);
100
101         /*
102          * Messy interlock, don't let the vnode go away while we try to
103          * lock it and check for race after we might have blocked.
104          */
105         vhold(ttyvp);
106         vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
107         if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN)) {
108                 kprintf("Warning: cttyopen: race avoided\n");
109                 vn_unlock(ttyvp);
110                 vdrop(ttyvp);
111                 goto retry;
112         }
113         vsetflags(ttyvp, VCTTYISOPEN);
114         error = VOP_OPEN(ttyvp, FREAD|FWRITE, ap->a_cred, NULL);
115         if (error)
116                 vclrflags(ttyvp, VCTTYISOPEN);
117         vn_unlock(ttyvp);
118         vdrop(ttyvp);
119         return(error);
120 }
121
122 /*
123  * This closes /dev/tty.  Because multiple opens of /dev/tty only
124  * generate a single open to the actual tty, the file modes are
125  * locked to FREAD|FWRITE.
126  */
127 static int
128 cttyclose(struct dev_close_args *ap)
129 {
130         struct proc *p = curproc;
131         struct vnode *ttyvp;
132         int error;
133
134         KKASSERT(p);
135 retry:
136         /*
137          * The tty may have been TIOCNOTTY'd, don't return an
138          * error on close.  We just have nothing to do.
139          */
140         if ((ttyvp = cttyvp(p)) == NULL)
141                 return(0);
142         if (ttyvp->v_flag & VCTTYISOPEN) {
143                 /*
144                  * Avoid a nasty race if we block while getting the lock.
145                  */
146                 vref(ttyvp);
147                 error = vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY);
148                 if (error) {
149                         vrele(ttyvp);
150                         goto retry;
151                 }
152                 if (ttyvp != cttyvp(p) || (ttyvp->v_flag & VCTTYISOPEN) == 0) {
153                         kprintf("Warning: cttyclose: race avoided\n");
154                         vn_unlock(ttyvp);
155                         vrele(ttyvp);
156                         goto retry;
157                 }
158                 vclrflags(ttyvp, VCTTYISOPEN);
159                 error = VOP_CLOSE(ttyvp, FREAD|FWRITE);
160                 vn_unlock(ttyvp);
161                 vrele(ttyvp);
162         } else {
163                 error = 0;
164         }
165         return(error);
166 }
167
168 /*
169  * Read from the controlling terminal (/dev/tty).  The tty is refed as
170  * of the cttyvp(), but the ref can get ripped out from under us if
171  * the controlling terminal is revoked while we are blocked on the lock,
172  * so use vget() instead of vn_lock().
173  */
174 static  int
175 cttyread(struct dev_read_args *ap)
176 {
177         struct proc *p = curproc;
178         struct vnode *ttyvp;
179         int error;
180
181         KKASSERT(p);
182         ttyvp = cttyvp(p);
183         if (ttyvp == NULL)
184                 return (EIO);
185         if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
186                 error = VOP_READ(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
187                 vput(ttyvp);
188         }
189         return (error);
190 }
191
192 /*
193  * Read from the controlling terminal (/dev/tty).  The tty is refed as
194  * of the cttyvp(), but the ref can get ripped out from under us if
195  * the controlling terminal is revoked while we are blocked on the lock,
196  * so use vget() instead of vn_lock().
197  */
198 static  int
199 cttywrite(struct dev_write_args *ap)
200 {
201         struct proc *p = curproc;
202         struct vnode *ttyvp;
203         int error;
204
205         KKASSERT(p);
206         ttyvp = cttyvp(p);
207         if (ttyvp == NULL)
208                 return (EIO);
209         if ((error = vget(ttyvp, LK_EXCLUSIVE | LK_RETRY)) == 0) {
210                 error = VOP_WRITE(ttyvp, ap->a_uio, ap->a_ioflag, NOCRED);
211                 vput(ttyvp);
212         }
213         return (error);
214 }
215
216 /*ARGSUSED*/
217 static  int
218 cttyioctl(struct dev_ioctl_args *ap)
219 {
220         struct vnode *ttyvp;
221         struct proc *p = curproc;
222
223         KKASSERT(p);
224         ttyvp = cttyvp(p);
225         if (ttyvp == NULL)
226                 return (EIO);
227         /*
228          * Don't allow controlling tty to be set to the controlling tty
229          * (infinite recursion).
230          */
231         if (ap->a_cmd == TIOCSCTTY)
232                 return EINVAL;
233         if (ap->a_cmd == TIOCNOTTY) {
234                 if (!SESS_LEADER(p)) {
235                         p->p_flag &= ~P_CONTROLT;
236                         return (0);
237                 } else {
238                         return (EINVAL);
239                 }
240         }
241         return (VOP_IOCTL(ttyvp, ap->a_cmd, ap->a_data, ap->a_fflag,
242                           ap->a_cred, ap->a_sysmsg));
243 }
244
245 /*ARGSUSED*/
246 static  int
247 cttypoll(struct dev_poll_args *ap)
248 {
249         cdev_t dev = ap->a_head.a_dev;
250         struct vnode *ttyvp;
251         struct proc *p = curproc;
252
253         KKASSERT(p);
254         ttyvp = cttyvp(p);
255         /*
256          * try operation to get EOF/failure 
257          */
258         if (ttyvp == NULL)
259                 ap->a_events = seltrue(dev, ap->a_events);
260         else
261                 ap->a_events = VOP_POLL(ttyvp, ap->a_events, p->p_ucred);
262         return(0);
263 }
264
265 static struct filterops cttyfiltops_read =
266         { 1, NULL, cttyfilt_detach, cttyfilt_read };
267 static struct filterops cttyfiltops_write =
268         { 1, NULL, cttyfilt_detach, cttyfilt_write };
269
270 static int
271 cttykqfilter(struct dev_kqfilter_args *ap)
272 {
273         cdev_t dev = ap->a_head.a_dev;
274         struct proc *p = curproc;
275         struct knote *kn = ap->a_kn;
276         struct vnode *ttyvp;
277
278         KKASSERT(p);
279         ttyvp = cttyvp(p);
280
281         if (ttyvp != NULL)
282                 return (VOP_KQFILTER(ttyvp, kn));
283
284         ap->a_result = 0;
285
286         switch (kn->kn_filter) {
287         case EVFILT_READ:
288                 kn->kn_fop = &cttyfiltops_read;
289                 kn->kn_hook = (caddr_t)dev;
290                 break;
291         case EVFILT_WRITE:
292                 kn->kn_fop = &cttyfiltops_write;
293                 kn->kn_hook = (caddr_t)dev;
294                 break;
295         default:
296                 ap->a_result = 1;
297                 return (0);
298         }
299
300         return (0);
301 }
302
303 static void
304 cttyfilt_detach(struct knote *kn) {}
305
306 static int
307 cttyfilt_read(struct knote *kn, long hint)
308 {
309         cdev_t dev = (cdev_t)kn->kn_hook;
310
311         if (seltrue(dev, POLLIN | POLLRDNORM))
312                 return (1);
313
314         return (0);
315 }
316
317 static int
318 cttyfilt_write(struct knote *kn, long hint)
319 {
320         cdev_t dev = (cdev_t)kn->kn_hook;
321
322         if (seltrue(dev, POLLOUT | POLLWRNORM))
323                 return (1);
324
325         return (0);
326 }
327
328 static void
329 ctty_drvinit(void *unused __unused)
330 {
331         make_dev(&ctty_ops, 0, 0, 0, 0666, "tty");
332 }
333
334 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)