xref: /freebsd/sys/kern/tty_tty.c (revision 4b2eaea43fec8e8792be611dea204071a10b655a)
1 #ifndef NODEVFS
2 /*-
3  * Copyright (c) 2003 Poul-Henning Kamp.  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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/conf.h>
32 #include <sys/kernel.h>
33 #include <sys/proc.h>
34 #include <sys/vnode.h>
35 
36 static	d_open_t	cttyopen;
37 
38 #define	CDEV_MAJOR	1
39 
40 static struct cdevsw ctty_cdevsw = {
41 	/* open */	cttyopen,
42 	/* close */	nullclose,
43 	/* read */	noread,
44 	/* write */	nowrite,
45 	/* ioctl */	noioctl,
46 	/* poll */	nopoll,
47 	/* mmap */	nommap,
48 	/* strategy */	nostrategy,
49 	/* name */	"ctty",
50 	/* maj */	CDEV_MAJOR,
51 	/* dump */	nodump,
52 	/* psize */	nopsize,
53 	/* flags */	D_TTY,
54 };
55 
56 static dev_t ctty;
57 
58 static	int
59 cttyopen(dev_t dev, int flag, int mode, struct thread *td)
60 {
61 
62 	return (ENXIO);
63 }
64 
65 static void
66 ctty_clone(void *arg, char *name, int namelen, dev_t *dev)
67 {
68 
69 	if (*dev != NODEV)
70 		return;
71 	if (strcmp(name, "tty"))
72 		return;
73 	if (!(curthread->td_proc->p_flag & P_CONTROLT))
74 		*dev = ctty;
75 	else if (curthread->td_proc->p_session->s_ttyvp == NULL)
76 		*dev = ctty;
77 	else
78 		*dev = curthread->td_proc->p_session->s_ttyvp->v_rdev;
79 }
80 
81 static void
82 ctty_drvinit(void *unused)
83 {
84 
85 	EVENTHANDLER_REGISTER(dev_clone, ctty_clone, 0, 1000);
86 	ctty = make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "ctty");
87 }
88 
89 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)
90 #else
91 /*-
92  * Copyright (c) 1982, 1986, 1991, 1993
93  *	The Regents of the University of California.  All rights reserved.
94  *
95  * Redistribution and use in source and binary forms, with or without
96  * modification, are permitted provided that the following conditions
97  * are met:
98  * 1. Redistributions of source code must retain the above copyright
99  *    notice, this list of conditions and the following disclaimer.
100  * 2. Redistributions in binary form must reproduce the above copyright
101  *    notice, this list of conditions and the following disclaimer in the
102  *    documentation and/or other materials provided with the distribution.
103  * 3. All advertising materials mentioning features or use of this software
104  *    must display the following acknowledgement:
105  *	This product includes software developed by the University of
106  *	California, Berkeley and its contributors.
107  * 4. Neither the name of the University nor the names of its contributors
108  *    may be used to endorse or promote products derived from this software
109  *    without specific prior written permission.
110  *
111  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
112  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
113  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
114  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
115  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
116  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
117  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
118  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
119  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
120  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
121  * SUCH DAMAGE.
122  *
123  *	@(#)tty_tty.c	8.2 (Berkeley) 9/23/93
124  * $FreeBSD$
125  */
126 
127 /*
128  * Indirect driver for controlling tty.
129  */
130 
131 #include "opt_mac.h"
132 
133 #include <sys/param.h>
134 #include <sys/systm.h>
135 #include <sys/conf.h>
136 #include <sys/kernel.h>
137 #include <sys/lock.h>
138 #include <sys/mac.h>
139 #include <sys/mutex.h>
140 #include <sys/sx.h>
141 #include <sys/proc.h>
142 #include <sys/ttycom.h>
143 #include <sys/vnode.h>
144 
145 static	d_open_t	cttyopen;
146 static	d_read_t	cttyread;
147 static	d_write_t	cttywrite;
148 static	d_ioctl_t	cttyioctl;
149 static	d_poll_t	cttypoll;
150 
151 #define	CDEV_MAJOR	1
152 
153 static struct cdevsw ctty_cdevsw = {
154 	/* open */	cttyopen,
155 	/* close */	nullclose,
156 	/* read */	cttyread,
157 	/* write */	cttywrite,
158 	/* ioctl */	cttyioctl,
159 	/* poll */	cttypoll,
160 	/* mmap */	nommap,
161 	/* strategy */	nostrategy,
162 	/* name */	"ctty",
163 	/* maj */	CDEV_MAJOR,
164 	/* dump */	nodump,
165 	/* psize */	nopsize,
166 	/* flags */	D_TTY,
167 };
168 
169 #define cttyvp(td) ((td)->td_proc->p_flag & P_CONTROLT ? (td)->td_proc->p_session->s_ttyvp : NULL)
170 
171 /*ARGSUSED*/
172 static	int
173 cttyopen(dev, flag, mode, td)
174 	dev_t dev;
175 	int flag, mode;
176 	struct thread *td;
177 {
178 	struct vnode *ttyvp;
179 	int error;
180 
181 	PROC_LOCK(td->td_proc);
182 	SESS_LOCK(td->td_proc->p_session);
183 	ttyvp = cttyvp(td);
184 	SESS_UNLOCK(td->td_proc->p_session);
185 	PROC_UNLOCK(td->td_proc);
186 
187 	if (ttyvp == NULL)
188 		return (ENXIO);
189 	vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
190 #ifdef MAC
191 	error = mac_check_vnode_open(td->td_ucred, ttyvp, flag);
192 	if (error) {
193 		VOP_UNLOCK(ttyvp, 0, td);
194 		return (error);
195 	}
196 #endif
197 	/* XXX: Shouldn't this cred be td->td_ucred not NOCRED? */
198 	error = VOP_OPEN(ttyvp, flag, NOCRED, td);
199 	VOP_UNLOCK(ttyvp, 0, td);
200 	return (error);
201 }
202 
203 /*ARGSUSED*/
204 static	int
205 cttyread(dev, uio, flag)
206 	dev_t dev;
207 	struct uio *uio;
208 	int flag;
209 {
210 	struct thread *td = uio->uio_td;
211 	register struct vnode *ttyvp;
212 	int error;
213 
214 	PROC_LOCK(td->td_proc);
215 	SESS_LOCK(td->td_proc->p_session);
216 	ttyvp = cttyvp(td);
217 	SESS_UNLOCK(td->td_proc->p_session);
218 	PROC_UNLOCK(td->td_proc);
219 
220 	if (ttyvp == NULL)
221 		return (EIO);
222 	vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
223 #ifdef MAC
224 	error = mac_check_vnode_read(td->td_ucred, NOCRED, ttyvp);
225 	if (error == 0)
226 #endif
227 		/* XXX: Shouldn't this cred be td->td_ucred not NOCRED? */
228 		error = VOP_READ(ttyvp, uio, flag, NOCRED);
229 	VOP_UNLOCK(ttyvp, 0, td);
230 	return (error);
231 }
232 
233 /*ARGSUSED*/
234 static	int
235 cttywrite(dev, uio, flag)
236 	dev_t dev;
237 	struct uio *uio;
238 	int flag;
239 {
240 	struct thread *td = uio->uio_td;
241 	struct vnode *ttyvp;
242 	struct mount *mp;
243 	int error;
244 
245 	PROC_LOCK(td->td_proc);
246 	SESS_LOCK(td->td_proc->p_session);
247 	ttyvp = cttyvp(td);
248 	SESS_UNLOCK(td->td_proc->p_session);
249 	PROC_UNLOCK(td->td_proc);
250 
251 	if (ttyvp == NULL)
252 		return (EIO);
253 	mp = NULL;
254 	if (ttyvp->v_type != VCHR &&
255 	    (error = vn_start_write(ttyvp, &mp, V_WAIT | PCATCH)) != 0)
256 		return (error);
257 	vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
258 #ifdef MAC
259 	error = mac_check_vnode_write(td->td_ucred, NOCRED, ttyvp);
260 	if (error == 0)
261 #endif
262 		/* XXX: shouldn't this cred be td->td_ucred not NOCRED? */
263 		error = VOP_WRITE(ttyvp, uio, flag, NOCRED);
264 	VOP_UNLOCK(ttyvp, 0, td);
265 	vn_finished_write(mp);
266 	return (error);
267 }
268 
269 /*ARGSUSED*/
270 static	int
271 cttyioctl(dev, cmd, addr, flag, td)
272 	dev_t dev;
273 	u_long cmd;
274 	caddr_t addr;
275 	int flag;
276 	struct thread *td;
277 {
278 	struct vnode *ttyvp;
279 	int error;
280 
281 	PROC_LOCK(td->td_proc);
282 	SESS_LOCK(td->td_proc->p_session);
283 	ttyvp = cttyvp(td);
284 	SESS_UNLOCK(td->td_proc->p_session);
285 	PROC_UNLOCK(td->td_proc);
286 
287 	if (ttyvp == NULL)
288 		return (EIO);
289 	if (cmd == TIOCSCTTY)  /* don't allow controlling tty to be set    */
290 		return EINVAL; /* to controlling tty -- infinite recursion */
291 	if (cmd == TIOCNOTTY) {
292 		PROC_LOCK(td->td_proc);
293 		SESS_LOCK(td->td_proc->p_session);
294 		error = 0;
295 		if (!SESS_LEADER(td->td_proc))
296 			td->td_proc->p_flag &= ~P_CONTROLT;
297 		else
298 			error = EINVAL;
299 		SESS_UNLOCK(td->td_proc->p_session);
300 		PROC_UNLOCK(td->td_proc);
301 		return (error);
302 	}
303 	/* XXXMAC: Should this be td->td_ucred below? */
304 	return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, td));
305 }
306 
307 /*ARGSUSED*/
308 static	int
309 cttypoll(dev, events, td)
310 	dev_t dev;
311 	int events;
312 	struct thread *td;
313 {
314 	struct vnode *ttyvp;
315 #ifdef MAC
316 	int error;
317 #endif
318 
319 	PROC_LOCK(td->td_proc);
320 	SESS_LOCK(td->td_proc->p_session);
321 	ttyvp = cttyvp(td);
322 	SESS_UNLOCK(td->td_proc->p_session);
323 	PROC_UNLOCK(td->td_proc);
324 
325 	if (ttyvp == NULL)
326 		/* try operation to get EOF/failure */
327 		return (seltrue(dev, events, td));
328 #ifdef MAC
329 	vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td);
330 	error = mac_check_vnode_poll(td->td_ucred, NOCRED, ttyvp);
331 	VOP_UNLOCK(ttyvp, 0, td);
332 	if (error)
333 		return (error);
334 #endif
335 	return (VOP_POLL(ttyvp, events, td->td_ucred, td));
336 }
337 
338 static void ctty_clone(void *arg, char *name, int namelen, dev_t *dev);
339 
340 static dev_t ctty;
341 
342 static void
343 ctty_clone(void *arg, char *name, int namelen, dev_t *dev)
344 {
345 	struct vnode *vp;
346 
347 	if (*dev != NODEV)
348 		return;
349 	if (strcmp(name, "tty"))
350 		return;
351 	vp = cttyvp(curthread);
352 	if (vp == NULL) {
353 		if (ctty)
354 			*dev = ctty;
355 	} else
356 		*dev = vp->v_rdev;
357 }
358 
359 
360 static void ctty_drvinit(void *unused);
361 static void
362 ctty_drvinit(unused)
363 	void *unused;
364 {
365 
366 	make_dev(&ctty_cdevsw, 0, 0, 0, 0666, "tty");
367 }
368 
369 SYSINIT(cttydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ctty_drvinit,NULL)
370 #endif
371