tty.c revision 194264
117651Speter/*-
2131377Stjr * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
317651Speter * All rights reserved.
4206708Sdelphij *
5206708Sdelphij * Portions of this software were developed under sponsorship from Snow
6206708Sdelphij * B.V., the Netherlands.
7206708Sdelphij *
8206708Sdelphij * Redistribution and use in source and binary forms, with or without
9206708Sdelphij * modification, are permitted provided that the following conditions
10206708Sdelphij * are met:
11206708Sdelphij * 1. Redistributions of source code must retain the above copyright
12206708Sdelphij *    notice, this list of conditions and the following disclaimer.
13206708Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
14206708Sdelphij *    notice, this list of conditions and the following disclaimer in the
15206708Sdelphij *    documentation and/or other materials provided with the distribution.
16206708Sdelphij *
17206708Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18206708Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19206708Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20206708Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21206708Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22206708Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23206708Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24206708Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25206708Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26206708Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27206708Sdelphij * SUCH DAMAGE.
28206708Sdelphij */
29206708Sdelphij
30206708Sdelphij#include <sys/cdefs.h>
31206708Sdelphij__FBSDID("$FreeBSD: head/sys/kern/tty.c 194264 2009-06-15 20:45:51Z ed $");
32206002Sdelphij
33206002Sdelphij#include "opt_compat.h"
34206002Sdelphij
35206002Sdelphij#include <sys/param.h>
36206002Sdelphij#include <sys/conf.h>
37206002Sdelphij#include <sys/cons.h>
38206002Sdelphij#include <sys/fcntl.h>
39206002Sdelphij#include <sys/file.h>
40206002Sdelphij#include <sys/filedesc.h>
41206002Sdelphij#include <sys/filio.h>
42206002Sdelphij#ifdef COMPAT_43TTY
43206002Sdelphij#include <sys/ioctl_compat.h>
44206002Sdelphij#endif /* COMPAT_43TTY */
45206002Sdelphij#include <sys/kernel.h>
46206002Sdelphij#include <sys/limits.h>
47206002Sdelphij#include <sys/malloc.h>
48206002Sdelphij#include <sys/mount.h>
49206002Sdelphij#include <sys/poll.h>
50206002Sdelphij#include <sys/priv.h>
51206002Sdelphij#include <sys/proc.h>
52206002Sdelphij#include <sys/serial.h>
53206002Sdelphij#include <sys/signal.h>
54206002Sdelphij#include <sys/stat.h>
55206002Sdelphij#include <sys/sx.h>
56205471Sdelphij#include <sys/sysctl.h>
57205471Sdelphij#include <sys/systm.h>
58205471Sdelphij#include <sys/tty.h>
59205471Sdelphij#include <sys/ttycom.h>
60205471Sdelphij#define TTYDEFCHARS
61205471Sdelphij#include <sys/ttydefaults.h>
62205471Sdelphij#undef TTYDEFCHARS
63205471Sdelphij#include <sys/ucred.h>
64205471Sdelphij#include <sys/vnode.h>
65205471Sdelphij
66205471Sdelphij#include <machine/stdarg.h>
67205471Sdelphij
68205471Sdelphijstatic MALLOC_DEFINE(M_TTY, "tty", "tty device");
69205471Sdelphij
70205471Sdelphijstatic void tty_rel_free(struct tty *tp);
71205471Sdelphij
72205471Sdelphijstatic TAILQ_HEAD(, tty) tty_list = TAILQ_HEAD_INITIALIZER(tty_list);
73205471Sdelphijstatic struct sx tty_list_sx;
74205471SdelphijSX_SYSINIT(tty_list, &tty_list_sx, "tty list");
75205471Sdelphijstatic unsigned int tty_list_count = 0;
76205471Sdelphij
77205471Sdelphij/* Character device of /dev/console. */
78205471Sdelphijstatic struct cdev	*dev_console;
79205471Sdelphijstatic const char	*dev_console_filename;
80205471Sdelphij
81205471Sdelphij/*
82205471Sdelphij * Flags that are supported and stored by this implementation.
83205471Sdelphij */
84205471Sdelphij#define TTYSUP_IFLAG	(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|\
85205471Sdelphij			INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|IMAXBEL)
86205471Sdelphij#define TTYSUP_OFLAG	(OPOST|ONLCR|TAB3|ONOEOT|OCRNL|ONOCR|ONLRET)
87205471Sdelphij#define TTYSUP_LFLAG	(ECHOKE|ECHOE|ECHOK|ECHO|ECHONL|ECHOPRT|\
88205471Sdelphij			ECHOCTL|ISIG|ICANON|ALTWERASE|IEXTEN|TOSTOP|\
89205471Sdelphij			FLUSHO|NOKERNINFO|NOFLSH)
90205471Sdelphij#define TTYSUP_CFLAG	(CIGNORE|CSIZE|CSTOPB|CREAD|PARENB|PARODD|\
91205471Sdelphij			HUPCL|CLOCAL|CCTS_OFLOW|CRTS_IFLOW|CDTR_IFLOW|\
92205471Sdelphij			CDSR_OFLOW|CCAR_OFLOW)
93205471Sdelphij
94205471Sdelphij#define	TTY_CALLOUT(tp,d) ((d) != (tp)->t_dev && (d) != dev_console)
95205471Sdelphij
96205471Sdelphij/*
97205471Sdelphij * Set TTY buffer sizes.
98205471Sdelphij */
99205471Sdelphij
100205471Sdelphij#define	TTYBUF_MAX	65536
101205471Sdelphij
102205471Sdelphijstatic void
103205471Sdelphijtty_watermarks(struct tty *tp)
104205471Sdelphij{
105205471Sdelphij	size_t bs;
106205471Sdelphij
107205471Sdelphij	/* Provide an input buffer for 0.2 seconds of data. */
108205471Sdelphij	bs = MIN(tp->t_termios.c_ispeed / 5, TTYBUF_MAX);
109205471Sdelphij	ttyinq_setsize(&tp->t_inq, tp, bs);
110205471Sdelphij
111205471Sdelphij	/* Set low watermark at 10% (when 90% is available). */
112205471Sdelphij	tp->t_inlow = (ttyinq_getsize(&tp->t_inq) * 9) / 10;
113205471Sdelphij
114205471Sdelphij	/* Provide an ouput buffer for 0.2 seconds of data. */
115205471Sdelphij	bs = MIN(tp->t_termios.c_ospeed / 5, TTYBUF_MAX);
116205471Sdelphij	ttyoutq_setsize(&tp->t_outq, tp, bs);
117205471Sdelphij
118205471Sdelphij	/* Set low watermark at 10% (when 90% is available). */
119205471Sdelphij	tp->t_outlow = (ttyoutq_getsize(&tp->t_outq) * 9) / 10;
120205471Sdelphij}
121205471Sdelphij
122205471Sdelphijstatic int
123205471Sdelphijtty_drain(struct tty *tp)
124205471Sdelphij{
125205471Sdelphij	int error;
126205471Sdelphij
127205471Sdelphij	if (ttyhook_hashook(tp, getc_inject))
128205471Sdelphij		/* buffer is inaccessible */
129205471Sdelphij		return (0);
130205471Sdelphij
131205471Sdelphij	while (ttyoutq_bytesused(&tp->t_outq) > 0) {
132205471Sdelphij		ttydevsw_outwakeup(tp);
133205471Sdelphij		/* Could be handled synchronously. */
134205471Sdelphij		if (ttyoutq_bytesused(&tp->t_outq) == 0)
135205471Sdelphij			return (0);
136205471Sdelphij
137205471Sdelphij		/* Wait for data to be drained. */
138205471Sdelphij		error = tty_wait(tp, &tp->t_outwait);
139205471Sdelphij		if (error)
140205471Sdelphij			return (error);
141205471Sdelphij	}
142205471Sdelphij
143205471Sdelphij	return (0);
144205471Sdelphij}
145205471Sdelphij
146205471Sdelphij/*
147205471Sdelphij * Though ttydev_enter() and ttydev_leave() seem to be related, they
148205471Sdelphij * don't have to be used together. ttydev_enter() is used by the cdev
149205471Sdelphij * operations to prevent an actual operation from being processed when
150205471Sdelphij * the TTY has been abandoned. ttydev_leave() is used by ttydev_open()
151205471Sdelphij * and ttydev_close() to determine whether per-TTY data should be
152205471Sdelphij * deallocated.
153205471Sdelphij */
154205471Sdelphij
155205471Sdelphijstatic __inline int
156205471Sdelphijttydev_enter(struct tty *tp)
157205471Sdelphij{
158205471Sdelphij	tty_lock(tp);
159205471Sdelphij
160205471Sdelphij	if (tty_gone(tp) || !tty_opened(tp)) {
161205471Sdelphij		/* Device is already gone. */
162205471Sdelphij		tty_unlock(tp);
163205471Sdelphij		return (ENXIO);
164205471Sdelphij	}
165205471Sdelphij
166205471Sdelphij	return (0);
167205471Sdelphij}
168205471Sdelphij
169205471Sdelphijstatic void
170205471Sdelphijttydev_leave(struct tty *tp)
171205471Sdelphij{
172205471Sdelphij	tty_lock_assert(tp, MA_OWNED);
173205471Sdelphij
174205471Sdelphij	if (tty_opened(tp) || tp->t_flags & TF_OPENCLOSE) {
175205471Sdelphij		/* Device is still opened somewhere. */
176205471Sdelphij		tty_unlock(tp);
177205471Sdelphij		return;
178205471Sdelphij	}
179205471Sdelphij
180205471Sdelphij	tp->t_flags |= TF_OPENCLOSE;
181205471Sdelphij
182205471Sdelphij	/* Stop asynchronous I/O. */
183205471Sdelphij	funsetown(&tp->t_sigio);
184205471Sdelphij
185205471Sdelphij	/* Remove console TTY. */
186205471Sdelphij	if (constty == tp)
187205471Sdelphij		constty_clear();
188205471Sdelphij
189205471Sdelphij	/* Drain any output. */
190205471Sdelphij	MPASS((tp->t_flags & TF_STOPPED) == 0);
191205471Sdelphij	if (!tty_gone(tp))
192205471Sdelphij		tty_drain(tp);
193205471Sdelphij
194205471Sdelphij	ttydisc_close(tp);
195205471Sdelphij
196205471Sdelphij	/* Destroy associated buffers already. */
197205471Sdelphij	ttyinq_free(&tp->t_inq);
198205471Sdelphij	tp->t_inlow = 0;
199205471Sdelphij	ttyoutq_free(&tp->t_outq);
200205471Sdelphij	tp->t_outlow = 0;
201205471Sdelphij
202205471Sdelphij	knlist_clear(&tp->t_inpoll.si_note, 1);
203205471Sdelphij	knlist_clear(&tp->t_outpoll.si_note, 1);
204205471Sdelphij
205205471Sdelphij	if (!tty_gone(tp))
206205471Sdelphij		ttydevsw_close(tp);
207205471Sdelphij
208205471Sdelphij	tp->t_flags &= ~TF_OPENCLOSE;
209205471Sdelphij	cv_broadcast(&tp->t_dcdwait);
210205471Sdelphij	tty_rel_free(tp);
211205471Sdelphij}
212205471Sdelphij
213205471Sdelphij/*
214205471Sdelphij * Operations that are exposed through the character device in /dev.
215205471Sdelphij */
216205471Sdelphijstatic int
217205471Sdelphijttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
218205471Sdelphij{
219205471Sdelphij	struct tty *tp = dev->si_drv1;
220205471Sdelphij	int error = 0;
221205471Sdelphij
222205471Sdelphij	/* Disallow access when the TTY belongs to a different prison. */
223205471Sdelphij	if (dev->si_cred != NULL &&
224205471Sdelphij	    dev->si_cred->cr_prison != td->td_ucred->cr_prison &&
225205471Sdelphij	    priv_check(td, PRIV_TTY_PRISON)) {
226205471Sdelphij		return (EPERM);
227205471Sdelphij	}
228205471Sdelphij
229205471Sdelphij	tty_lock(tp);
230205471Sdelphij	if (tty_gone(tp)) {
231205471Sdelphij		/* Device is already gone. */
232205471Sdelphij		tty_unlock(tp);
233205471Sdelphij		return (ENXIO);
234205471Sdelphij	}
235205471Sdelphij
236205471Sdelphij	/*
237205471Sdelphij	 * Block when other processes are currently opening or closing
238205471Sdelphij	 * the TTY.
239205471Sdelphij	 */
240205471Sdelphij	while (tp->t_flags & TF_OPENCLOSE) {
241205471Sdelphij		error = tty_wait(tp, &tp->t_dcdwait);
242205471Sdelphij		if (error != 0) {
243205471Sdelphij			tty_unlock(tp);
244205471Sdelphij			return (error);
245205471Sdelphij		}
246205471Sdelphij	}
247205471Sdelphij	tp->t_flags |= TF_OPENCLOSE;
248205471Sdelphij
249205471Sdelphij	/*
250205471Sdelphij	 * Make sure the "tty" and "cua" device cannot be opened at the
251205471Sdelphij	 * same time.
252205471Sdelphij	 */
253205471Sdelphij	if (TTY_CALLOUT(tp, dev)) {
254205471Sdelphij		if (tp->t_flags & TF_OPENED_IN) {
255205471Sdelphij			error = EBUSY;
256205471Sdelphij			goto done;
257205471Sdelphij		}
258205471Sdelphij	} else {
259205471Sdelphij		if (tp->t_flags & TF_OPENED_OUT) {
260205471Sdelphij			error = EBUSY;
261205471Sdelphij			goto done;
262205471Sdelphij		}
263205471Sdelphij	}
264205471Sdelphij
265205471Sdelphij	if (tp->t_flags & TF_EXCLUDE && priv_check(td, PRIV_TTY_EXCLUSIVE)) {
266205471Sdelphij		error = EBUSY;
267205471Sdelphij		goto done;
268205471Sdelphij	}
269205471Sdelphij
270205471Sdelphij	if (!tty_opened(tp)) {
271205471Sdelphij		/* Set proper termios flags. */
272205471Sdelphij		if (TTY_CALLOUT(tp, dev)) {
273205471Sdelphij			tp->t_termios = tp->t_termios_init_out;
274205471Sdelphij		} else {
275205471Sdelphij			tp->t_termios = tp->t_termios_init_in;
276205471Sdelphij		}
277205471Sdelphij		ttydevsw_param(tp, &tp->t_termios);
278205471Sdelphij
279205471Sdelphij		ttydevsw_modem(tp, SER_DTR|SER_RTS, 0);
280205471Sdelphij
281205471Sdelphij		error = ttydevsw_open(tp);
282205471Sdelphij		if (error != 0)
283205471Sdelphij			goto done;
284205471Sdelphij
285205471Sdelphij		ttydisc_open(tp);
286205471Sdelphij		tty_watermarks(tp);
287205471Sdelphij	}
288205471Sdelphij
289205471Sdelphij	/* Wait for Carrier Detect. */
290205471Sdelphij	if (!TTY_CALLOUT(tp, dev) && (oflags & O_NONBLOCK) == 0 &&
291205471Sdelphij	    (tp->t_termios.c_cflag & CLOCAL) == 0) {
292205471Sdelphij		while ((ttydevsw_modem(tp, 0, 0) & SER_DCD) == 0) {
293205471Sdelphij			error = tty_wait(tp, &tp->t_dcdwait);
294205471Sdelphij			if (error != 0)
295205471Sdelphij				goto done;
296205471Sdelphij		}
297205471Sdelphij	}
298205471Sdelphij
299205471Sdelphij	if (dev == dev_console)
300205471Sdelphij		tp->t_flags |= TF_OPENED_CONS;
301205471Sdelphij	else if (TTY_CALLOUT(tp, dev))
302205471Sdelphij		tp->t_flags |= TF_OPENED_OUT;
303205471Sdelphij	else
304205471Sdelphij		tp->t_flags |= TF_OPENED_IN;
305205471Sdelphij
306205471Sdelphijdone:	tp->t_flags &= ~TF_OPENCLOSE;
307205471Sdelphij	cv_broadcast(&tp->t_dcdwait);
308205471Sdelphij	ttydev_leave(tp);
309205471Sdelphij
310205471Sdelphij	return (error);
311205471Sdelphij}
312205471Sdelphij
313205471Sdelphijstatic int
314205471Sdelphijttydev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
315205471Sdelphij{
316205471Sdelphij	struct tty *tp = dev->si_drv1;
317205471Sdelphij
318205471Sdelphij	tty_lock(tp);
319205471Sdelphij
320205471Sdelphij	/*
321205471Sdelphij	 * Don't actually close the device if it is being used as the
322205471Sdelphij	 * console.
323205471Sdelphij	 */
324205471Sdelphij	MPASS((tp->t_flags & TF_OPENED) != TF_OPENED);
325205471Sdelphij	if (dev == dev_console)
326205471Sdelphij		tp->t_flags &= ~TF_OPENED_CONS;
327205471Sdelphij	else
328205471Sdelphij		tp->t_flags &= ~(TF_OPENED_IN|TF_OPENED_OUT);
329205471Sdelphij
330205471Sdelphij	if (tp->t_flags & TF_OPENED) {
331157043Sdes		tty_unlock(tp);
332157043Sdes		return (0);
333157043Sdes	}
334157043Sdes
335157043Sdes	/*
336157043Sdes	 * This can only be called once. The callin and the callout
337157043Sdes	 * devices cannot be opened at the same time.
338157043Sdes	 */
339157043Sdes	tp->t_flags &= ~(TF_EXCLUDE|TF_STOPPED);
340157043Sdes
341157043Sdes	/* Properly wake up threads that are stuck - revoke(). */
342157043Sdes	tp->t_revokecnt++;
343205471Sdelphij	tty_wakeup(tp, FREAD|FWRITE);
344157043Sdes	cv_broadcast(&tp->t_bgwait);
345157043Sdes
346157043Sdes	ttydev_leave(tp);
347157043Sdes
348157043Sdes	return (0);
349157043Sdes}
350157043Sdes
351157043Sdesstatic __inline int
352157043Sdestty_is_ctty(struct tty *tp, struct proc *p)
353157043Sdes{
354157043Sdes	tty_lock_assert(tp, MA_OWNED);
355157043Sdes
356157043Sdes	return (p->p_session == tp->t_session && p->p_flag & P_CONTROLT);
357157043Sdes}
358157043Sdes
359157043Sdesstatic int
360157043Sdestty_wait_background(struct tty *tp, struct thread *td, int sig)
361157043Sdes{
362157043Sdes	struct proc *p = td->td_proc;
363157043Sdes	struct pgrp *pg;
364157043Sdes	int error;
365157043Sdes
366157043Sdes	MPASS(sig == SIGTTIN || sig == SIGTTOU);
367157043Sdes	tty_lock_assert(tp, MA_OWNED);
368157043Sdes
369157043Sdes	for (;;) {
370157043Sdes		PROC_LOCK(p);
371157043Sdes		/*
372157043Sdes		 * The process should only sleep, when:
373157043Sdes		 * - This terminal is the controling terminal
374157043Sdes		 * - Its process group is not the foreground process
375157043Sdes		 *   group
376157043Sdes		 * - The parent process isn't waiting for the child to
377157043Sdes		 *   exit
378157043Sdes		 * - the signal to send to the process isn't masked
379157043Sdes		 */
380157043Sdes		if (!tty_is_ctty(tp, p) || p->p_pgrp == tp->t_pgrp) {
381157043Sdes			/* Allow the action to happen. */
382157043Sdes			PROC_UNLOCK(p);
383157043Sdes			return (0);
384157043Sdes		}
385157043Sdes
386157043Sdes		if (SIGISMEMBER(p->p_sigacts->ps_sigignore, sig) ||
387157043Sdes		    SIGISMEMBER(td->td_sigmask, sig)) {
388157043Sdes			/* Only allow them in write()/ioctl(). */
389157043Sdes			PROC_UNLOCK(p);
390157043Sdes			return (sig == SIGTTOU ? 0 : EIO);
391157043Sdes		}
392157043Sdes
393157043Sdes		pg = p->p_pgrp;
394157043Sdes		if (p->p_flag & P_PPWAIT || pg->pg_jobc == 0) {
395157043Sdes			/* Don't allow the action to happen. */
396157043Sdes			PROC_UNLOCK(p);
397157043Sdes			return (EIO);
398157043Sdes		}
399157043Sdes		PROC_UNLOCK(p);
400157043Sdes
401157043Sdes		/*
402157043Sdes		 * Send the signal and sleep until we're the new
403157043Sdes		 * foreground process group.
404157043Sdes		 */
405157043Sdes		PGRP_LOCK(pg);
406157043Sdes		pgsignal(pg, sig, 1);
407157043Sdes		PGRP_UNLOCK(pg);
408157043Sdes
409157043Sdes		error = tty_wait(tp, &tp->t_bgwait);
410157043Sdes		if (error)
411157043Sdes			return (error);
412157043Sdes	}
413157043Sdes}
414157043Sdes
415157043Sdesstatic int
416157043Sdesttydev_read(struct cdev *dev, struct uio *uio, int ioflag)
417157043Sdes{
418157043Sdes	struct tty *tp = dev->si_drv1;
419157043Sdes	int error;
420157043Sdes
421157043Sdes	error = ttydev_enter(tp);
422145474Skientzle	if (error)
423145474Skientzle		goto done;
424145474Skientzle
425145474Skientzle	error = tty_wait_background(tp, curthread, SIGTTIN);
426145474Skientzle	if (error) {
427145474Skientzle		tty_unlock(tp);
428145474Skientzle		goto done;
429145474Skientzle	}
430145474Skientzle
431145474Skientzle	error = ttydisc_read(tp, uio, ioflag);
432145474Skientzle	tty_unlock(tp);
433145474Skientzle
434145474Skientzle	/*
435145474Skientzle	 * The read() call should not throw an error when the device is
436145474Skientzle	 * being destroyed. Silently convert it to an EOF.
437145474Skientzle	 */
438145474Skientzledone:	if (error == ENXIO)
439145474Skientzle		error = 0;
440145474Skientzle	return (error);
441145474Skientzle}
442145474Skientzle
443145474Skientzlestatic int
444145474Skientzlettydev_write(struct cdev *dev, struct uio *uio, int ioflag)
445145474Skientzle{
446145474Skientzle	struct tty *tp = dev->si_drv1;
447145474Skientzle	int error;
448145474Skientzle
449145474Skientzle	error = ttydev_enter(tp);
450145474Skientzle	if (error)
451145474Skientzle		return (error);
452145474Skientzle
453145474Skientzle	if (tp->t_termios.c_lflag & TOSTOP) {
454145474Skientzle		error = tty_wait_background(tp, curthread, SIGTTOU);
455145474Skientzle		if (error)
456145474Skientzle			goto done;
457145474Skientzle	}
458145474Skientzle
459145474Skientzle	if (ioflag & IO_NDELAY && tp->t_flags & TF_BUSY_OUT) {
460145474Skientzle		/* Allow non-blocking writes to bypass serialization. */
461145474Skientzle		error = ttydisc_write(tp, uio, ioflag);
462145474Skientzle	} else {
463145474Skientzle		/* Serialize write() calls. */
464131377Stjr		while (tp->t_flags & TF_BUSY_OUT) {
465131377Stjr			error = tty_wait(tp, &tp->t_bgwait);
466131377Stjr			if (error)
467131377Stjr				goto done;
468131377Stjr		}
469131377Stjr
470131377Stjr 		tp->t_flags |= TF_BUSY_OUT;
471131377Stjr		error = ttydisc_write(tp, uio, ioflag);
472131377Stjr 		tp->t_flags &= ~TF_BUSY_OUT;
473131377Stjr		cv_broadcast(&tp->t_bgwait);
474131377Stjr	}
475131377Stjr
476131377Stjrdone:	tty_unlock(tp);
477131377Stjr	return (error);
478131377Stjr}
479131377Stjr
480131377Stjrstatic int
481131377Stjrttydev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
482131377Stjr    struct thread *td)
483131377Stjr{
484131377Stjr	struct tty *tp = dev->si_drv1;
485131377Stjr	int error;
486131377Stjr
487131377Stjr	error = ttydev_enter(tp);
488131377Stjr	if (error)
489131377Stjr		return (error);
490131377Stjr
491131377Stjr	switch (cmd) {
492131377Stjr	case TIOCCBRK:
493131377Stjr	case TIOCCONS:
494131377Stjr	case TIOCDRAIN:
495131377Stjr	case TIOCEXCL:
496131377Stjr	case TIOCFLUSH:
497131377Stjr	case TIOCNXCL:
498131377Stjr	case TIOCSBRK:
499131377Stjr	case TIOCSCTTY:
500131377Stjr	case TIOCSETA:
501131377Stjr	case TIOCSETAF:
502131377Stjr	case TIOCSETAW:
503131377Stjr	case TIOCSPGRP:
504131377Stjr	case TIOCSTART:
505131377Stjr	case TIOCSTAT:
506131377Stjr	case TIOCSTOP:
507131377Stjr	case TIOCSWINSZ:
508131377Stjr#if 0
509131377Stjr	case TIOCSDRAINWAIT:
510131377Stjr	case TIOCSETD:
511131377Stjr	case TIOCSTI:
512131377Stjr#endif
513131377Stjr#ifdef COMPAT_43TTY
514131377Stjr	case  TIOCLBIC:
515131377Stjr	case  TIOCLBIS:
516131377Stjr	case  TIOCLSET:
517131377Stjr	case  TIOCSETC:
518131377Stjr	case OTIOCSETD:
519131377Stjr	case  TIOCSETN:
520131377Stjr	case  TIOCSETP:
521131377Stjr	case  TIOCSLTC:
522131377Stjr#endif /* COMPAT_43TTY */
523131377Stjr		/*
524131377Stjr		 * If the ioctl() causes the TTY to be modified, let it
525131377Stjr		 * wait in the background.
526131377Stjr		 */
527131377Stjr		error = tty_wait_background(tp, curthread, SIGTTOU);
528131377Stjr		if (error)
529131377Stjr			goto done;
530131377Stjr	}
531131377Stjr
532131377Stjr	error = tty_ioctl(tp, cmd, data, td);
533131377Stjrdone:	tty_unlock(tp);
534131377Stjr
535131377Stjr	return (error);
536131377Stjr}
537131377Stjr
538131377Stjrstatic int
539131377Stjrttydev_poll(struct cdev *dev, int events, struct thread *td)
540131377Stjr{
541131377Stjr	struct tty *tp = dev->si_drv1;
542131377Stjr	int error, revents = 0;
543131377Stjr
544131377Stjr	error = ttydev_enter(tp);
545131377Stjr	if (error) {
546131377Stjr		/* Don't return the error here, but the event mask. */
547131377Stjr		return (events &
548131377Stjr		    (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM));
549131377Stjr	}
550131377Stjr
551131377Stjr	if (events & (POLLIN|POLLRDNORM)) {
552131377Stjr		/* See if we can read something. */
553131377Stjr		if (ttydisc_read_poll(tp) > 0)
554131377Stjr			revents |= events & (POLLIN|POLLRDNORM);
555131377Stjr	}
556131377Stjr	if (events & (POLLOUT|POLLWRNORM)) {
557131377Stjr		/* See if we can write something. */
558131377Stjr		if (ttydisc_write_poll(tp) > 0)
559131377Stjr			revents |= events & (POLLOUT|POLLWRNORM);
560131377Stjr	}
561131377Stjr	if (tp->t_flags & TF_ZOMBIE)
562131377Stjr		/* Hangup flag on zombie state. */
563131377Stjr		revents |= events & POLLHUP;
564131377Stjr
565131377Stjr	if (revents == 0) {
566131377Stjr		if (events & (POLLIN|POLLRDNORM))
567131377Stjr			selrecord(td, &tp->t_inpoll);
568131377Stjr		if (events & (POLLOUT|POLLWRNORM))
569131377Stjr			selrecord(td, &tp->t_outpoll);
570131377Stjr	}
571131377Stjr
572131377Stjr	tty_unlock(tp);
573131377Stjr
574131377Stjr	return (revents);
575131377Stjr}
576131377Stjr
577131377Stjrstatic int
578131377Stjrttydev_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
579131377Stjr{
580131377Stjr	struct tty *tp = dev->si_drv1;
581131377Stjr	int error;
582131377Stjr
583131377Stjr	/* Handle mmap() through the driver. */
584131377Stjr
585131377Stjr	error = ttydev_enter(tp);
586131377Stjr	if (error)
587131377Stjr		return (-1);
588131377Stjr	error = ttydevsw_mmap(tp, offset, paddr, nprot);
589131377Stjr	tty_unlock(tp);
590131377Stjr
591131377Stjr	return (error);
592131377Stjr}
593131377Stjr
594131377Stjr/*
595131377Stjr * kqueue support.
596131377Stjr */
597131377Stjr
598131377Stjrstatic void
599131377Stjrtty_kqops_read_detach(struct knote *kn)
600131377Stjr{
601131377Stjr	struct tty *tp = kn->kn_hook;
602131377Stjr
603131377Stjr	knlist_remove(&tp->t_inpoll.si_note, kn, 0);
604131377Stjr}
605131377Stjr
606131377Stjrstatic int
607131377Stjrtty_kqops_read_event(struct knote *kn, long hint)
608131377Stjr{
609131377Stjr	struct tty *tp = kn->kn_hook;
610131377Stjr
611131377Stjr	tty_lock_assert(tp, MA_OWNED);
612131377Stjr
613131377Stjr	if (tty_gone(tp) || tp->t_flags & TF_ZOMBIE) {
614131377Stjr		kn->kn_flags |= EV_EOF;
615131377Stjr		return (1);
616131377Stjr	} else {
617131377Stjr		kn->kn_data = ttydisc_read_poll(tp);
618131377Stjr		return (kn->kn_data > 0);
619131377Stjr	}
620131377Stjr}
621131377Stjr
622131377Stjrstatic void
623131377Stjrtty_kqops_write_detach(struct knote *kn)
624131377Stjr{
625131377Stjr	struct tty *tp = kn->kn_hook;
626131377Stjr
627131377Stjr	knlist_remove(&tp->t_outpoll.si_note, kn, 0);
628131377Stjr}
629131377Stjr
630131377Stjrstatic int
631131377Stjrtty_kqops_write_event(struct knote *kn, long hint)
632131377Stjr{
633131377Stjr	struct tty *tp = kn->kn_hook;
634131377Stjr
635131377Stjr	tty_lock_assert(tp, MA_OWNED);
636131377Stjr
637131377Stjr	if (tty_gone(tp)) {
638131377Stjr		kn->kn_flags |= EV_EOF;
639131377Stjr		return (1);
640131377Stjr	} else {
641131377Stjr		kn->kn_data = ttydisc_write_poll(tp);
642131377Stjr		return (kn->kn_data > 0);
643131377Stjr	}
644131377Stjr}
645131377Stjr
646131377Stjrstatic struct filterops tty_kqops_read =
647131377Stjr    { 1, NULL, tty_kqops_read_detach, tty_kqops_read_event };
648131377Stjrstatic struct filterops tty_kqops_write =
649131377Stjr    { 1, NULL, tty_kqops_write_detach, tty_kqops_write_event };
650131377Stjr
651131377Stjrstatic int
652131377Stjrttydev_kqfilter(struct cdev *dev, struct knote *kn)
653131377Stjr{
654131377Stjr	struct tty *tp = dev->si_drv1;
655131377Stjr	int error;
656131377Stjr
657131377Stjr	error = ttydev_enter(tp);
658131377Stjr	if (error)
659131377Stjr		return (error);
660131377Stjr
661131377Stjr	switch (kn->kn_filter) {
662131377Stjr	case EVFILT_READ:
663131377Stjr		kn->kn_hook = tp;
664131377Stjr		kn->kn_fop = &tty_kqops_read;
665131377Stjr		knlist_add(&tp->t_inpoll.si_note, kn, 1);
666131377Stjr		break;
667131377Stjr	case EVFILT_WRITE:
668131377Stjr		kn->kn_hook = tp;
669131377Stjr		kn->kn_fop = &tty_kqops_write;
670131377Stjr		knlist_add(&tp->t_outpoll.si_note, kn, 1);
671131377Stjr		break;
672131377Stjr	default:
673131377Stjr		error = EINVAL;
674131377Stjr		break;
675131377Stjr	}
676131377Stjr
677131377Stjr	tty_unlock(tp);
678131377Stjr	return (error);
679131377Stjr}
680131377Stjr
681131377Stjrstatic struct cdevsw ttydev_cdevsw = {
682131377Stjr	.d_version	= D_VERSION,
683131377Stjr	.d_open		= ttydev_open,
684131377Stjr	.d_close	= ttydev_close,
685131377Stjr	.d_read		= ttydev_read,
686131377Stjr	.d_write	= ttydev_write,
687131377Stjr	.d_ioctl	= ttydev_ioctl,
688131377Stjr	.d_kqfilter	= ttydev_kqfilter,
689131377Stjr	.d_poll		= ttydev_poll,
690131377Stjr	.d_mmap		= ttydev_mmap,
691131377Stjr	.d_name		= "ttydev",
692131377Stjr	.d_flags	= D_TTY,
693131377Stjr};
694131377Stjr
695131377Stjr/*
696131377Stjr * Init/lock-state devices
697131377Stjr */
698131377Stjr
699131377Stjrstatic int
700131377Stjrttyil_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
701131377Stjr{
702131377Stjr	struct tty *tp = dev->si_drv1;
703131377Stjr	int error = 0;
704131377Stjr
70592111Sgreen	tty_lock(tp);
70692111Sgreen	if (tty_gone(tp))
70792111Sgreen		error = ENODEV;
70892111Sgreen	tty_unlock(tp);
70992111Sgreen
71092111Sgreen	return (error);
71192111Sgreen}
71292111Sgreen
71392111Sgreenstatic int
714131377Stjrttyil_close(struct cdev *dev, int flag, int mode, struct thread *td)
71542468Speter{
71642468Speter	return (0);
71742468Speter}
71842468Speter
71942468Speterstatic int
72042468Speterttyil_rdwr(struct cdev *dev, struct uio *uio, int ioflag)
72142468Speter{
72242468Speter	return (ENODEV);
72342468Speter}
72442468Speter
72542468Speterstatic int
72642468Speterttyil_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
72742468Speter    struct thread *td)
72842468Speter{
72942468Speter	struct tty *tp = dev->si_drv1;
73042468Speter	int error = 0;
73142468Speter
73242468Speter	tty_lock(tp);
73342468Speter	if (tty_gone(tp)) {
73442468Speter		error = ENODEV;
73542468Speter		goto done;
73642468Speter	}
73742468Speter
73842468Speter	switch (cmd) {
73942468Speter	case TIOCGETA:
74042468Speter		/* Obtain terminal flags through tcgetattr(). */
74142468Speter		*(struct termios*)data = *(struct termios*)dev->si_drv2;
74242468Speter		break;
74342468Speter	case TIOCSETA:
74442468Speter		/* Set terminal flags through tcsetattr(). */
74542468Speter		error = priv_check(td, PRIV_TTY_SETA);
74642468Speter		if (error)
74742468Speter			break;
74842468Speter		*(struct termios*)dev->si_drv2 = *(struct termios*)data;
74942468Speter		break;
75042468Speter	case TIOCGETD:
75142468Speter		*(int *)data = TTYDISC;
75242468Speter		break;
75342468Speter	case TIOCGWINSZ:
75442468Speter		bzero(data, sizeof(struct winsize));
75542468Speter		break;
75642468Speter	default:
75742468Speter		error = ENOTTY;
75842468Speter	}
75942468Speter
76042468Speterdone:	tty_unlock(tp);
76142468Speter	return (error);
76242468Speter}
76342468Speter
76442468Speterstatic struct cdevsw ttyil_cdevsw = {
76542468Speter	.d_version	= D_VERSION,
76642468Speter	.d_open		= ttyil_open,
76742468Speter	.d_close	= ttyil_close,
76842468Speter	.d_read		= ttyil_rdwr,
76942468Speter	.d_write	= ttyil_rdwr,
77042468Speter	.d_ioctl	= ttyil_ioctl,
77142468Speter	.d_name		= "ttyil",
77242468Speter	.d_flags	= D_TTY,
77342468Speter};
77442468Speter
77542468Speterstatic void
77642468Spetertty_init_termios(struct tty *tp)
77742468Speter{
77842468Speter	struct termios *t = &tp->t_termios_init_in;
77942468Speter
78042468Speter	t->c_cflag = TTYDEF_CFLAG;
78142468Speter	t->c_iflag = TTYDEF_IFLAG;
78233904Ssteve	t->c_lflag = TTYDEF_LFLAG;
78333904Ssteve	t->c_oflag = TTYDEF_OFLAG;
78433904Ssteve	t->c_ispeed = TTYDEF_SPEED;
78533904Ssteve	t->c_ospeed = TTYDEF_SPEED;
78633904Ssteve	memcpy(&t->c_cc, ttydefchars, sizeof ttydefchars);
78733904Ssteve
78833904Ssteve	tp->t_termios_init_out = *t;
78933904Ssteve}
79033904Ssteve
79133904Sstevevoid
79233904Sstevetty_init_console(struct tty *tp, speed_t s)
79333904Ssteve{
79433904Ssteve	struct termios *ti = &tp->t_termios_init_in;
79533904Ssteve	struct termios *to = &tp->t_termios_init_out;
79633904Ssteve
79733904Ssteve	if (s != 0) {
79833904Ssteve		ti->c_ispeed = ti->c_ospeed = s;
79933904Ssteve		to->c_ispeed = to->c_ospeed = s;
80033904Ssteve	}
80133904Ssteve
80233904Ssteve	ti->c_cflag |= CLOCAL;
80333904Ssteve	to->c_cflag |= CLOCAL;
80433904Ssteve}
80533904Ssteve
80633904Ssteve/*
80733904Ssteve * Standard device routine implementations, mostly meant for
80833904Ssteve * pseudo-terminal device drivers. When a driver creates a new terminal
80933904Ssteve * device class, missing routines are patched.
81033904Ssteve */
81133904Ssteve
81233904Sstevestatic int
81333904Sstevettydevsw_defopen(struct tty *tp)
81433904Ssteve{
81533904Ssteve
81633904Ssteve	return (0);
81733904Ssteve}
81833904Ssteve
81933904Sstevestatic void
82033904Sstevettydevsw_defclose(struct tty *tp)
82133904Ssteve{
82233904Ssteve}
82333904Ssteve
82433904Sstevestatic void
82533904Sstevettydevsw_defoutwakeup(struct tty *tp)
82633904Ssteve{
82733904Ssteve
82833904Ssteve	panic("Terminal device has output, while not implemented");
82933904Ssteve}
83033904Ssteve
83133904Sstevestatic void
83233904Sstevettydevsw_definwakeup(struct tty *tp)
83333904Ssteve{
83433904Ssteve}
83533904Ssteve
83633904Sstevestatic int
83733904Sstevettydevsw_defioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
83833904Ssteve{
83933904Ssteve
84033904Ssteve	return (ENOIOCTL);
84133904Ssteve}
84233904Ssteve
84333904Sstevestatic int
84433904Sstevettydevsw_defparam(struct tty *tp, struct termios *t)
84533904Ssteve{
84633904Ssteve
84733904Ssteve	/* Use a fake baud rate, we're not a real device. */
84833904Ssteve	t->c_ispeed = t->c_ospeed = TTYDEF_SPEED;
84933904Ssteve
85033904Ssteve	return (0);
85133904Ssteve}
85233904Ssteve
85333904Sstevestatic int
85433904Sstevettydevsw_defmodem(struct tty *tp, int sigon, int sigoff)
85533904Ssteve{
85633904Ssteve
85733904Ssteve	/* Simulate a carrier to make the TTY layer happy. */
85833904Ssteve	return (SER_DCD);
85933904Ssteve}
86033904Ssteve
86133904Sstevestatic int
86233904Sstevettydevsw_defmmap(struct tty *tp, vm_offset_t offset, vm_paddr_t *paddr,
86333904Ssteve    int nprot)
86433904Ssteve{
86533904Ssteve
86633904Ssteve	return (-1);
86733904Ssteve}
86833904Ssteve
86933904Sstevestatic void
870157043Sdesttydevsw_defpktnotify(struct tty *tp, char event)
87133904Ssteve{
87233904Ssteve}
87333904Ssteve
87433904Sstevestatic void
87533904Sstevettydevsw_deffree(void *softc)
87633904Ssteve{
87733904Ssteve
87833904Ssteve	panic("Terminal device freed without a free-handler");
87933904Ssteve}
88033904Ssteve
88133904Ssteve/*
88233904Ssteve * TTY allocation and deallocation. TTY devices can be deallocated when
88333904Ssteve * the driver doesn't use it anymore, when the TTY isn't a session's
88433904Ssteve * controlling TTY and when the device node isn't opened through devfs.
88533904Ssteve */
88633904Ssteve
88733904Sstevestruct tty *
888131377Stjrtty_alloc(struct ttydevsw *tsw, void *sc)
88933904Ssteve{
89033904Ssteve
89133904Ssteve	return (tty_alloc_mutex(tsw, sc, NULL));
892131377Stjr}
89333904Ssteve
894131377Stjrstruct tty *
89533904Sstevetty_alloc_mutex(struct ttydevsw *tsw, void *sc, struct mtx *mutex)
89633904Ssteve{
89733904Ssteve	struct tty *tp;
89833904Ssteve
89933904Ssteve	/* Make sure the driver defines all routines. */
90033904Ssteve#define PATCH_FUNC(x) do {				\
90133904Ssteve	if (tsw->tsw_ ## x == NULL)			\
90233904Ssteve		tsw->tsw_ ## x = ttydevsw_def ## x;	\
90333904Ssteve} while (0)
90433904Ssteve	PATCH_FUNC(open);
90533904Ssteve	PATCH_FUNC(close);
90633904Ssteve	PATCH_FUNC(outwakeup);
90733904Ssteve	PATCH_FUNC(inwakeup);
90833904Ssteve	PATCH_FUNC(ioctl);
90933904Ssteve	PATCH_FUNC(param);
91033904Ssteve	PATCH_FUNC(modem);
91133904Ssteve	PATCH_FUNC(mmap);
91233904Ssteve	PATCH_FUNC(pktnotify);
91333904Ssteve	PATCH_FUNC(free);
91433904Ssteve#undef PATCH_FUNC
91533904Ssteve
91633904Ssteve	tp = malloc(sizeof(struct tty), M_TTY, M_WAITOK|M_ZERO);
91733904Ssteve	tp->t_devsw = tsw;
91833904Ssteve	tp->t_devswsoftc = sc;
91942468Speter	tp->t_flags = tsw->tsw_flags;
92033904Ssteve
921131377Stjr	tty_init_termios(tp);
92233904Ssteve
92333904Ssteve	cv_init(&tp->t_inwait, "ttyin");
92433904Ssteve	cv_init(&tp->t_outwait, "ttyout");
92533904Ssteve	cv_init(&tp->t_bgwait, "ttybg");
92633904Ssteve	cv_init(&tp->t_dcdwait, "ttydcd");
92733904Ssteve
92833904Ssteve	/* Allow drivers to use a custom mutex to lock the TTY. */
92933904Ssteve	if (mutex != NULL) {
93033904Ssteve		tp->t_mtx = mutex;
93133904Ssteve	} else {
93233904Ssteve		tp->t_mtx = &tp->t_mtxobj;
93333904Ssteve		mtx_init(&tp->t_mtxobj, "ttymtx", NULL, MTX_DEF);
93433904Ssteve	}
93533904Ssteve
93633904Ssteve	knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx);
93733904Ssteve	knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx);
93833904Ssteve
93933904Ssteve	sx_xlock(&tty_list_sx);
94033904Ssteve	TAILQ_INSERT_TAIL(&tty_list, tp, t_list);
94133904Ssteve	tty_list_count++;
94233904Ssteve	sx_xunlock(&tty_list_sx);
94333904Ssteve
94433904Ssteve	return (tp);
94533904Ssteve}
946131377Stjr
94717651Speterstatic void
94817651Spetertty_dealloc(void *arg)
94917651Speter{
95017651Speter	struct tty *tp = arg;
95117651Speter
95217651Speter	sx_xlock(&tty_list_sx);
95317651Speter	TAILQ_REMOVE(&tty_list, tp, t_list);
95417651Speter	tty_list_count--;
95517651Speter	sx_xunlock(&tty_list_sx);
95617651Speter
95717651Speter	/* Make sure we haven't leaked buffers. */
95817651Speter	MPASS(ttyinq_getsize(&tp->t_inq) == 0);
95917651Speter	MPASS(ttyoutq_getsize(&tp->t_outq) == 0);
96017651Speter
96117651Speter	knlist_destroy(&tp->t_inpoll.si_note);
96217651Speter	knlist_destroy(&tp->t_outpoll.si_note);
96317651Speter
96417651Speter	cv_destroy(&tp->t_inwait);
96517651Speter	cv_destroy(&tp->t_outwait);
96617651Speter	cv_destroy(&tp->t_bgwait);
96717651Speter	cv_destroy(&tp->t_dcdwait);
96817651Speter
96917651Speter	if (tp->t_mtx == &tp->t_mtxobj)
97017651Speter		mtx_destroy(&tp->t_mtxobj);
97117651Speter	ttydevsw_free(tp);
97217651Speter	free(tp, M_TTY);
97317651Speter}
97417651Speter
97517651Speterstatic void
97617651Spetertty_rel_free(struct tty *tp)
97717651Speter{
97817651Speter	struct cdev *dev;
97917651Speter
98017651Speter	tty_lock_assert(tp, MA_OWNED);
98117651Speter
98217651Speter#define	TF_ACTIVITY	(TF_GONE|TF_OPENED|TF_HOOK|TF_OPENCLOSE)
98317651Speter	if (tp->t_sessioncnt != 0 || (tp->t_flags & TF_ACTIVITY) != TF_GONE) {
98417651Speter		/* TTY is still in use. */
98517651Speter		tty_unlock(tp);
98617651Speter		return;
98717651Speter	}
98817651Speter
98917651Speter	/* TTY can be deallocated. */
99017651Speter	dev = tp->t_dev;
99117651Speter	tp->t_dev = NULL;
99217651Speter	tty_unlock(tp);
99317651Speter
99417651Speter	destroy_dev_sched_cb(dev, tty_dealloc, tp);
99517651Speter}
99617651Speter
99717651Spetervoid
99817651Spetertty_rel_pgrp(struct tty *tp, struct pgrp *pg)
99917651Speter{
100017651Speter	MPASS(tp->t_sessioncnt > 0);
100117651Speter	tty_lock_assert(tp, MA_OWNED);
100217651Speter
100317651Speter	if (tp->t_pgrp == pg)
100417651Speter		tp->t_pgrp = NULL;
100517651Speter
100617651Speter	tty_unlock(tp);
100717651Speter}
100817651Speter
100917651Spetervoid
101017651Spetertty_rel_sess(struct tty *tp, struct session *sess)
101117651Speter{
101217651Speter	MPASS(tp->t_sessioncnt > 0);
101317651Speter
101417651Speter	/* Current session has left. */
101517651Speter	if (tp->t_session == sess) {
101617651Speter		tp->t_session = NULL;
101717651Speter		MPASS(tp->t_pgrp == NULL);
101817651Speter	}
101917651Speter	tp->t_sessioncnt--;
102017651Speter	tty_rel_free(tp);
102117651Speter}
102217651Speter
102317651Spetervoid
102417651Spetertty_rel_gone(struct tty *tp)
102517651Speter{
102617651Speter	MPASS(!tty_gone(tp));
102717651Speter
102817651Speter	/* Simulate carrier removal. */
102917651Speter	ttydisc_modem(tp, 0);
103017651Speter
103117651Speter	/* Wake up all blocked threads. */
103217651Speter	tty_wakeup(tp, FREAD|FWRITE);
103317651Speter	cv_broadcast(&tp->t_bgwait);
103417651Speter	cv_broadcast(&tp->t_dcdwait);
103517651Speter
103617651Speter	tp->t_flags |= TF_GONE;
103717651Speter	tty_rel_free(tp);
103817651Speter}
103917651Speter
104017651Speter/*
104117651Speter * Exposing information about current TTY's through sysctl
104217651Speter */
104317651Speter
104417651Speterstatic void
104517651Spetertty_to_xtty(struct tty *tp, struct xtty *xt)
104617651Speter{
104717651Speter	tty_lock_assert(tp, MA_OWNED);
104817651Speter
104917651Speter	xt->xt_size = sizeof(struct xtty);
105017651Speter	xt->xt_insize = ttyinq_getsize(&tp->t_inq);
105117651Speter	xt->xt_incc = ttyinq_bytescanonicalized(&tp->t_inq);
105217651Speter	xt->xt_inlc = ttyinq_bytesline(&tp->t_inq);
105317651Speter	xt->xt_inlow = tp->t_inlow;
105417651Speter	xt->xt_outsize = ttyoutq_getsize(&tp->t_outq);
105517651Speter	xt->xt_outcc = ttyoutq_bytesused(&tp->t_outq);
105617651Speter	xt->xt_outlow = tp->t_outlow;
105717651Speter	xt->xt_column = tp->t_column;
105817651Speter	xt->xt_pgid = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
105917651Speter	xt->xt_sid = tp->t_session ? tp->t_session->s_sid : 0;
106017651Speter	xt->xt_flags = tp->t_flags;
106117651Speter	xt->xt_dev = tp->t_dev ? dev2udev(tp->t_dev) : NODEV;
106217651Speter}
106317651Speter
106417651Speterstatic int
106517651Spetersysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
106617651Speter{
106717651Speter	unsigned long lsize;
106817651Speter	struct xtty *xtlist, *xt;
106917651Speter	struct tty *tp;
107017651Speter	int error;
107117651Speter
107217651Speter	sx_slock(&tty_list_sx);
107317651Speter	lsize = tty_list_count * sizeof(struct xtty);
107417651Speter	if (lsize == 0) {
107517651Speter		sx_sunlock(&tty_list_sx);
107617651Speter		return (0);
107717651Speter	}
107817651Speter
107917651Speter	xtlist = xt = malloc(lsize, M_TTY, M_WAITOK);
108017651Speter
108117651Speter	TAILQ_FOREACH(tp, &tty_list, t_list) {
108217651Speter		tty_lock(tp);
108317651Speter		tty_to_xtty(tp, xt);
108417651Speter		tty_unlock(tp);
108517651Speter		xt++;
108617651Speter	}
108717651Speter	sx_sunlock(&tty_list_sx);
108817651Speter
108917651Speter	error = SYSCTL_OUT(req, xtlist, lsize);
109017651Speter	free(xtlist, M_TTY);
109117651Speter	return (error);
109217651Speter}
109317651Speter
109417651SpeterSYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_MPSAFE,
109517651Speter	0, 0, sysctl_kern_ttys, "S,xtty", "List of TTYs");
109617651Speter
109717651Speter/*
109817651Speter * Device node creation. Device has been set up, now we can expose it to
109917651Speter * the user.
110017651Speter */
110117651Speter
110217651Spetervoid
110317651Spetertty_makedev(struct tty *tp, struct ucred *cred, const char *fmt, ...)
110417651Speter{
110517651Speter	va_list ap;
110617651Speter	struct cdev *dev;
110717651Speter	const char *prefix = "tty";
110817651Speter	char name[SPECNAMELEN - 3]; /* for "tty" and "cua". */
110917651Speter	uid_t uid;
111017651Speter	gid_t gid;
111117651Speter	mode_t mode;
111217651Speter
111317651Speter	/* Remove "tty" prefix from devices like PTY's. */
111417651Speter	if (tp->t_flags & TF_NOPREFIX)
111517651Speter		prefix = "";
111617651Speter
111717651Speter	va_start(ap, fmt);
111817651Speter	vsnrprintf(name, sizeof name, 32, fmt, ap);
111917651Speter	va_end(ap);
112017651Speter
112117651Speter	if (cred == NULL) {
112217651Speter		/* System device. */
112317651Speter		uid = UID_ROOT;
112417651Speter		gid = GID_WHEEL;
112517651Speter		mode = S_IRUSR|S_IWUSR;
112617651Speter	} else {
112717651Speter		/* User device. */
112817651Speter		uid = cred->cr_ruid;
112917651Speter		gid = GID_TTY;
113017651Speter		mode = S_IRUSR|S_IWUSR|S_IWGRP;
113117651Speter	}
113217651Speter
113317651Speter	/* Master call-in device. */
113417651Speter	dev = make_dev_cred(&ttydev_cdevsw, 0, cred,
113517651Speter	    uid, gid, mode, "%s%s", prefix, name);
113617651Speter	dev->si_drv1 = tp;
113717651Speter	tp->t_dev = dev;
113817651Speter
113917651Speter	/* Slave call-in devices. */
114017651Speter	if (tp->t_flags & TF_INITLOCK) {
114117651Speter		dev = make_dev_cred(&ttyil_cdevsw, 0, cred,
114217651Speter		    uid, gid, mode, "%s%s.init", prefix, name);
114317651Speter		dev_depends(tp->t_dev, dev);
114417651Speter		dev->si_drv1 = tp;
114517651Speter		dev->si_drv2 = &tp->t_termios_init_in;
114617651Speter
114717651Speter		dev = make_dev_cred(&ttyil_cdevsw, 0, cred,
114817651Speter		    uid, gid, mode, "%s%s.lock", prefix, name);
114917651Speter		dev_depends(tp->t_dev, dev);
115017651Speter		dev->si_drv1 = tp;
115117651Speter		dev->si_drv2 = &tp->t_termios_lock_in;
115217651Speter	}
115317651Speter
115417651Speter	/* Call-out devices. */
115517651Speter	if (tp->t_flags & TF_CALLOUT) {
115617651Speter		dev = make_dev_cred(&ttydev_cdevsw, 0, cred,
115717651Speter		    UID_UUCP, GID_DIALER, 0660, "cua%s", name);
115817651Speter		dev_depends(tp->t_dev, dev);
115917651Speter		dev->si_drv1 = tp;
116017651Speter
116117651Speter		/* Slave call-out devices. */
116217651Speter		if (tp->t_flags & TF_INITLOCK) {
116317651Speter			dev = make_dev_cred(&ttyil_cdevsw, 0, cred,
116417651Speter			    UID_UUCP, GID_DIALER, 0660, "cua%s.init", name);
116517651Speter			dev_depends(tp->t_dev, dev);
116617651Speter			dev->si_drv1 = tp;
116717651Speter			dev->si_drv2 = &tp->t_termios_init_out;
116817651Speter
116917651Speter			dev = make_dev_cred(&ttyil_cdevsw, 0, cred,
117017651Speter			    UID_UUCP, GID_DIALER, 0660, "cua%s.lock", name);
117117651Speter			dev_depends(tp->t_dev, dev);
117217651Speter			dev->si_drv1 = tp;
117317651Speter			dev->si_drv2 = &tp->t_termios_lock_out;
117417651Speter		}
117517651Speter	}
117617651Speter}
117717651Speter
117817651Speter/*
117917651Speter * Signalling processes.
118017651Speter */
118117651Speter
118217651Spetervoid
1183tty_signal_sessleader(struct tty *tp, int sig)
1184{
1185	struct proc *p;
1186
1187	tty_lock_assert(tp, MA_OWNED);
1188	MPASS(sig >= 1 && sig < NSIG);
1189
1190	/* Make signals start output again. */
1191	tp->t_flags &= ~TF_STOPPED;
1192
1193	if (tp->t_session != NULL && tp->t_session->s_leader != NULL) {
1194		p = tp->t_session->s_leader;
1195		PROC_LOCK(p);
1196		psignal(p, sig);
1197		PROC_UNLOCK(p);
1198	}
1199}
1200
1201void
1202tty_signal_pgrp(struct tty *tp, int sig)
1203{
1204	tty_lock_assert(tp, MA_OWNED);
1205	MPASS(sig >= 1 && sig < NSIG);
1206
1207	/* Make signals start output again. */
1208	tp->t_flags &= ~TF_STOPPED;
1209
1210	if (sig == SIGINFO && !(tp->t_termios.c_lflag & NOKERNINFO))
1211		tty_info(tp);
1212	if (tp->t_pgrp != NULL) {
1213		PGRP_LOCK(tp->t_pgrp);
1214		pgsignal(tp->t_pgrp, sig, 1);
1215		PGRP_UNLOCK(tp->t_pgrp);
1216	}
1217}
1218
1219void
1220tty_wakeup(struct tty *tp, int flags)
1221{
1222	if (tp->t_flags & TF_ASYNC && tp->t_sigio != NULL)
1223		pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL));
1224
1225	if (flags & FWRITE) {
1226		cv_broadcast(&tp->t_outwait);
1227		selwakeup(&tp->t_outpoll);
1228		KNOTE_LOCKED(&tp->t_outpoll.si_note, 0);
1229	}
1230	if (flags & FREAD) {
1231		cv_broadcast(&tp->t_inwait);
1232		selwakeup(&tp->t_inpoll);
1233		KNOTE_LOCKED(&tp->t_inpoll.si_note, 0);
1234	}
1235}
1236
1237int
1238tty_wait(struct tty *tp, struct cv *cv)
1239{
1240	int error;
1241	int revokecnt = tp->t_revokecnt;
1242
1243	tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED);
1244	MPASS(!tty_gone(tp));
1245
1246	error = cv_wait_sig(cv, tp->t_mtx);
1247
1248	/* Restart the system call when we may have been revoked. */
1249	if (tp->t_revokecnt != revokecnt)
1250		return (ERESTART);
1251
1252	/* Bail out when the device slipped away. */
1253	if (tty_gone(tp))
1254		return (ENXIO);
1255
1256	return (error);
1257}
1258
1259int
1260tty_timedwait(struct tty *tp, struct cv *cv, int hz)
1261{
1262	int error;
1263	int revokecnt = tp->t_revokecnt;
1264
1265	tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED);
1266	MPASS(!tty_gone(tp));
1267
1268	error = cv_timedwait_sig(cv, tp->t_mtx, hz);
1269
1270	/* Restart the system call when we may have been revoked. */
1271	if (tp->t_revokecnt != revokecnt)
1272		return (ERESTART);
1273
1274	/* Bail out when the device slipped away. */
1275	if (tty_gone(tp))
1276		return (ENXIO);
1277
1278	return (error);
1279}
1280
1281void
1282tty_flush(struct tty *tp, int flags)
1283{
1284	if (flags & FWRITE) {
1285		tp->t_flags &= ~TF_HIWAT_OUT;
1286		ttyoutq_flush(&tp->t_outq);
1287		tty_wakeup(tp, FWRITE);
1288		ttydevsw_pktnotify(tp, TIOCPKT_FLUSHWRITE);
1289	}
1290	if (flags & FREAD) {
1291		tty_hiwat_in_unblock(tp);
1292		ttyinq_flush(&tp->t_inq);
1293		ttydevsw_inwakeup(tp);
1294		ttydevsw_pktnotify(tp, TIOCPKT_FLUSHREAD);
1295	}
1296}
1297
1298static int
1299tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, struct thread *td)
1300{
1301	int error;
1302
1303	switch (cmd) {
1304	/*
1305	 * Modem commands.
1306	 * The SER_* and TIOCM_* flags are the same, but one bit
1307	 * shifted. I don't know why.
1308	 */
1309	case TIOCSDTR:
1310		ttydevsw_modem(tp, SER_DTR, 0);
1311		return (0);
1312	case TIOCCDTR:
1313		ttydevsw_modem(tp, 0, SER_DTR);
1314		return (0);
1315	case TIOCMSET: {
1316		int bits = *(int *)data;
1317		ttydevsw_modem(tp,
1318		    (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1,
1319		    ((~bits) & (TIOCM_DTR | TIOCM_RTS)) >> 1);
1320		return (0);
1321	}
1322	case TIOCMBIS: {
1323		int bits = *(int *)data;
1324		ttydevsw_modem(tp, (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1, 0);
1325		return (0);
1326	}
1327	case TIOCMBIC: {
1328		int bits = *(int *)data;
1329		ttydevsw_modem(tp, 0, (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1);
1330		return (0);
1331	}
1332	case TIOCMGET:
1333		*(int *)data = TIOCM_LE + (ttydevsw_modem(tp, 0, 0) << 1);
1334		return (0);
1335
1336	case FIOASYNC:
1337		if (*(int *)data)
1338			tp->t_flags |= TF_ASYNC;
1339		else
1340			tp->t_flags &= ~TF_ASYNC;
1341		return (0);
1342	case FIONBIO:
1343		/* This device supports non-blocking operation. */
1344		return (0);
1345	case FIONREAD:
1346		*(int *)data = ttyinq_bytescanonicalized(&tp->t_inq);
1347		return (0);
1348	case FIOSETOWN:
1349		if (tp->t_session != NULL && !tty_is_ctty(tp, td->td_proc))
1350			/* Not allowed to set ownership. */
1351			return (ENOTTY);
1352
1353		/* Temporarily unlock the TTY to set ownership. */
1354		tty_unlock(tp);
1355		error = fsetown(*(int *)data, &tp->t_sigio);
1356		tty_lock(tp);
1357		return (error);
1358	case FIOGETOWN:
1359		if (tp->t_session != NULL && !tty_is_ctty(tp, td->td_proc))
1360			/* Not allowed to set ownership. */
1361			return (ENOTTY);
1362
1363		/* Get ownership. */
1364		*(int *)data = fgetown(&tp->t_sigio);
1365		return (0);
1366	case TIOCGETA:
1367		/* Obtain terminal flags through tcgetattr(). */
1368		*(struct termios*)data = tp->t_termios;
1369		return (0);
1370	case TIOCSETA:
1371	case TIOCSETAW:
1372	case TIOCSETAF: {
1373		struct termios *t = data;
1374
1375		/*
1376		 * Who makes up these funny rules? According to POSIX,
1377		 * input baud rate is set equal to the output baud rate
1378		 * when zero.
1379		 */
1380		if (t->c_ispeed == 0)
1381			t->c_ispeed = t->c_ospeed;
1382
1383		/* Discard any unsupported bits. */
1384		t->c_iflag &= TTYSUP_IFLAG;
1385		t->c_oflag &= TTYSUP_OFLAG;
1386		t->c_lflag &= TTYSUP_LFLAG;
1387		t->c_cflag &= TTYSUP_CFLAG;
1388
1389		/* Set terminal flags through tcsetattr(). */
1390		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
1391			error = tty_drain(tp);
1392			if (error)
1393				return (error);
1394			if (cmd == TIOCSETAF)
1395				tty_flush(tp, FREAD);
1396		}
1397
1398		/*
1399		 * Only call param() when the flags really change.
1400		 */
1401		if ((t->c_cflag & CIGNORE) == 0 &&
1402		    (tp->t_termios.c_cflag != t->c_cflag ||
1403		    tp->t_termios.c_ispeed != t->c_ispeed ||
1404		    tp->t_termios.c_ospeed != t->c_ospeed)) {
1405			error = ttydevsw_param(tp, t);
1406			if (error)
1407				return (error);
1408
1409			/* XXX: CLOCAL? */
1410
1411			tp->t_termios.c_cflag = t->c_cflag & ~CIGNORE;
1412			tp->t_termios.c_ispeed = t->c_ispeed;
1413			tp->t_termios.c_ospeed = t->c_ospeed;
1414
1415			/* Baud rate has changed - update watermarks. */
1416			tty_watermarks(tp);
1417		}
1418
1419		/* Copy new non-device driver parameters. */
1420		tp->t_termios.c_iflag = t->c_iflag;
1421		tp->t_termios.c_oflag = t->c_oflag;
1422		tp->t_termios.c_lflag = t->c_lflag;
1423		memcpy(&tp->t_termios.c_cc, t->c_cc, sizeof t->c_cc);
1424
1425		ttydisc_optimize(tp);
1426
1427		if ((t->c_lflag & ICANON) == 0) {
1428			/*
1429			 * When in non-canonical mode, wake up all
1430			 * readers. Canonicalize any partial input. VMIN
1431			 * and VTIME could also be adjusted.
1432			 */
1433			ttyinq_canonicalize(&tp->t_inq);
1434			tty_wakeup(tp, FREAD);
1435		}
1436
1437		/*
1438		 * For packet mode: notify the PTY consumer that VSTOP
1439		 * and VSTART may have been changed.
1440		 */
1441		if (tp->t_termios.c_iflag & IXON &&
1442		    tp->t_termios.c_cc[VSTOP] == CTRL('S') &&
1443		    tp->t_termios.c_cc[VSTART] == CTRL('Q'))
1444			ttydevsw_pktnotify(tp, TIOCPKT_DOSTOP);
1445		else
1446			ttydevsw_pktnotify(tp, TIOCPKT_NOSTOP);
1447		return (0);
1448	}
1449	case TIOCGETD:
1450		/* For compatibility - we only support TTYDISC. */
1451		*(int *)data = TTYDISC;
1452		return (0);
1453	case TIOCGPGRP:
1454		if (!tty_is_ctty(tp, td->td_proc))
1455			return (ENOTTY);
1456
1457		if (tp->t_pgrp != NULL)
1458			*(int *)data = tp->t_pgrp->pg_id;
1459		else
1460			*(int *)data = NO_PID;
1461		return (0);
1462	case TIOCGSID:
1463		if (!tty_is_ctty(tp, td->td_proc))
1464			return (ENOTTY);
1465
1466		MPASS(tp->t_session);
1467		*(int *)data = tp->t_session->s_sid;
1468		return (0);
1469	case TIOCSCTTY: {
1470		struct proc *p = td->td_proc;
1471
1472		/* XXX: This looks awful. */
1473		tty_unlock(tp);
1474		sx_xlock(&proctree_lock);
1475		tty_lock(tp);
1476
1477		if (!SESS_LEADER(p)) {
1478			/* Only the session leader may do this. */
1479			sx_xunlock(&proctree_lock);
1480			return (EPERM);
1481		}
1482
1483		if (tp->t_session != NULL && tp->t_session == p->p_session) {
1484			/* This is already our controlling TTY. */
1485			sx_xunlock(&proctree_lock);
1486			return (0);
1487		}
1488
1489		if (p->p_session->s_ttyp != NULL ||
1490		    (tp->t_session != NULL && tp->t_session->s_ttyvp != NULL &&
1491		    tp->t_session->s_ttyvp->v_type != VBAD)) {
1492			/*
1493			 * There is already a relation between a TTY and
1494			 * a session, or the caller is not the session
1495			 * leader.
1496			 *
1497			 * Allow the TTY to be stolen when the vnode is
1498			 * invalid, but the reference to the TTY is
1499			 * still active.  This allows immediate reuse of
1500			 * TTYs of which the session leader has been
1501			 * killed or the TTY revoked.
1502			 */
1503			sx_xunlock(&proctree_lock);
1504			return (EPERM);
1505		}
1506
1507		/* Connect the session to the TTY. */
1508		tp->t_session = p->p_session;
1509		tp->t_session->s_ttyp = tp;
1510		tp->t_sessioncnt++;
1511		sx_xunlock(&proctree_lock);
1512
1513		/* Assign foreground process group. */
1514		tp->t_pgrp = p->p_pgrp;
1515		PROC_LOCK(p);
1516		p->p_flag |= P_CONTROLT;
1517		PROC_UNLOCK(p);
1518
1519		return (0);
1520	}
1521	case TIOCSPGRP: {
1522		struct pgrp *pg;
1523
1524		/*
1525		 * XXX: Temporarily unlock the TTY to locate the process
1526		 * group. This code would be lot nicer if we would ever
1527		 * decompose proctree_lock.
1528		 */
1529		tty_unlock(tp);
1530		sx_slock(&proctree_lock);
1531		pg = pgfind(*(int *)data);
1532		if (pg != NULL)
1533			PGRP_UNLOCK(pg);
1534		if (pg == NULL || pg->pg_session != td->td_proc->p_session) {
1535			sx_sunlock(&proctree_lock);
1536			tty_lock(tp);
1537			return (EPERM);
1538		}
1539		tty_lock(tp);
1540
1541		/*
1542		 * Determine if this TTY is the controlling TTY after
1543		 * relocking the TTY.
1544		 */
1545		if (!tty_is_ctty(tp, td->td_proc)) {
1546			sx_sunlock(&proctree_lock);
1547			return (ENOTTY);
1548		}
1549		tp->t_pgrp = pg;
1550		sx_sunlock(&proctree_lock);
1551
1552		/* Wake up the background process groups. */
1553		cv_broadcast(&tp->t_bgwait);
1554		return (0);
1555	}
1556	case TIOCFLUSH: {
1557		int flags = *(int *)data;
1558
1559		if (flags == 0)
1560			flags = (FREAD|FWRITE);
1561		else
1562			flags &= (FREAD|FWRITE);
1563		tty_flush(tp, flags);
1564		return (0);
1565	}
1566	case TIOCDRAIN:
1567		/* Drain TTY output. */
1568		return tty_drain(tp);
1569	case TIOCCONS:
1570		/* Set terminal as console TTY. */
1571		if (*(int *)data) {
1572			error = priv_check(td, PRIV_TTY_CONSOLE);
1573			if (error)
1574				return (error);
1575
1576			/*
1577			 * XXX: constty should really need to be locked!
1578			 * XXX: allow disconnected constty's to be stolen!
1579			 */
1580
1581			if (constty == tp)
1582				return (0);
1583			if (constty != NULL)
1584				return (EBUSY);
1585
1586			tty_unlock(tp);
1587			constty_set(tp);
1588			tty_lock(tp);
1589		} else if (constty == tp) {
1590			constty_clear();
1591		}
1592		return (0);
1593	case TIOCGWINSZ:
1594		/* Obtain window size. */
1595		*(struct winsize*)data = tp->t_winsize;
1596		return (0);
1597	case TIOCSWINSZ:
1598		/* Set window size. */
1599		if (bcmp(&tp->t_winsize, data, sizeof(struct winsize)) == 0)
1600			return (0);
1601		tp->t_winsize = *(struct winsize*)data;
1602		tty_signal_pgrp(tp, SIGWINCH);
1603		return (0);
1604	case TIOCEXCL:
1605		tp->t_flags |= TF_EXCLUDE;
1606		return (0);
1607	case TIOCNXCL:
1608		tp->t_flags &= ~TF_EXCLUDE;
1609		return (0);
1610	case TIOCOUTQ:
1611		*(unsigned int *)data = ttyoutq_bytesused(&tp->t_outq);
1612		return (0);
1613	case TIOCSTOP:
1614		tp->t_flags |= TF_STOPPED;
1615		ttydevsw_pktnotify(tp, TIOCPKT_STOP);
1616		return (0);
1617	case TIOCSTART:
1618		tp->t_flags &= ~TF_STOPPED;
1619		ttydevsw_outwakeup(tp);
1620		ttydevsw_pktnotify(tp, TIOCPKT_START);
1621		return (0);
1622	case TIOCSTAT:
1623		tty_info(tp);
1624		return (0);
1625	}
1626
1627#ifdef COMPAT_43TTY
1628	return tty_ioctl_compat(tp, cmd, data, td);
1629#else /* !COMPAT_43TTY */
1630	return (ENOIOCTL);
1631#endif /* COMPAT_43TTY */
1632}
1633
1634int
1635tty_ioctl(struct tty *tp, u_long cmd, void *data, struct thread *td)
1636{
1637	int error;
1638
1639	tty_lock_assert(tp, MA_OWNED);
1640
1641	if (tty_gone(tp))
1642		return (ENXIO);
1643
1644	error = ttydevsw_ioctl(tp, cmd, data, td);
1645	if (error == ENOIOCTL)
1646		error = tty_generic_ioctl(tp, cmd, data, td);
1647
1648	return (error);
1649}
1650
1651dev_t
1652tty_udev(struct tty *tp)
1653{
1654	if (tp->t_dev)
1655		return dev2udev(tp->t_dev);
1656	else
1657		return NODEV;
1658}
1659
1660int
1661tty_checkoutq(struct tty *tp)
1662{
1663
1664	/* 256 bytes should be enough to print a log message. */
1665	return (ttyoutq_bytesleft(&tp->t_outq) >= 256);
1666}
1667
1668void
1669tty_hiwat_in_block(struct tty *tp)
1670{
1671
1672	if ((tp->t_flags & TF_HIWAT_IN) == 0 &&
1673	    tp->t_termios.c_iflag & IXOFF &&
1674	    tp->t_termios.c_cc[VSTOP] != _POSIX_VDISABLE) {
1675		/*
1676		 * Input flow control. Only enter the high watermark when we
1677		 * can successfully store the VSTOP character.
1678		 */
1679		if (ttyoutq_write_nofrag(&tp->t_outq,
1680		    &tp->t_termios.c_cc[VSTOP], 1) == 0)
1681			tp->t_flags |= TF_HIWAT_IN;
1682	} else {
1683		/* No input flow control. */
1684		tp->t_flags |= TF_HIWAT_IN;
1685	}
1686}
1687
1688void
1689tty_hiwat_in_unblock(struct tty *tp)
1690{
1691
1692	if (tp->t_flags & TF_HIWAT_IN &&
1693	    tp->t_termios.c_iflag & IXOFF &&
1694	    tp->t_termios.c_cc[VSTART] != _POSIX_VDISABLE) {
1695		/*
1696		 * Input flow control. Only leave the high watermark when we
1697		 * can successfully store the VSTART character.
1698		 */
1699		if (ttyoutq_write_nofrag(&tp->t_outq,
1700		    &tp->t_termios.c_cc[VSTART], 1) == 0)
1701			tp->t_flags &= ~TF_HIWAT_IN;
1702	} else {
1703		/* No input flow control. */
1704		tp->t_flags &= ~TF_HIWAT_IN;
1705	}
1706
1707	if (!tty_gone(tp))
1708		ttydevsw_inwakeup(tp);
1709}
1710
1711/*
1712 * TTY hooks interface.
1713 */
1714
1715static int
1716ttyhook_defrint(struct tty *tp, char c, int flags)
1717{
1718
1719	if (ttyhook_rint_bypass(tp, &c, 1) != 1)
1720		return (-1);
1721
1722	return (0);
1723}
1724
1725int
1726ttyhook_register(struct tty **rtp, struct proc *p, int fd,
1727    struct ttyhook *th, void *softc)
1728{
1729	struct tty *tp;
1730	struct file *fp;
1731	struct cdev *dev;
1732	struct cdevsw *cdp;
1733	struct filedesc *fdp;
1734	int error;
1735
1736	/* Validate the file descriptor. */
1737	if ((fdp = p->p_fd) == NULL)
1738		return (EBADF);
1739
1740	fp = fget_unlocked(fdp, fd);
1741	if (fp == NULL)
1742		return (EBADF);
1743	if (fp->f_ops == &badfileops) {
1744		error = EBADF;
1745		goto done1;
1746	}
1747
1748	/*
1749	 * Make sure the vnode is bound to a character device.
1750	 * Unlocked check for the vnode type is ok there, because we
1751	 * only shall prevent calling devvn_refthread on the file that
1752	 * never has been opened over a character device.
1753	 */
1754	if (fp->f_type != DTYPE_VNODE || fp->f_vnode->v_type != VCHR) {
1755		error = EINVAL;
1756		goto done1;
1757	}
1758
1759	/* Make sure it is a TTY. */
1760	cdp = devvn_refthread(fp->f_vnode, &dev);
1761	if (cdp == NULL) {
1762		error = ENXIO;
1763		goto done1;
1764	}
1765	if (dev != fp->f_data) {
1766		error = ENXIO;
1767		goto done2;
1768	}
1769	if (cdp != &ttydev_cdevsw) {
1770		error = ENOTTY;
1771		goto done2;
1772	}
1773	tp = dev->si_drv1;
1774
1775	/* Try to attach the hook to the TTY. */
1776	error = EBUSY;
1777	tty_lock(tp);
1778	MPASS((tp->t_hook == NULL) == ((tp->t_flags & TF_HOOK) == 0));
1779	if (tp->t_flags & TF_HOOK)
1780		goto done3;
1781
1782	tp->t_flags |= TF_HOOK;
1783	tp->t_hook = th;
1784	tp->t_hooksoftc = softc;
1785	*rtp = tp;
1786	error = 0;
1787
1788	/* Maybe we can switch into bypass mode now. */
1789	ttydisc_optimize(tp);
1790
1791	/* Silently convert rint() calls to rint_bypass() when possible. */
1792	if (!ttyhook_hashook(tp, rint) && ttyhook_hashook(tp, rint_bypass))
1793		th->th_rint = ttyhook_defrint;
1794
1795done3:	tty_unlock(tp);
1796done2:	dev_relthread(dev);
1797done1:	fdrop(fp, curthread);
1798	return (error);
1799}
1800
1801void
1802ttyhook_unregister(struct tty *tp)
1803{
1804
1805	tty_lock_assert(tp, MA_OWNED);
1806	MPASS(tp->t_flags & TF_HOOK);
1807
1808	/* Disconnect the hook. */
1809	tp->t_flags &= ~TF_HOOK;
1810	tp->t_hook = NULL;
1811
1812	/* Maybe we need to leave bypass mode. */
1813	ttydisc_optimize(tp);
1814
1815	/* Maybe deallocate the TTY as well. */
1816	tty_rel_free(tp);
1817}
1818
1819/*
1820 * /dev/console handling.
1821 */
1822
1823static int
1824ttyconsdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
1825{
1826	struct tty *tp;
1827
1828	/* System has no console device. */
1829	if (dev_console_filename == NULL)
1830		return (ENXIO);
1831
1832	/* Look up corresponding TTY by device name. */
1833	sx_slock(&tty_list_sx);
1834	TAILQ_FOREACH(tp, &tty_list, t_list) {
1835		if (strcmp(dev_console_filename, tty_devname(tp)) == 0) {
1836			dev_console->si_drv1 = tp;
1837			break;
1838		}
1839	}
1840	sx_sunlock(&tty_list_sx);
1841
1842	/* System console has no TTY associated. */
1843	if (dev_console->si_drv1 == NULL)
1844		return (ENXIO);
1845
1846	return (ttydev_open(dev, oflags, devtype, td));
1847}
1848
1849static int
1850ttyconsdev_write(struct cdev *dev, struct uio *uio, int ioflag)
1851{
1852
1853	log_console(uio);
1854
1855	return (ttydev_write(dev, uio, ioflag));
1856}
1857
1858/*
1859 * /dev/console is a little different than normal TTY's.  When opened,
1860 * it determines which TTY to use.  When data gets written to it, it
1861 * will be logged in the kernel message buffer.
1862 */
1863static struct cdevsw ttyconsdev_cdevsw = {
1864	.d_version	= D_VERSION,
1865	.d_open		= ttyconsdev_open,
1866	.d_close	= ttydev_close,
1867	.d_read		= ttydev_read,
1868	.d_write	= ttyconsdev_write,
1869	.d_ioctl	= ttydev_ioctl,
1870	.d_kqfilter	= ttydev_kqfilter,
1871	.d_poll		= ttydev_poll,
1872	.d_mmap		= ttydev_mmap,
1873	.d_name		= "ttyconsdev",
1874	.d_flags	= D_TTY,
1875};
1876
1877static void
1878ttyconsdev_init(void *unused)
1879{
1880
1881	dev_console = make_dev(&ttyconsdev_cdevsw, 0, UID_ROOT, GID_WHEEL,
1882	    0600, "console");
1883}
1884
1885SYSINIT(tty, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyconsdev_init, NULL);
1886
1887void
1888ttyconsdev_select(const char *name)
1889{
1890
1891	dev_console_filename = name;
1892}
1893
1894/*
1895 * Debugging routines.
1896 */
1897
1898#include "opt_ddb.h"
1899#ifdef DDB
1900#include <ddb/ddb.h>
1901#include <ddb/db_sym.h>
1902
1903static struct {
1904	int flag;
1905	char val;
1906} ttystates[] = {
1907#if 0
1908	{ TF_NOPREFIX,		'N' },
1909#endif
1910	{ TF_INITLOCK,		'I' },
1911	{ TF_CALLOUT,		'C' },
1912
1913	/* Keep these together -> 'Oi' and 'Oo'. */
1914	{ TF_OPENED,		'O' },
1915	{ TF_OPENED_IN,		'i' },
1916	{ TF_OPENED_OUT,	'o' },
1917	{ TF_OPENED_CONS,	'c' },
1918
1919	{ TF_GONE,		'G' },
1920	{ TF_OPENCLOSE,		'B' },
1921	{ TF_ASYNC,		'Y' },
1922	{ TF_LITERAL,		'L' },
1923
1924	/* Keep these together -> 'Hi' and 'Ho'. */
1925	{ TF_HIWAT,		'H' },
1926	{ TF_HIWAT_IN,		'i' },
1927	{ TF_HIWAT_OUT,		'o' },
1928
1929	{ TF_STOPPED,		'S' },
1930	{ TF_EXCLUDE,		'X' },
1931	{ TF_BYPASS,		'l' },
1932	{ TF_ZOMBIE,		'Z' },
1933	{ TF_HOOK,		's' },
1934
1935	/* Keep these together -> 'bi' and 'bo'. */
1936	{ TF_BUSY,		'b' },
1937	{ TF_BUSY_IN,		'i' },
1938	{ TF_BUSY_OUT,		'o' },
1939
1940	{ 0,			'\0'},
1941};
1942
1943#define	TTY_FLAG_BITS \
1944	"\20\1NOPREFIX\2INITLOCK\3CALLOUT\4OPENED_IN\5OPENED_OUT\6GONE" \
1945	"\7OPENCLOSE\10ASYNC\11LITERAL\12HIWAT_IN\13HIWAT_OUT\14STOPPED" \
1946	"\15EXCLUDE\16BYPASS\17ZOMBIE\20HOOK"
1947
1948#define DB_PRINTSYM(name, addr) \
1949	db_printf("%s  " #name ": ", sep); \
1950	db_printsym((db_addr_t) addr, DB_STGY_ANY); \
1951	db_printf("\n");
1952
1953static void
1954_db_show_devsw(const char *sep, const struct ttydevsw *tsw)
1955{
1956	db_printf("%sdevsw: ", sep);
1957	db_printsym((db_addr_t)tsw, DB_STGY_ANY);
1958	db_printf(" (%p)\n", tsw);
1959	DB_PRINTSYM(open, tsw->tsw_open);
1960	DB_PRINTSYM(close, tsw->tsw_close);
1961	DB_PRINTSYM(outwakeup, tsw->tsw_outwakeup);
1962	DB_PRINTSYM(inwakeup, tsw->tsw_inwakeup);
1963	DB_PRINTSYM(ioctl, tsw->tsw_ioctl);
1964	DB_PRINTSYM(param, tsw->tsw_param);
1965	DB_PRINTSYM(modem, tsw->tsw_modem);
1966	DB_PRINTSYM(mmap, tsw->tsw_mmap);
1967	DB_PRINTSYM(pktnotify, tsw->tsw_pktnotify);
1968	DB_PRINTSYM(free, tsw->tsw_free);
1969}
1970static void
1971_db_show_hooks(const char *sep, const struct ttyhook *th)
1972{
1973	db_printf("%shook: ", sep);
1974	db_printsym((db_addr_t)th, DB_STGY_ANY);
1975	db_printf(" (%p)\n", th);
1976	if (th == NULL)
1977		return;
1978	DB_PRINTSYM(rint, th->th_rint);
1979	DB_PRINTSYM(rint_bypass, th->th_rint_bypass);
1980	DB_PRINTSYM(rint_done, th->th_rint_done);
1981	DB_PRINTSYM(rint_poll, th->th_rint_poll);
1982	DB_PRINTSYM(getc_inject, th->th_getc_inject);
1983	DB_PRINTSYM(getc_capture, th->th_getc_capture);
1984	DB_PRINTSYM(getc_poll, th->th_getc_poll);
1985	DB_PRINTSYM(close, th->th_close);
1986}
1987
1988static void
1989_db_show_termios(const char *name, const struct termios *t)
1990{
1991
1992	db_printf("%s: iflag 0x%x oflag 0x%x cflag 0x%x "
1993	    "lflag 0x%x ispeed %u ospeed %u\n", name,
1994	    t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag,
1995	    t->c_ispeed, t->c_ospeed);
1996}
1997
1998/* DDB command to show TTY statistics. */
1999DB_SHOW_COMMAND(tty, db_show_tty)
2000{
2001	struct tty *tp;
2002
2003	if (!have_addr) {
2004		db_printf("usage: show tty <addr>\n");
2005		return;
2006	}
2007	tp = (struct tty *)addr;
2008
2009	db_printf("0x%p: %s\n", tp, tty_devname(tp));
2010	db_printf("\tmtx: %p\n", tp->t_mtx);
2011	db_printf("\tflags: %b\n", tp->t_flags, TTY_FLAG_BITS);
2012	db_printf("\trevokecnt: %u\n", tp->t_revokecnt);
2013
2014	/* Buffering mechanisms. */
2015	db_printf("\tinq: %p begin %u linestart %u reprint %u end %u "
2016	    "nblocks %u quota %u\n", &tp->t_inq, tp->t_inq.ti_begin,
2017	    tp->t_inq.ti_linestart, tp->t_inq.ti_reprint, tp->t_inq.ti_end,
2018	    tp->t_inq.ti_nblocks, tp->t_inq.ti_quota);
2019	db_printf("\toutq: %p begin %u end %u nblocks %u quota %u\n",
2020	    &tp->t_outq, tp->t_outq.to_begin, tp->t_outq.to_end,
2021	    tp->t_outq.to_nblocks, tp->t_outq.to_quota);
2022	db_printf("\tinlow: %zu\n", tp->t_inlow);
2023	db_printf("\toutlow: %zu\n", tp->t_outlow);
2024	_db_show_termios("\ttermios", &tp->t_termios);
2025	db_printf("\twinsize: row %u col %u xpixel %u ypixel %u\n",
2026	    tp->t_winsize.ws_row, tp->t_winsize.ws_col,
2027	    tp->t_winsize.ws_xpixel, tp->t_winsize.ws_ypixel);
2028	db_printf("\tcolumn: %u\n", tp->t_column);
2029	db_printf("\twritepos: %u\n", tp->t_writepos);
2030	db_printf("\tcompatflags: 0x%x\n", tp->t_compatflags);
2031
2032	/* Init/lock-state devices. */
2033	_db_show_termios("\ttermios_init_in", &tp->t_termios_init_in);
2034	_db_show_termios("\ttermios_init_out", &tp->t_termios_init_out);
2035	_db_show_termios("\ttermios_lock_in", &tp->t_termios_lock_in);
2036	_db_show_termios("\ttermios_lock_out", &tp->t_termios_lock_out);
2037
2038	/* Hooks */
2039	_db_show_devsw("\t", tp->t_devsw);
2040	_db_show_hooks("\t", tp->t_hook);
2041
2042	/* Process info. */
2043	db_printf("\tpgrp: %p gid %d jobc %d\n", tp->t_pgrp,
2044	    tp->t_pgrp ? tp->t_pgrp->pg_id : 0,
2045	    tp->t_pgrp ? tp->t_pgrp->pg_jobc : 0);
2046	db_printf("\tsession: %p", tp->t_session);
2047	if (tp->t_session != NULL)
2048	    db_printf(" count %u leader %p tty %p sid %d login %s",
2049		tp->t_session->s_count, tp->t_session->s_leader,
2050		tp->t_session->s_ttyp, tp->t_session->s_sid,
2051		tp->t_session->s_login);
2052	db_printf("\n");
2053	db_printf("\tsessioncnt: %u\n", tp->t_sessioncnt);
2054	db_printf("\tdevswsoftc: %p\n", tp->t_devswsoftc);
2055	db_printf("\thooksoftc: %p\n", tp->t_hooksoftc);
2056	db_printf("\tdev: %p\n", tp->t_dev);
2057}
2058
2059/* DDB command to list TTYs. */
2060DB_SHOW_ALL_COMMAND(ttys, db_show_all_ttys)
2061{
2062	struct tty *tp;
2063	size_t isiz, osiz;
2064	int i, j;
2065
2066	/* Make the output look like `pstat -t'. */
2067	db_printf("PTR        ");
2068#if defined(__LP64__)
2069	db_printf("        ");
2070#endif
2071	db_printf("      LINE   INQ  CAN  LIN  LOW  OUTQ  USE  LOW   "
2072	    "COL  SESS  PGID STATE\n");
2073
2074	TAILQ_FOREACH(tp, &tty_list, t_list) {
2075		isiz = tp->t_inq.ti_nblocks * TTYINQ_DATASIZE;
2076		osiz = tp->t_outq.to_nblocks * TTYOUTQ_DATASIZE;
2077
2078		db_printf("%p %10s %5zu %4u %4u %4zu %5zu %4u %4zu %5u %5d %5d ",
2079		    tp,
2080		    tty_devname(tp),
2081		    isiz,
2082		    tp->t_inq.ti_linestart - tp->t_inq.ti_begin,
2083		    tp->t_inq.ti_end - tp->t_inq.ti_linestart,
2084		    isiz - tp->t_inlow,
2085		    osiz,
2086		    tp->t_outq.to_end - tp->t_outq.to_begin,
2087		    osiz - tp->t_outlow,
2088		    MIN(tp->t_column, 99999),
2089		    tp->t_session ? tp->t_session->s_sid : 0,
2090		    tp->t_pgrp ? tp->t_pgrp->pg_id : 0);
2091
2092		/* Flag bits. */
2093		for (i = j = 0; ttystates[i].flag; i++)
2094			if (tp->t_flags & ttystates[i].flag) {
2095				db_printf("%c", ttystates[i].val);
2096				j++;
2097			}
2098		if (j == 0)
2099			db_printf("-");
2100		db_printf("\n");
2101	}
2102}
2103#endif /* DDB */
2104