FreeBSD/Linux Kernel Cross Reference
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: releng/5.0/sys/kern/tty_tty.c 102129 2002-08-19 19:04:53Z rwatson $
35 */
36
37 /*
38 * Indirect driver for controlling tty.
39 */
40
41 #include "opt_mac.h"
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/conf.h>
46 #include <sys/kernel.h>
47 #include <sys/lock.h>
48 #include <sys/mac.h>
49 #include <sys/mutex.h>
50 #include <sys/sx.h>
51 #include <sys/proc.h>
52 #include <sys/ttycom.h>
53 #include <sys/vnode.h>
54
55 static d_open_t cttyopen;
56 static d_read_t cttyread;
57 static d_write_t cttywrite;
58 static d_ioctl_t cttyioctl;
59 static d_poll_t cttypoll;
60
61 #define CDEV_MAJOR 1
62
63 static struct cdevsw ctty_cdevsw = {
64 /* open */ cttyopen,
65 /* close */ nullclose,
66 /* read */ cttyread,
67 /* write */ cttywrite,
68 /* ioctl */ cttyioctl,
69 /* poll */ cttypoll,
70 /* mmap */ nommap,
71 /* strategy */ nostrategy,
72 /* name */ "ctty",
73 /* maj */ CDEV_MAJOR,
74 /* dump */ nodump,
75 /* psize */ nopsize,
76 /* flags */ D_TTY,
77 };
78
79 #define cttyvp(td) ((td)->td_proc->p_flag & P_CONTROLT ? (td)->td_proc->p_session->s_ttyvp : NULL)
80
81 /*ARGSUSED*/
82 static int
83 cttyopen(dev, flag, mode, td)
84 dev_t dev;
85 int flag, mode;
86 struct thread *td;
87 {
88 struct vnode *ttyvp;
89 int error;
90
91 PROC_LOCK(td->td_proc);
92 SESS_LOCK(td->td_proc->p_session);
93 ttyvp = cttyvp(td);
94 SESS_UNLOCK(td->td_proc->p_session);
95 PROC_UNLOCK(td->td_proc);
96
97 if (ttyvp == NULL)
98 return (ENXIO);
99 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
100 #ifdef MAC
101 error = mac_check_vnode_open(td->td_ucred, ttyvp, flag);
102 if (error) {
103 VOP_UNLOCK(ttyvp, 0, td);
104 return (error);
105 }
106 #endif
107 /* XXX: Shouldn't this cred be td->td_ucred not NOCRED? */
108 error = VOP_OPEN(ttyvp, flag, NOCRED, td);
109 VOP_UNLOCK(ttyvp, 0, td);
110 return (error);
111 }
112
113 /*ARGSUSED*/
114 static int
115 cttyread(dev, uio, flag)
116 dev_t dev;
117 struct uio *uio;
118 int flag;
119 {
120 struct thread *td = uio->uio_td;
121 register struct vnode *ttyvp;
122 int error;
123
124 PROC_LOCK(td->td_proc);
125 SESS_LOCK(td->td_proc->p_session);
126 ttyvp = cttyvp(td);
127 SESS_UNLOCK(td->td_proc->p_session);
128 PROC_UNLOCK(td->td_proc);
129
130 if (ttyvp == NULL)
131 return (EIO);
132 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
133 #ifdef MAC
134 error = mac_check_vnode_read(td->td_ucred, NOCRED, ttyvp);
135 if (error == 0)
136 #endif
137 /* XXX: Shouldn't this cred be td->td_ucred not NOCRED? */
138 error = VOP_READ(ttyvp, uio, flag, NOCRED);
139 VOP_UNLOCK(ttyvp, 0, td);
140 return (error);
141 }
142
143 /*ARGSUSED*/
144 static int
145 cttywrite(dev, uio, flag)
146 dev_t dev;
147 struct uio *uio;
148 int flag;
149 {
150 struct thread *td = uio->uio_td;
151 struct vnode *ttyvp;
152 struct mount *mp;
153 int error;
154
155 PROC_LOCK(td->td_proc);
156 SESS_LOCK(td->td_proc->p_session);
157 ttyvp = cttyvp(td);
158 SESS_UNLOCK(td->td_proc->p_session);
159 PROC_UNLOCK(td->td_proc);
160
161 if (ttyvp == NULL)
162 return (EIO);
163 mp = NULL;
164 if (ttyvp->v_type != VCHR &&
165 (error = vn_start_write(ttyvp, &mp, V_WAIT | PCATCH)) != 0)
166 return (error);
167 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
168 #ifdef MAC
169 error = mac_check_vnode_write(td->td_ucred, NOCRED, ttyvp);
170 if (error == 0)
171 #endif
172 /* XXX: shouldn't this cred be td->td_ucred not NOCRED? */
173 error = VOP_WRITE(ttyvp, uio, flag, NOCRED);
174 VOP_UNLOCK(ttyvp, 0, td);
175 vn_finished_write(mp);
176 return (error);
177 }
178
179 /*ARGSUSED*/
180 static int
181 cttyioctl(dev, cmd, addr, flag, td)
182 dev_t dev;
183 u_long cmd;
184 caddr_t addr;
185 int flag;
186 struct thread *td;
187 {
188 struct vnode *ttyvp;
189 int error;
190
191 PROC_LOCK(td->td_proc);
192 SESS_LOCK(td->td_proc->p_session);
193 ttyvp = cttyvp(td);
194 SESS_UNLOCK(td->td_proc->p_session);
195 PROC_UNLOCK(td->td_proc);
196
197 if (ttyvp == NULL)
198 return (EIO);
199 if (cmd == TIOCSCTTY) /* don't allow controlling tty to be set */
200 return EINVAL; /* to controlling tty -- infinite recursion */
201 if (cmd == TIOCNOTTY) {
202 PROC_LOCK(td->td_proc);
203 SESS_LOCK(td->td_proc->p_session);
204 error = 0;
205 if (!SESS_LEADER(td->td_proc))
206 td->td_proc->p_flag &= ~P_CONTROLT;
207 else
208 error = EINVAL;
209 SESS_UNLOCK(td->td_proc->p_session);
210 PROC_UNLOCK(td->td_proc);
211 return (error);
212 }
213 /* XXXMAC: Should this be td->td_ucred below? */
214 return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, td));
215 }
216
217 /*ARGSUSED*/
218 static int
219 cttypoll(dev, events, td)
220 dev_t dev;
221 int events;
222 struct thread *td;
223 {
224 struct vnode *ttyvp;
225 #ifdef MAC
226 int error;
227 #endif
228
229 PROC_LOCK(td->td_proc);
230 SESS_LOCK(td->td_proc->p_session);
231 ttyvp = cttyvp(td);
232 SESS_UNLOCK(td->td_proc->p_session);
233 PROC_UNLOCK(td->td_proc);
234
235 if (ttyvp == NULL)
236 /* try operation to get EOF/failure */
237 return (seltrue(dev, events, td));
238 #ifdef MAC
239 vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
240 error = mac_check_vnode_poll(td->td_ucred, NOCRED, ttyvp);
241 VOP_UNLOCK(ttyvp, 0, td);
242 if (error)
243 return (error);
244 #endif
245 return (VOP_POLL(ttyvp, events, td->td_ucred, td));
246 }
247
248 static void ctty_clone(void *arg, char *name, int namelen, dev_t *dev);
249
250 static dev_t ctty;
251
252 static void
253 ctty_clone(void *arg, char *name, int namelen, dev_t *dev)
254 {
255 struct vnode *vp;
256
257 if (*dev != NODEV)
258 return;
259 if (strcmp(name, "tty"))
260 return;
261 vp = cttyvp(curthread);
262 if (vp == NULL) {
263 if (ctty)
264 *dev = ctty;
265 } else
266 *dev = vp->v_rdev;
267 }
268
269
270 static void ctty_drvinit(void *unused);
271 static void
272 ctty_drvinit(unused)
273 void *unused;
274 {
275
276 if (devfs_present) {
277 EVENTHANDLER_REGISTER(dev_clone, ctty_clone, 0, 1000);
278 ctty = make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "ctty");
279 } else {
280 make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "tty");
281 }
282 }
283
284 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)
Cache object: 8eae6d0be3cc0a78b40face877641364
|