tty.c revision 236730
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> 31556Srgrimes * All rights reserved. 496196Sdes * 596196Sdes * Portions of this software were developed under sponsorship from Snow 61556Srgrimes * B.V., the Netherlands. 796196Sdes * 896196Sdes * Redistribution and use in source and binary forms, with or without 996196Sdes * modification, are permitted provided that the following conditions 1096196Sdes * are met: 1196196Sdes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 171556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271556Srgrimes * SUCH DAMAGE. 281556Srgrimes */ 291556Srgrimes 301556Srgrimes#include <sys/cdefs.h> 311556Srgrimes__FBSDID("$FreeBSD: head/sys/kern/tty.c 236730 2012-06-07 23:08:18Z pjd $"); 321556Srgrimes 331556Srgrimes#include "opt_capsicum.h" 341556Srgrimes#include "opt_compat.h" 351556Srgrimes 361556Srgrimes#include <sys/param.h> 371556Srgrimes#include <sys/capability.h> 381556Srgrimes#include <sys/conf.h> 391556Srgrimes#include <sys/cons.h> 401556Srgrimes#include <sys/fcntl.h> 411556Srgrimes#include <sys/file.h> 4220420Ssteve#include <sys/filedesc.h> 431556Srgrimes#include <sys/filio.h> 441556Srgrimes#ifdef COMPAT_43TTY 451556Srgrimes#include <sys/ioctl_compat.h> 461556Srgrimes#endif /* COMPAT_43TTY */ 471556Srgrimes#include <sys/kernel.h> 4836149Scharnier#include <sys/limits.h> 4936149Scharnier#include <sys/malloc.h> 5036149Scharnier#include <sys/mount.h> 5136149Scharnier#include <sys/poll.h> 5250471Speter#include <sys/priv.h> 531556Srgrimes#include <sys/proc.h> 541556Srgrimes#include <sys/serial.h> 551556Srgrimes#include <sys/signal.h> 561556Srgrimes#include <sys/stat.h> 571556Srgrimes#include <sys/sx.h> 581556Srgrimes#include <sys/sysctl.h> 591556Srgrimes#include <sys/systm.h> 601556Srgrimes#include <sys/tty.h> 611556Srgrimes#include <sys/ttycom.h> 621556Srgrimes#define TTYDEFCHARS 631556Srgrimes#include <sys/ttydefaults.h> 641556Srgrimes#undef TTYDEFCHARS 651556Srgrimes#include <sys/ucred.h> 661556Srgrimes#include <sys/vnode.h> 671556Srgrimes 6877462Simp#include <machine/stdarg.h> 6977462Simp 701556Srgrimesstatic MALLOC_DEFINE(M_TTY, "tty", "tty device"); 7196196Sdes 721556Srgrimesstatic void tty_rel_free(struct tty *tp); 731556Srgrimes 741556Srgrimesstatic TAILQ_HEAD(, tty) tty_list = TAILQ_HEAD_INITIALIZER(tty_list); 751556Srgrimesstatic struct sx tty_list_sx; 761556SrgrimesSX_SYSINIT(tty_list, &tty_list_sx, "tty list"); 771556Srgrimesstatic unsigned int tty_list_count = 0; 781556Srgrimes 791556Srgrimes/* Character device of /dev/console. */ 801556Srgrimesstatic struct cdev *dev_console; 811556Srgrimesstatic const char *dev_console_filename; 821556Srgrimes 8357454Smarkm/* 8429914Smarkm * Flags that are supported and stored by this implementation. 8551434Smarkm */ 861556Srgrimes#define TTYSUP_IFLAG (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|\ 871556Srgrimes INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY|IMAXBEL) 881556Srgrimes#define TTYSUP_OFLAG (OPOST|ONLCR|TAB3|ONOEOT|OCRNL|ONOCR|ONLRET) 891556Srgrimes#define TTYSUP_LFLAG (ECHOKE|ECHOE|ECHOK|ECHO|ECHONL|ECHOPRT|\ 9096196Sdes ECHOCTL|ISIG|ICANON|ALTWERASE|IEXTEN|TOSTOP|\ 911556Srgrimes FLUSHO|NOKERNINFO|NOFLSH) 921556Srgrimes#define TTYSUP_CFLAG (CIGNORE|CSIZE|CSTOPB|CREAD|PARENB|PARODD|\ 931556Srgrimes HUPCL|CLOCAL|CCTS_OFLOW|CRTS_IFLOW|CDTR_IFLOW|\ 941556Srgrimes CDSR_OFLOW|CCAR_OFLOW) 951556Srgrimes 961556Srgrimes#define TTY_CALLOUT(tp,d) (dev2unit(d) & TTYUNIT_CALLOUT) 971556Srgrimes 981556Srgrimes/* 991556Srgrimes * Set TTY buffer sizes. 1001556Srgrimes */ 1011556Srgrimes 1021556Srgrimes#define TTYBUF_MAX 65536 1031556Srgrimes 1041556Srgrimesstatic void 1051556Srgrimestty_watermarks(struct tty *tp) 1061556Srgrimes{ 1071556Srgrimes size_t bs = 0; 1081556Srgrimes 10934898Smarkm /* Provide an input buffer for 0.2 seconds of data. */ 11034898Smarkm if (tp->t_termios.c_cflag & CREAD) 11134898Smarkm bs = MIN(tp->t_termios.c_ispeed / 5, TTYBUF_MAX); 1121556Srgrimes ttyinq_setsize(&tp->t_inq, tp, bs); 1131556Srgrimes 1141556Srgrimes /* Set low watermark at 10% (when 90% is available). */ 1151556Srgrimes tp->t_inlow = (ttyinq_getallocatedsize(&tp->t_inq) * 9) / 10; 11690110Simp 11790110Simp /* Provide an ouput buffer for 0.2 seconds of data. */ 1181556Srgrimes bs = MIN(tp->t_termios.c_ospeed / 5, TTYBUF_MAX); 11990110Simp ttyoutq_setsize(&tp->t_outq, tp, bs); 12090110Simp 12190110Simp /* Set low watermark at 10% (when 90% is available). */ 12290110Simp tp->t_outlow = (ttyoutq_getallocatedsize(&tp->t_outq) * 9) / 10; 12390110Simp} 12490110Simp 12590110Simpstatic int 12690110Simptty_drain(struct tty *tp) 1271556Srgrimes{ 1281556Srgrimes int error; 12990110Simp 1301556Srgrimes if (ttyhook_hashook(tp, getc_inject)) 1311556Srgrimes /* buffer is inaccessible */ 13248560Sbde return (0); 1331556Srgrimes 13440101Smarkm while (ttyoutq_bytesused(&tp->t_outq) > 0) { 13540101Smarkm ttydevsw_outwakeup(tp); 13640101Smarkm /* Could be handled synchronously. */ 1371556Srgrimes if (ttyoutq_bytesused(&tp->t_outq) == 0) 13834898Smarkm return (0); 13934898Smarkm 14034898Smarkm /* Wait for data to be drained. */ 14134898Smarkm error = tty_wait(tp, &tp->t_outwait); 14234898Smarkm if (error) 14334898Smarkm return (error); 14434898Smarkm } 14534898Smarkm 14634898Smarkm return (0); 14748560Sbde} 14834898Smarkm 14934898Smarkm/* 15034898Smarkm * Though ttydev_enter() and ttydev_leave() seem to be related, they 15134898Smarkm * don't have to be used together. ttydev_enter() is used by the cdev 15234898Smarkm * operations to prevent an actual operation from being processed when 15334898Smarkm * the TTY has been abandoned. ttydev_leave() is used by ttydev_open() 1541556Srgrimes * and ttydev_close() to determine whether per-TTY data should be 15524348Simp * deallocated. 1561556Srgrimes */ 1571556Srgrimes 1581556Srgrimesstatic __inline int 1591556Srgrimesttydev_enter(struct tty *tp) 1601556Srgrimes{ 1611556Srgrimes tty_lock(tp); 1621556Srgrimes 1631556Srgrimes if (tty_gone(tp) || !tty_opened(tp)) { 1641556Srgrimes /* Device is already gone. */ 16525612Sjoerg tty_unlock(tp); 16625612Sjoerg return (ENXIO); 1671556Srgrimes } 1681556Srgrimes 1691556Srgrimes return (0); 1701556Srgrimes} 1711556Srgrimes 1721556Srgrimesstatic void 1731556Srgrimesttydev_leave(struct tty *tp) 1741556Srgrimes{ 1751556Srgrimes tty_lock_assert(tp, MA_OWNED); 1761556Srgrimes 1771556Srgrimes if (tty_opened(tp) || tp->t_flags & TF_OPENCLOSE) { 1781556Srgrimes /* Device is still opened somewhere. */ 1791556Srgrimes tty_unlock(tp); 1801556Srgrimes return; 1811556Srgrimes } 1821556Srgrimes 1831556Srgrimes tp->t_flags |= TF_OPENCLOSE; 1841556Srgrimes 1851556Srgrimes /* Stop asynchronous I/O. */ 1861556Srgrimes funsetown(&tp->t_sigio); 1871556Srgrimes 1881556Srgrimes /* Remove console TTY. */ 1891556Srgrimes if (constty == tp) 1901556Srgrimes constty_clear(); 1911556Srgrimes 1921556Srgrimes /* Drain any output. */ 1931556Srgrimes MPASS((tp->t_flags & TF_STOPPED) == 0); 1941556Srgrimes if (!tty_gone(tp)) 1951556Srgrimes tty_drain(tp); 1961556Srgrimes 1971556Srgrimes ttydisc_close(tp); 1981556Srgrimes 1991556Srgrimes /* Destroy associated buffers already. */ 2001556Srgrimes ttyinq_free(&tp->t_inq); 20140101Smarkm tp->t_inlow = 0; 20240101Smarkm ttyoutq_free(&tp->t_outq); 20340101Smarkm tp->t_outlow = 0; 2041556Srgrimes 2051556Srgrimes knlist_clear(&tp->t_inpoll.si_note, 1); 2061556Srgrimes knlist_clear(&tp->t_outpoll.si_note, 1); 2071556Srgrimes 2081556Srgrimes if (!tty_gone(tp)) 2091556Srgrimes ttydevsw_close(tp); 2101556Srgrimes 2111556Srgrimes tp->t_flags &= ~TF_OPENCLOSE; 2121556Srgrimes cv_broadcast(&tp->t_dcdwait); 2131556Srgrimes tty_rel_free(tp); 2141556Srgrimes} 2151556Srgrimes 2161556Srgrimes/* 2171556Srgrimes * Operations that are exposed through the character device in /dev. 2181556Srgrimes */ 2191556Srgrimesstatic int 2201556Srgrimesttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 2211556Srgrimes{ 2221556Srgrimes struct tty *tp = dev->si_drv1; 2231556Srgrimes int error = 0; 2241556Srgrimes 2251556Srgrimes tty_lock(tp); 2261556Srgrimes if (tty_gone(tp)) { 2271556Srgrimes /* Device is already gone. */ 2281556Srgrimes tty_unlock(tp); 2291556Srgrimes return (ENXIO); 2301556Srgrimes } 2311556Srgrimes 2321556Srgrimes /* 2331556Srgrimes * Block when other processes are currently opening or closing 2341556Srgrimes * the TTY. 2351556Srgrimes */ 2361556Srgrimes while (tp->t_flags & TF_OPENCLOSE) { 2371556Srgrimes error = tty_wait(tp, &tp->t_dcdwait); 2381556Srgrimes if (error != 0) { 2391556Srgrimes tty_unlock(tp); 2401556Srgrimes return (error); 2411556Srgrimes } 2421556Srgrimes } 2431556Srgrimes tp->t_flags |= TF_OPENCLOSE; 2441556Srgrimes 2451556Srgrimes /* 2461556Srgrimes * Make sure the "tty" and "cua" device cannot be opened at the 2471556Srgrimes * same time. 2481556Srgrimes */ 2491556Srgrimes if (TTY_CALLOUT(tp, dev)) { 2501556Srgrimes if (tp->t_flags & TF_OPENED_IN) { 2511556Srgrimes error = EBUSY; 2521556Srgrimes goto done; 2531556Srgrimes } 2541556Srgrimes } else { 2551556Srgrimes if (tp->t_flags & TF_OPENED_OUT) { 2561556Srgrimes error = EBUSY; 2571556Srgrimes goto done; 2581556Srgrimes } 2591556Srgrimes } 2601556Srgrimes 2611556Srgrimes if (tp->t_flags & TF_EXCLUDE && priv_check(td, PRIV_TTY_EXCLUSIVE)) { 2621556Srgrimes error = EBUSY; 2631556Srgrimes goto done; 2641556Srgrimes } 2651556Srgrimes 2667165Sjoerg if (!tty_opened(tp)) { 2671556Srgrimes /* Set proper termios flags. */ 2681556Srgrimes if (TTY_CALLOUT(tp, dev)) 2691556Srgrimes tp->t_termios = tp->t_termios_init_out; 2701556Srgrimes else 2711556Srgrimes tp->t_termios = tp->t_termios_init_in; 2721556Srgrimes ttydevsw_param(tp, &tp->t_termios); 2731556Srgrimes /* Prevent modem control on callout devices and /dev/console. */ 2741556Srgrimes if (TTY_CALLOUT(tp, dev) || dev == dev_console) 2751556Srgrimes tp->t_termios.c_cflag |= CLOCAL; 2761556Srgrimes 27790110Simp ttydevsw_modem(tp, SER_DTR|SER_RTS, 0); 2781556Srgrimes 2791556Srgrimes error = ttydevsw_open(tp); 2801556Srgrimes if (error != 0) 2811556Srgrimes goto done; 2821556Srgrimes 2831556Srgrimes ttydisc_open(tp); 2841556Srgrimes tty_watermarks(tp); 2851556Srgrimes } 2867165Sjoerg 2871556Srgrimes /* Wait for Carrier Detect. */ 2881556Srgrimes if ((oflags & O_NONBLOCK) == 0 && 2891556Srgrimes (tp->t_termios.c_cflag & CLOCAL) == 0) { 2901556Srgrimes while ((ttydevsw_modem(tp, 0, 0) & SER_DCD) == 0) { 2911556Srgrimes error = tty_wait(tp, &tp->t_dcdwait); 2921556Srgrimes if (error != 0) 2931556Srgrimes goto done; 2941556Srgrimes } 2951556Srgrimes } 2961556Srgrimes 2971556Srgrimes if (dev == dev_console) 2981556Srgrimes tp->t_flags |= TF_OPENED_CONS; 2991556Srgrimes else if (TTY_CALLOUT(tp, dev)) 3001556Srgrimes tp->t_flags |= TF_OPENED_OUT; 3011556Srgrimes else 3021556Srgrimes tp->t_flags |= TF_OPENED_IN; 3031556Srgrimes 3041556Srgrimesdone: tp->t_flags &= ~TF_OPENCLOSE; 3051556Srgrimes cv_broadcast(&tp->t_dcdwait); 3061556Srgrimes ttydev_leave(tp); 3071556Srgrimes 3081556Srgrimes return (error); 3091556Srgrimes} 3101556Srgrimes 3111556Srgrimesstatic int 3121556Srgrimesttydev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 3131556Srgrimes{ 3141556Srgrimes struct tty *tp = dev->si_drv1; 3151556Srgrimes 31677491Spirzyk tty_lock(tp); 31777491Spirzyk 3181556Srgrimes /* 31977491Spirzyk * Don't actually close the device if it is being used as the 3201556Srgrimes * console. 3211556Srgrimes */ 3221556Srgrimes MPASS((tp->t_flags & TF_OPENED) != TF_OPENED); 3231556Srgrimes if (dev == dev_console) 3241556Srgrimes tp->t_flags &= ~TF_OPENED_CONS; 3251556Srgrimes else 3261556Srgrimes tp->t_flags &= ~(TF_OPENED_IN|TF_OPENED_OUT); 3271556Srgrimes 3281556Srgrimes if (tp->t_flags & TF_OPENED) { 3291556Srgrimes tty_unlock(tp); 3301556Srgrimes return (0); 3311556Srgrimes } 3321556Srgrimes 3331556Srgrimes /* 3341556Srgrimes * This can only be called once. The callin and the callout 3351556Srgrimes * devices cannot be opened at the same time. 3361556Srgrimes */ 3371556Srgrimes tp->t_flags &= ~(TF_EXCLUDE|TF_STOPPED); 3381556Srgrimes 3391556Srgrimes /* Properly wake up threads that are stuck - revoke(). */ 3401556Srgrimes tp->t_revokecnt++; 3411556Srgrimes tty_wakeup(tp, FREAD|FWRITE); 3421556Srgrimes cv_broadcast(&tp->t_bgwait); 3431556Srgrimes cv_broadcast(&tp->t_dcdwait); 3441556Srgrimes 3451556Srgrimes ttydev_leave(tp); 3461556Srgrimes 3471556Srgrimes return (0); 3481556Srgrimes} 3491556Srgrimes 3501556Srgrimesstatic __inline int 3511556Srgrimestty_is_ctty(struct tty *tp, struct proc *p) 3521556Srgrimes{ 3531556Srgrimes tty_lock_assert(tp, MA_OWNED); 3541556Srgrimes 3551556Srgrimes return (p->p_session == tp->t_session && p->p_flag & P_CONTROLT); 3561556Srgrimes} 3571556Srgrimes 3581556Srgrimesstatic int 3591556Srgrimestty_wait_background(struct tty *tp, struct thread *td, int sig) 3601556Srgrimes{ 3611556Srgrimes struct proc *p = td->td_proc; 3621556Srgrimes struct pgrp *pg; 3631556Srgrimes ksiginfo_t ksi; 3641556Srgrimes int error; 3651556Srgrimes 3661556Srgrimes MPASS(sig == SIGTTIN || sig == SIGTTOU); 36790110Simp tty_lock_assert(tp, MA_OWNED); 3681556Srgrimes 3691556Srgrimes for (;;) { 3701556Srgrimes PROC_LOCK(p); 3711556Srgrimes /* 3721556Srgrimes * The process should only sleep, when: 3731556Srgrimes * - This terminal is the controling terminal 3741556Srgrimes * - Its process group is not the foreground process 3751556Srgrimes * group 3761556Srgrimes * - The parent process isn't waiting for the child to 3771556Srgrimes * exit 3781556Srgrimes * - the signal to send to the process isn't masked 37931633Swosch */ 3801556Srgrimes if (!tty_is_ctty(tp, p) || p->p_pgrp == tp->t_pgrp) { 3811556Srgrimes /* Allow the action to happen. */ 3821556Srgrimes PROC_UNLOCK(p); 3831556Srgrimes return (0); 3841556Srgrimes } 3851556Srgrimes 3861556Srgrimes if (SIGISMEMBER(p->p_sigacts->ps_sigignore, sig) || 3871556Srgrimes SIGISMEMBER(td->td_sigmask, sig)) { 3881556Srgrimes /* Only allow them in write()/ioctl(). */ 3891556Srgrimes PROC_UNLOCK(p); 3901556Srgrimes return (sig == SIGTTOU ? 0 : EIO); 3911556Srgrimes } 3921556Srgrimes 3931556Srgrimes pg = p->p_pgrp; 3941556Srgrimes if (p->p_flag & P_PPWAIT || pg->pg_jobc == 0) { 3951556Srgrimes /* Don't allow the action to happen. */ 3961556Srgrimes PROC_UNLOCK(p); 39777491Spirzyk return (EIO); 39877491Spirzyk } 3991556Srgrimes PROC_UNLOCK(p); 40077491Spirzyk 4011556Srgrimes /* 4021556Srgrimes * Send the signal and sleep until we're the new 4031556Srgrimes * foreground process group. 4041556Srgrimes */ 4051556Srgrimes if (sig != 0) { 4068855Srgrimes ksiginfo_init(&ksi); 4071556Srgrimes ksi.ksi_code = SI_KERNEL; 4088855Srgrimes ksi.ksi_signo = sig; 4098855Srgrimes sig = 0; 4101556Srgrimes } 4111556Srgrimes PGRP_LOCK(pg); 4121556Srgrimes pgsignal(pg, ksi.ksi_signo, 1, &ksi); 4131556Srgrimes PGRP_UNLOCK(pg); 4141556Srgrimes 4151556Srgrimes error = tty_wait(tp, &tp->t_bgwait); 4161556Srgrimes if (error) 4171556Srgrimes return (error); 4181556Srgrimes } 4191556Srgrimes} 4201556Srgrimes 4211556Srgrimesstatic int 4221556Srgrimesttydev_read(struct cdev *dev, struct uio *uio, int ioflag) 4231556Srgrimes{ 4241556Srgrimes struct tty *tp = dev->si_drv1; 4251556Srgrimes int error; 4261556Srgrimes 4271556Srgrimes error = ttydev_enter(tp); 4281556Srgrimes if (error) 42990110Simp goto done; 4301556Srgrimes 4311556Srgrimes error = tty_wait_background(tp, curthread, SIGTTIN); 4321556Srgrimes if (error) { 4331556Srgrimes tty_unlock(tp); 4341556Srgrimes goto done; 4351556Srgrimes } 4361556Srgrimes 4371556Srgrimes error = ttydisc_read(tp, uio, ioflag); 4381556Srgrimes tty_unlock(tp); 43996196Sdes 4401556Srgrimes /* 4411556Srgrimes * The read() call should not throw an error when the device is 4421556Srgrimes * being destroyed. Silently convert it to an EOF. 4431556Srgrimes */ 4441556Srgrimesdone: if (error == ENXIO) 4451556Srgrimes error = 0; 4461556Srgrimes return (error); 4471556Srgrimes} 4481556Srgrimes 4491556Srgrimesstatic int 4501556Srgrimesttydev_write(struct cdev *dev, struct uio *uio, int ioflag) 4511556Srgrimes{ 4521556Srgrimes struct tty *tp = dev->si_drv1; 4531556Srgrimes int error; 4541556Srgrimes 4551556Srgrimes error = ttydev_enter(tp); 4561556Srgrimes if (error) 4571556Srgrimes return (error); 4581556Srgrimes 4591556Srgrimes if (tp->t_termios.c_lflag & TOSTOP) { 4601556Srgrimes error = tty_wait_background(tp, curthread, SIGTTOU); 4611556Srgrimes if (error) 4621556Srgrimes goto done; 4631556Srgrimes } 4641556Srgrimes 4651556Srgrimes if (ioflag & IO_NDELAY && tp->t_flags & TF_BUSY_OUT) { 4661556Srgrimes /* Allow non-blocking writes to bypass serialization. */ 4671556Srgrimes error = ttydisc_write(tp, uio, ioflag); 4681556Srgrimes } else { 46938018Sbde /* Serialize write() calls. */ 47038018Sbde while (tp->t_flags & TF_BUSY_OUT) { 4711556Srgrimes error = tty_wait(tp, &tp->t_outserwait); 4721556Srgrimes if (error) 4731556Srgrimes goto done; 4741556Srgrimes } 4751556Srgrimes 4761556Srgrimes tp->t_flags |= TF_BUSY_OUT; 4771556Srgrimes error = ttydisc_write(tp, uio, ioflag); 4781556Srgrimes tp->t_flags &= ~TF_BUSY_OUT; 4791556Srgrimes cv_signal(&tp->t_outserwait); 4801556Srgrimes } 4811556Srgrimes 4821556Srgrimesdone: tty_unlock(tp); 4831556Srgrimes return (error); 4841556Srgrimes} 4851556Srgrimes 4861556Srgrimesstatic int 4871556Srgrimesttydev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 4881556Srgrimes struct thread *td) 4891556Srgrimes{ 4901556Srgrimes struct tty *tp = dev->si_drv1; 4911556Srgrimes int error; 4921556Srgrimes 4931556Srgrimes error = ttydev_enter(tp); 4941556Srgrimes if (error) 4951556Srgrimes return (error); 4961556Srgrimes 4971556Srgrimes switch (cmd) { 4981556Srgrimes case TIOCCBRK: 4991556Srgrimes case TIOCCONS: 5001556Srgrimes case TIOCDRAIN: 5011556Srgrimes case TIOCEXCL: 5021556Srgrimes case TIOCFLUSH: 5031556Srgrimes case TIOCNXCL: 5041556Srgrimes case TIOCSBRK: 5051556Srgrimes case TIOCSCTTY: 5061556Srgrimes case TIOCSETA: 5071556Srgrimes case TIOCSETAF: 5081556Srgrimes case TIOCSETAW: 5091556Srgrimes case TIOCSPGRP: 5101556Srgrimes case TIOCSTART: 5111556Srgrimes case TIOCSTAT: 5121556Srgrimes case TIOCSTI: 5131556Srgrimes case TIOCSTOP: 5141556Srgrimes case TIOCSWINSZ: 51590110Simp#if 0 5161556Srgrimes case TIOCSDRAINWAIT: 5171556Srgrimes case TIOCSETD: 5181556Srgrimes#endif 51977462Simp#ifdef COMPAT_43TTY 5201556Srgrimes case TIOCLBIC: 5211556Srgrimes case TIOCLBIS: 5221556Srgrimes case TIOCLSET: 5231556Srgrimes case TIOCSETC: 5241556Srgrimes case OTIOCSETD: 5251556Srgrimes case TIOCSETN: 5261556Srgrimes case TIOCSETP: 5271556Srgrimes case TIOCSLTC: 5281556Srgrimes#endif /* COMPAT_43TTY */ 5291556Srgrimes /* 5301556Srgrimes * If the ioctl() causes the TTY to be modified, let it 5311556Srgrimes * wait in the background. 53238018Sbde */ 53338018Sbde error = tty_wait_background(tp, curthread, SIGTTOU); 5341556Srgrimes if (error) 5351556Srgrimes goto done; 5361556Srgrimes } 5371556Srgrimes 5381556Srgrimes if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 5391556Srgrimes struct termios *old = &tp->t_termios; 5401556Srgrimes struct termios *new = (struct termios *)data; 5411556Srgrimes struct termios *lock = TTY_CALLOUT(tp, dev) ? 5421556Srgrimes &tp->t_termios_lock_out : &tp->t_termios_lock_in; 5431556Srgrimes int cc; 5441556Srgrimes 5451556Srgrimes /* 5461556Srgrimes * Lock state devices. Just overwrite the values of the 5477165Sjoerg * commands that are currently in use. 5481556Srgrimes */ 5491556Srgrimes new->c_iflag = (old->c_iflag & lock->c_iflag) | 5501556Srgrimes (new->c_iflag & ~lock->c_iflag); 5511556Srgrimes new->c_oflag = (old->c_oflag & lock->c_oflag) | 55277462Simp (new->c_oflag & ~lock->c_oflag); 5531556Srgrimes new->c_cflag = (old->c_cflag & lock->c_cflag) | 5541556Srgrimes (new->c_cflag & ~lock->c_cflag); 5551556Srgrimes new->c_lflag = (old->c_lflag & lock->c_lflag) | 5561556Srgrimes (new->c_lflag & ~lock->c_lflag); 5571556Srgrimes for (cc = 0; cc < NCCS; ++cc) 5581556Srgrimes if (lock->c_cc[cc]) 5591556Srgrimes new->c_cc[cc] = old->c_cc[cc]; 5601556Srgrimes if (lock->c_ispeed) 5611556Srgrimes new->c_ispeed = old->c_ispeed; 5621556Srgrimes if (lock->c_ospeed) 5631556Srgrimes new->c_ospeed = old->c_ospeed; 5641556Srgrimes } 5651556Srgrimes 56690110Simp error = tty_ioctl(tp, cmd, data, fflag, td); 5671556Srgrimesdone: tty_unlock(tp); 5681556Srgrimes 5691556Srgrimes return (error); 5701556Srgrimes} 5711556Srgrimes 5721556Srgrimesstatic int 57346057Sdtttydev_poll(struct cdev *dev, int events, struct thread *td) 5741556Srgrimes{ 57546057Sdt struct tty *tp = dev->si_drv1; 5761556Srgrimes int error, revents = 0; 5771556Srgrimes 5781556Srgrimes error = ttydev_enter(tp); 5791556Srgrimes if (error) 5801556Srgrimes return ((events & (POLLIN|POLLRDNORM)) | POLLHUP); 5811556Srgrimes 5821556Srgrimes if (events & (POLLIN|POLLRDNORM)) { 5831556Srgrimes /* See if we can read something. */ 5841556Srgrimes if (ttydisc_read_poll(tp) > 0) 5851556Srgrimes revents |= events & (POLLIN|POLLRDNORM); 5861556Srgrimes } 5871556Srgrimes 5881556Srgrimes if (tp->t_flags & TF_ZOMBIE) { 5891556Srgrimes /* Hangup flag on zombie state. */ 5901556Srgrimes revents |= POLLHUP; 5911556Srgrimes } else if (events & (POLLOUT|POLLWRNORM)) { 5921556Srgrimes /* See if we can write something. */ 5931556Srgrimes if (ttydisc_write_poll(tp) > 0) 5941556Srgrimes revents |= events & (POLLOUT|POLLWRNORM); 5951556Srgrimes } 5961556Srgrimes 5971556Srgrimes if (revents == 0) { 5981556Srgrimes if (events & (POLLIN|POLLRDNORM)) 5991556Srgrimes selrecord(td, &tp->t_inpoll); 6001556Srgrimes if (events & (POLLOUT|POLLWRNORM)) 6011556Srgrimes selrecord(td, &tp->t_outpoll); 6021556Srgrimes } 6031556Srgrimes 6041556Srgrimes tty_unlock(tp); 6051556Srgrimes 6061556Srgrimes return (revents); 6071556Srgrimes} 6081556Srgrimes 6091556Srgrimesstatic int 6101556Srgrimesttydev_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 6111556Srgrimes int nprot, vm_memattr_t *memattr) 6121556Srgrimes{ 6131556Srgrimes struct tty *tp = dev->si_drv1; 6141556Srgrimes int error; 6151556Srgrimes 6161556Srgrimes /* Handle mmap() through the driver. */ 6171556Srgrimes 6181556Srgrimes error = ttydev_enter(tp); 6191556Srgrimes if (error) 6201556Srgrimes return (-1); 6211556Srgrimes error = ttydevsw_mmap(tp, offset, paddr, nprot, memattr); 6221556Srgrimes tty_unlock(tp); 6231556Srgrimes 6241556Srgrimes return (error); 6251556Srgrimes} 6261556Srgrimes 6271556Srgrimes/* 6281556Srgrimes * kqueue support. 6291556Srgrimes */ 63013978Spst 63113978Spststatic void 6321556Srgrimestty_kqops_read_detach(struct knote *kn) 63313978Spst{ 63413978Spst struct tty *tp = kn->kn_hook; 6351556Srgrimes 63613978Spst knlist_remove(&tp->t_inpoll.si_note, kn, 0); 63713978Spst} 6381556Srgrimes 63913978Spststatic int 64013978Spsttty_kqops_read_event(struct knote *kn, long hint) 6411556Srgrimes{ 6421556Srgrimes struct tty *tp = kn->kn_hook; 6431556Srgrimes 6441556Srgrimes tty_lock_assert(tp, MA_OWNED); 6451556Srgrimes 6461556Srgrimes if (tty_gone(tp) || tp->t_flags & TF_ZOMBIE) { 6471556Srgrimes kn->kn_flags |= EV_EOF; 6481556Srgrimes return (1); 6491556Srgrimes } else { 6501556Srgrimes kn->kn_data = ttydisc_read_poll(tp); 6511556Srgrimes return (kn->kn_data > 0); 6521556Srgrimes } 6531556Srgrimes} 6541556Srgrimes 6551556Srgrimesstatic void 6561556Srgrimestty_kqops_write_detach(struct knote *kn) 6571556Srgrimes{ 6581556Srgrimes struct tty *tp = kn->kn_hook; 6591556Srgrimes 6601556Srgrimes knlist_remove(&tp->t_outpoll.si_note, kn, 0); 6611556Srgrimes} 6621556Srgrimes 6631556Srgrimesstatic int 6641556Srgrimestty_kqops_write_event(struct knote *kn, long hint) 6651556Srgrimes{ 6661556Srgrimes struct tty *tp = kn->kn_hook; 6671556Srgrimes 6681556Srgrimes tty_lock_assert(tp, MA_OWNED); 6691556Srgrimes 6701556Srgrimes if (tty_gone(tp)) { 6711556Srgrimes kn->kn_flags |= EV_EOF; 6721556Srgrimes return (1); 6731556Srgrimes } else { 6741556Srgrimes kn->kn_data = ttydisc_write_poll(tp); 6751556Srgrimes return (kn->kn_data > 0); 6761556Srgrimes } 6771556Srgrimes} 6781556Srgrimes 6791556Srgrimesstatic struct filterops tty_kqops_read = { 6801556Srgrimes .f_isfd = 1, 6811556Srgrimes .f_detach = tty_kqops_read_detach, 6821556Srgrimes .f_event = tty_kqops_read_event, 6831556Srgrimes}; 6841556Srgrimesstatic struct filterops tty_kqops_write = { 6851556Srgrimes .f_isfd = 1, 6861556Srgrimes .f_detach = tty_kqops_write_detach, 6871556Srgrimes .f_event = tty_kqops_write_event, 6881556Srgrimes}; 6891556Srgrimes 6901556Srgrimesstatic int 6911556Srgrimesttydev_kqfilter(struct cdev *dev, struct knote *kn) 6921556Srgrimes{ 6931556Srgrimes struct tty *tp = dev->si_drv1; 6941556Srgrimes int error; 6951556Srgrimes 6961556Srgrimes error = ttydev_enter(tp); 6971556Srgrimes if (error) 6981556Srgrimes return (error); 6991556Srgrimes 7001556Srgrimes switch (kn->kn_filter) { 7011556Srgrimes case EVFILT_READ: 7021556Srgrimes kn->kn_hook = tp; 7031556Srgrimes kn->kn_fop = &tty_kqops_read; 7041556Srgrimes knlist_add(&tp->t_inpoll.si_note, kn, 1); 7051556Srgrimes break; 7061556Srgrimes case EVFILT_WRITE: 7071556Srgrimes kn->kn_hook = tp; 7081556Srgrimes kn->kn_fop = &tty_kqops_write; 7091556Srgrimes knlist_add(&tp->t_outpoll.si_note, kn, 1); 7101556Srgrimes break; 7111556Srgrimes default: 7121556Srgrimes error = EINVAL; 7131556Srgrimes break; 7141556Srgrimes } 7151556Srgrimes 7161556Srgrimes tty_unlock(tp); 7171556Srgrimes return (error); 7181556Srgrimes} 7191556Srgrimes 7201556Srgrimesstatic struct cdevsw ttydev_cdevsw = { 7211556Srgrimes .d_version = D_VERSION, 7221556Srgrimes .d_open = ttydev_open, 7231556Srgrimes .d_close = ttydev_close, 7241556Srgrimes .d_read = ttydev_read, 7251556Srgrimes .d_write = ttydev_write, 7261556Srgrimes .d_ioctl = ttydev_ioctl, 7271556Srgrimes .d_kqfilter = ttydev_kqfilter, 7281556Srgrimes .d_poll = ttydev_poll, 7291556Srgrimes .d_mmap = ttydev_mmap, 7301556Srgrimes .d_name = "ttydev", 7311556Srgrimes .d_flags = D_TTY, 7321556Srgrimes}; 7331556Srgrimes 7341556Srgrimes/* 7351556Srgrimes * Init/lock-state devices 7361556Srgrimes */ 7371556Srgrimes 7381556Srgrimesstatic int 7391556Srgrimesttyil_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 7401556Srgrimes{ 7411556Srgrimes struct tty *tp = dev->si_drv1; 7421556Srgrimes int error = 0; 7431556Srgrimes 7441556Srgrimes tty_lock(tp); 7451556Srgrimes if (tty_gone(tp)) 7461556Srgrimes error = ENODEV; 7471556Srgrimes tty_unlock(tp); 7481556Srgrimes 7498855Srgrimes return (error); 7501556Srgrimes} 7511556Srgrimes 7521556Srgrimesstatic int 7531556Srgrimesttyil_close(struct cdev *dev, int flag, int mode, struct thread *td) 7541556Srgrimes{ 7551556Srgrimes return (0); 7561556Srgrimes} 7571556Srgrimes 7581556Srgrimesstatic int 7598855Srgrimesttyil_rdwr(struct cdev *dev, struct uio *uio, int ioflag) 7601556Srgrimes{ 7611556Srgrimes return (ENODEV); 7621556Srgrimes} 7631556Srgrimes 7641556Srgrimesstatic int 7651556Srgrimesttyil_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 7661556Srgrimes struct thread *td) 7671556Srgrimes{ 7681556Srgrimes struct tty *tp = dev->si_drv1; 7691556Srgrimes int error; 7701556Srgrimes 7711556Srgrimes tty_lock(tp); 7721556Srgrimes if (tty_gone(tp)) { 7731556Srgrimes error = ENODEV; 7741556Srgrimes goto done; 7751556Srgrimes } 7761556Srgrimes 7771556Srgrimes error = ttydevsw_cioctl(tp, dev2unit(dev), cmd, data, td); 7781556Srgrimes if (error != ENOIOCTL) 7791556Srgrimes goto done; 7801556Srgrimes error = 0; 7811556Srgrimes 7821556Srgrimes switch (cmd) { 7831556Srgrimes case TIOCGETA: 7841556Srgrimes /* Obtain terminal flags through tcgetattr(). */ 7851556Srgrimes *(struct termios*)data = *(struct termios*)dev->si_drv2; 7861556Srgrimes break; 7871556Srgrimes case TIOCSETA: 7881556Srgrimes /* Set terminal flags through tcsetattr(). */ 7891556Srgrimes error = priv_check(td, PRIV_TTY_SETA); 7901556Srgrimes if (error) 7911556Srgrimes break; 7921556Srgrimes *(struct termios*)dev->si_drv2 = *(struct termios*)data; 7931556Srgrimes break; 7941556Srgrimes case TIOCGETD: 7951556Srgrimes *(int *)data = TTYDISC; 7961556Srgrimes break; 7971556Srgrimes case TIOCGWINSZ: 7981556Srgrimes bzero(data, sizeof(struct winsize)); 7991556Srgrimes break; 8001556Srgrimes default: 8011556Srgrimes error = ENOTTY; 8021556Srgrimes } 8031556Srgrimes 80490110Simpdone: tty_unlock(tp); 8051556Srgrimes return (error); 8061556Srgrimes} 80734898Smarkm 8081556Srgrimesstatic struct cdevsw ttyil_cdevsw = { 8091556Srgrimes .d_version = D_VERSION, 8101556Srgrimes .d_open = ttyil_open, 8111556Srgrimes .d_close = ttyil_close, 8128855Srgrimes .d_read = ttyil_rdwr, 8131556Srgrimes .d_write = ttyil_rdwr, 8148855Srgrimes .d_ioctl = ttyil_ioctl, 8151556Srgrimes .d_name = "ttyil", 8161556Srgrimes .d_flags = D_TTY, 8171556Srgrimes}; 8181556Srgrimes 8191556Srgrimesstatic void 8201556Srgrimestty_init_termios(struct tty *tp) 8211556Srgrimes{ 8221556Srgrimes struct termios *t = &tp->t_termios_init_in; 8231556Srgrimes 8241556Srgrimes t->c_cflag = TTYDEF_CFLAG; 82534898Smarkm t->c_iflag = TTYDEF_IFLAG; 82648560Sbde t->c_lflag = TTYDEF_LFLAG; 8271556Srgrimes t->c_oflag = TTYDEF_OFLAG; 8281556Srgrimes t->c_ispeed = TTYDEF_SPEED; 8291556Srgrimes t->c_ospeed = TTYDEF_SPEED; 8301556Srgrimes memcpy(&t->c_cc, ttydefchars, sizeof ttydefchars); 8311556Srgrimes 8321556Srgrimes tp->t_termios_init_out = *t; 8331556Srgrimes} 8341556Srgrimes 8351556Srgrimesvoid 8361556Srgrimestty_init_console(struct tty *tp, speed_t s) 8371556Srgrimes{ 8381556Srgrimes struct termios *ti = &tp->t_termios_init_in; 8391556Srgrimes struct termios *to = &tp->t_termios_init_out; 8401556Srgrimes 84190110Simp if (s != 0) { 8421556Srgrimes ti->c_ispeed = ti->c_ospeed = s; 8431556Srgrimes to->c_ispeed = to->c_ospeed = s; 8441556Srgrimes } 8451556Srgrimes 8461556Srgrimes ti->c_cflag |= CLOCAL; 8471556Srgrimes to->c_cflag |= CLOCAL; 8481556Srgrimes} 8491556Srgrimes 8501556Srgrimes/* 8511556Srgrimes * Standard device routine implementations, mostly meant for 8521556Srgrimes * pseudo-terminal device drivers. When a driver creates a new terminal 8531556Srgrimes * device class, missing routines are patched. 8541556Srgrimes */ 8551556Srgrimes 8561556Srgrimesstatic int 8571556Srgrimesttydevsw_defopen(struct tty *tp) 8581556Srgrimes{ 8591556Srgrimes 8601556Srgrimes return (0); 8611556Srgrimes} 8621556Srgrimes 8631556Srgrimesstatic void 8641556Srgrimesttydevsw_defclose(struct tty *tp) 8651556Srgrimes{ 8661556Srgrimes} 8671556Srgrimes 8681556Srgrimesstatic void 8691556Srgrimesttydevsw_defoutwakeup(struct tty *tp) 8701556Srgrimes{ 8711556Srgrimes 8721556Srgrimes panic("Terminal device has output, while not implemented"); 8731556Srgrimes} 87490110Simp 8751556Srgrimesstatic void 8761556Srgrimesttydevsw_definwakeup(struct tty *tp) 8771556Srgrimes{ 87826466Scharnier} 8791556Srgrimes 88026466Scharnierstatic int 8811556Srgrimesttydevsw_defioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 88226466Scharnier{ 8831556Srgrimes 88426466Scharnier return (ENOIOCTL); 8851556Srgrimes} 8861556Srgrimes 88726466Scharnierstatic int 88826466Scharnierttydevsw_defcioctl(struct tty *tp, int unit, u_long cmd, caddr_t data, struct thread *td) 88926466Scharnier{ 8901556Srgrimes 8911556Srgrimes return (ENOIOCTL); 8921556Srgrimes} 8931556Srgrimes 8941556Srgrimesstatic int 8951556Srgrimesttydevsw_defparam(struct tty *tp, struct termios *t) 8961556Srgrimes{ 8971556Srgrimes 8981556Srgrimes /* 8991556Srgrimes * Allow the baud rate to be adjusted for pseudo-devices, but at 9001556Srgrimes * least restrict it to 115200 to prevent excessive buffer 9011556Srgrimes * usage. Also disallow 0, to prevent foot shooting. 9021556Srgrimes */ 9031556Srgrimes if (t->c_ispeed < B50) 9041556Srgrimes t->c_ispeed = B50; 9051556Srgrimes else if (t->c_ispeed > B115200) 9061556Srgrimes t->c_ispeed = B115200; 9071556Srgrimes if (t->c_ospeed < B50) 9081556Srgrimes t->c_ospeed = B50; 9091556Srgrimes else if (t->c_ospeed > B115200) 9101556Srgrimes t->c_ospeed = B115200; 9111556Srgrimes t->c_cflag |= CREAD; 9121556Srgrimes 9131556Srgrimes return (0); 9141556Srgrimes} 9151556Srgrimes 9161556Srgrimesstatic int 9171556Srgrimesttydevsw_defmodem(struct tty *tp, int sigon, int sigoff) 9181556Srgrimes{ 9191556Srgrimes 9201556Srgrimes /* Simulate a carrier to make the TTY layer happy. */ 9211556Srgrimes return (SER_DCD); 9221556Srgrimes} 9231556Srgrimes 9241556Srgrimesstatic int 9251556Srgrimesttydevsw_defmmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t *paddr, 9261556Srgrimes int nprot, vm_memattr_t *memattr) 9271556Srgrimes{ 9281556Srgrimes 9291556Srgrimes return (-1); 930} 931 932static void 933ttydevsw_defpktnotify(struct tty *tp, char event) 934{ 935} 936 937static void 938ttydevsw_deffree(void *softc) 939{ 940 941 panic("Terminal device freed without a free-handler"); 942} 943 944/* 945 * TTY allocation and deallocation. TTY devices can be deallocated when 946 * the driver doesn't use it anymore, when the TTY isn't a session's 947 * controlling TTY and when the device node isn't opened through devfs. 948 */ 949 950struct tty * 951tty_alloc(struct ttydevsw *tsw, void *sc) 952{ 953 954 return (tty_alloc_mutex(tsw, sc, NULL)); 955} 956 957struct tty * 958tty_alloc_mutex(struct ttydevsw *tsw, void *sc, struct mtx *mutex) 959{ 960 struct tty *tp; 961 962 /* Make sure the driver defines all routines. */ 963#define PATCH_FUNC(x) do { \ 964 if (tsw->tsw_ ## x == NULL) \ 965 tsw->tsw_ ## x = ttydevsw_def ## x; \ 966} while (0) 967 PATCH_FUNC(open); 968 PATCH_FUNC(close); 969 PATCH_FUNC(outwakeup); 970 PATCH_FUNC(inwakeup); 971 PATCH_FUNC(ioctl); 972 PATCH_FUNC(cioctl); 973 PATCH_FUNC(param); 974 PATCH_FUNC(modem); 975 PATCH_FUNC(mmap); 976 PATCH_FUNC(pktnotify); 977 PATCH_FUNC(free); 978#undef PATCH_FUNC 979 980 tp = malloc(sizeof(struct tty), M_TTY, M_WAITOK|M_ZERO); 981 tp->t_devsw = tsw; 982 tp->t_devswsoftc = sc; 983 tp->t_flags = tsw->tsw_flags; 984 985 tty_init_termios(tp); 986 987 cv_init(&tp->t_inwait, "ttyin"); 988 cv_init(&tp->t_outwait, "ttyout"); 989 cv_init(&tp->t_outserwait, "ttyosr"); 990 cv_init(&tp->t_bgwait, "ttybg"); 991 cv_init(&tp->t_dcdwait, "ttydcd"); 992 993 /* Allow drivers to use a custom mutex to lock the TTY. */ 994 if (mutex != NULL) { 995 tp->t_mtx = mutex; 996 } else { 997 tp->t_mtx = &tp->t_mtxobj; 998 mtx_init(&tp->t_mtxobj, "ttymtx", NULL, MTX_DEF); 999 } 1000 1001 knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx); 1002 knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx); 1003 1004 sx_xlock(&tty_list_sx); 1005 TAILQ_INSERT_TAIL(&tty_list, tp, t_list); 1006 tty_list_count++; 1007 sx_xunlock(&tty_list_sx); 1008 1009 return (tp); 1010} 1011 1012static void 1013tty_dealloc(void *arg) 1014{ 1015 struct tty *tp = arg; 1016 1017 sx_xlock(&tty_list_sx); 1018 TAILQ_REMOVE(&tty_list, tp, t_list); 1019 tty_list_count--; 1020 sx_xunlock(&tty_list_sx); 1021 1022 /* Make sure we haven't leaked buffers. */ 1023 MPASS(ttyinq_getsize(&tp->t_inq) == 0); 1024 MPASS(ttyoutq_getsize(&tp->t_outq) == 0); 1025 1026 seldrain(&tp->t_inpoll); 1027 seldrain(&tp->t_outpoll); 1028 knlist_destroy(&tp->t_inpoll.si_note); 1029 knlist_destroy(&tp->t_outpoll.si_note); 1030 1031 cv_destroy(&tp->t_inwait); 1032 cv_destroy(&tp->t_outwait); 1033 cv_destroy(&tp->t_bgwait); 1034 cv_destroy(&tp->t_dcdwait); 1035 cv_destroy(&tp->t_outserwait); 1036 1037 if (tp->t_mtx == &tp->t_mtxobj) 1038 mtx_destroy(&tp->t_mtxobj); 1039 ttydevsw_free(tp); 1040 free(tp, M_TTY); 1041} 1042 1043static void 1044tty_rel_free(struct tty *tp) 1045{ 1046 struct cdev *dev; 1047 1048 tty_lock_assert(tp, MA_OWNED); 1049 1050#define TF_ACTIVITY (TF_GONE|TF_OPENED|TF_HOOK|TF_OPENCLOSE) 1051 if (tp->t_sessioncnt != 0 || (tp->t_flags & TF_ACTIVITY) != TF_GONE) { 1052 /* TTY is still in use. */ 1053 tty_unlock(tp); 1054 return; 1055 } 1056 1057 /* TTY can be deallocated. */ 1058 dev = tp->t_dev; 1059 tp->t_dev = NULL; 1060 tty_unlock(tp); 1061 1062 if (dev != NULL) 1063 destroy_dev_sched_cb(dev, tty_dealloc, tp); 1064} 1065 1066void 1067tty_rel_pgrp(struct tty *tp, struct pgrp *pg) 1068{ 1069 MPASS(tp->t_sessioncnt > 0); 1070 tty_lock_assert(tp, MA_OWNED); 1071 1072 if (tp->t_pgrp == pg) 1073 tp->t_pgrp = NULL; 1074 1075 tty_unlock(tp); 1076} 1077 1078void 1079tty_rel_sess(struct tty *tp, struct session *sess) 1080{ 1081 MPASS(tp->t_sessioncnt > 0); 1082 1083 /* Current session has left. */ 1084 if (tp->t_session == sess) { 1085 tp->t_session = NULL; 1086 MPASS(tp->t_pgrp == NULL); 1087 } 1088 tp->t_sessioncnt--; 1089 tty_rel_free(tp); 1090} 1091 1092void 1093tty_rel_gone(struct tty *tp) 1094{ 1095 MPASS(!tty_gone(tp)); 1096 1097 /* Simulate carrier removal. */ 1098 ttydisc_modem(tp, 0); 1099 1100 /* Wake up all blocked threads. */ 1101 tty_wakeup(tp, FREAD|FWRITE); 1102 cv_broadcast(&tp->t_bgwait); 1103 cv_broadcast(&tp->t_dcdwait); 1104 1105 tp->t_flags |= TF_GONE; 1106 tty_rel_free(tp); 1107} 1108 1109/* 1110 * Exposing information about current TTY's through sysctl 1111 */ 1112 1113static void 1114tty_to_xtty(struct tty *tp, struct xtty *xt) 1115{ 1116 tty_lock_assert(tp, MA_OWNED); 1117 1118 xt->xt_size = sizeof(struct xtty); 1119 xt->xt_insize = ttyinq_getsize(&tp->t_inq); 1120 xt->xt_incc = ttyinq_bytescanonicalized(&tp->t_inq); 1121 xt->xt_inlc = ttyinq_bytesline(&tp->t_inq); 1122 xt->xt_inlow = tp->t_inlow; 1123 xt->xt_outsize = ttyoutq_getsize(&tp->t_outq); 1124 xt->xt_outcc = ttyoutq_bytesused(&tp->t_outq); 1125 xt->xt_outlow = tp->t_outlow; 1126 xt->xt_column = tp->t_column; 1127 xt->xt_pgid = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 1128 xt->xt_sid = tp->t_session ? tp->t_session->s_sid : 0; 1129 xt->xt_flags = tp->t_flags; 1130 xt->xt_dev = tp->t_dev ? dev2udev(tp->t_dev) : NODEV; 1131} 1132 1133static int 1134sysctl_kern_ttys(SYSCTL_HANDLER_ARGS) 1135{ 1136 unsigned long lsize; 1137 struct xtty *xtlist, *xt; 1138 struct tty *tp; 1139 int error; 1140 1141 sx_slock(&tty_list_sx); 1142 lsize = tty_list_count * sizeof(struct xtty); 1143 if (lsize == 0) { 1144 sx_sunlock(&tty_list_sx); 1145 return (0); 1146 } 1147 1148 xtlist = xt = malloc(lsize, M_TTY, M_WAITOK); 1149 1150 TAILQ_FOREACH(tp, &tty_list, t_list) { 1151 tty_lock(tp); 1152 tty_to_xtty(tp, xt); 1153 tty_unlock(tp); 1154 xt++; 1155 } 1156 sx_sunlock(&tty_list_sx); 1157 1158 error = SYSCTL_OUT(req, xtlist, lsize); 1159 free(xtlist, M_TTY); 1160 return (error); 1161} 1162 1163SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_MPSAFE, 1164 0, 0, sysctl_kern_ttys, "S,xtty", "List of TTYs"); 1165 1166/* 1167 * Device node creation. Device has been set up, now we can expose it to 1168 * the user. 1169 */ 1170 1171void 1172tty_makedev(struct tty *tp, struct ucred *cred, const char *fmt, ...) 1173{ 1174 va_list ap; 1175 struct cdev *dev; 1176 const char *prefix = "tty"; 1177 char name[SPECNAMELEN - 3]; /* for "tty" and "cua". */ 1178 uid_t uid; 1179 gid_t gid; 1180 mode_t mode; 1181 1182 /* Remove "tty" prefix from devices like PTY's. */ 1183 if (tp->t_flags & TF_NOPREFIX) 1184 prefix = ""; 1185 1186 va_start(ap, fmt); 1187 vsnrprintf(name, sizeof name, 32, fmt, ap); 1188 va_end(ap); 1189 1190 if (cred == NULL) { 1191 /* System device. */ 1192 uid = UID_ROOT; 1193 gid = GID_WHEEL; 1194 mode = S_IRUSR|S_IWUSR; 1195 } else { 1196 /* User device. */ 1197 uid = cred->cr_ruid; 1198 gid = GID_TTY; 1199 mode = S_IRUSR|S_IWUSR|S_IWGRP; 1200 } 1201 1202 /* Master call-in device. */ 1203 dev = make_dev_cred(&ttydev_cdevsw, 0, cred, 1204 uid, gid, mode, "%s%s", prefix, name); 1205 dev->si_drv1 = tp; 1206 tp->t_dev = dev; 1207 1208 /* Slave call-in devices. */ 1209 if (tp->t_flags & TF_INITLOCK) { 1210 dev = make_dev_cred(&ttyil_cdevsw, TTYUNIT_INIT, cred, 1211 uid, gid, mode, "%s%s.init", prefix, name); 1212 dev_depends(tp->t_dev, dev); 1213 dev->si_drv1 = tp; 1214 dev->si_drv2 = &tp->t_termios_init_in; 1215 1216 dev = make_dev_cred(&ttyil_cdevsw, TTYUNIT_LOCK, cred, 1217 uid, gid, mode, "%s%s.lock", prefix, name); 1218 dev_depends(tp->t_dev, dev); 1219 dev->si_drv1 = tp; 1220 dev->si_drv2 = &tp->t_termios_lock_in; 1221 } 1222 1223 /* Call-out devices. */ 1224 if (tp->t_flags & TF_CALLOUT) { 1225 dev = make_dev_cred(&ttydev_cdevsw, TTYUNIT_CALLOUT, cred, 1226 UID_UUCP, GID_DIALER, 0660, "cua%s", name); 1227 dev_depends(tp->t_dev, dev); 1228 dev->si_drv1 = tp; 1229 1230 /* Slave call-out devices. */ 1231 if (tp->t_flags & TF_INITLOCK) { 1232 dev = make_dev_cred(&ttyil_cdevsw, 1233 TTYUNIT_CALLOUT | TTYUNIT_INIT, cred, 1234 UID_UUCP, GID_DIALER, 0660, "cua%s.init", name); 1235 dev_depends(tp->t_dev, dev); 1236 dev->si_drv1 = tp; 1237 dev->si_drv2 = &tp->t_termios_init_out; 1238 1239 dev = make_dev_cred(&ttyil_cdevsw, 1240 TTYUNIT_CALLOUT | TTYUNIT_LOCK, cred, 1241 UID_UUCP, GID_DIALER, 0660, "cua%s.lock", name); 1242 dev_depends(tp->t_dev, dev); 1243 dev->si_drv1 = tp; 1244 dev->si_drv2 = &tp->t_termios_lock_out; 1245 } 1246 } 1247} 1248 1249/* 1250 * Signalling processes. 1251 */ 1252 1253void 1254tty_signal_sessleader(struct tty *tp, int sig) 1255{ 1256 struct proc *p; 1257 1258 tty_lock_assert(tp, MA_OWNED); 1259 MPASS(sig >= 1 && sig < NSIG); 1260 1261 /* Make signals start output again. */ 1262 tp->t_flags &= ~TF_STOPPED; 1263 1264 if (tp->t_session != NULL && tp->t_session->s_leader != NULL) { 1265 p = tp->t_session->s_leader; 1266 PROC_LOCK(p); 1267 kern_psignal(p, sig); 1268 PROC_UNLOCK(p); 1269 } 1270} 1271 1272void 1273tty_signal_pgrp(struct tty *tp, int sig) 1274{ 1275 ksiginfo_t ksi; 1276 1277 tty_lock_assert(tp, MA_OWNED); 1278 MPASS(sig >= 1 && sig < NSIG); 1279 1280 /* Make signals start output again. */ 1281 tp->t_flags &= ~TF_STOPPED; 1282 1283 if (sig == SIGINFO && !(tp->t_termios.c_lflag & NOKERNINFO)) 1284 tty_info(tp); 1285 if (tp->t_pgrp != NULL) { 1286 ksiginfo_init(&ksi); 1287 ksi.ksi_signo = sig; 1288 ksi.ksi_code = SI_KERNEL; 1289 PGRP_LOCK(tp->t_pgrp); 1290 pgsignal(tp->t_pgrp, sig, 1, &ksi); 1291 PGRP_UNLOCK(tp->t_pgrp); 1292 } 1293} 1294 1295void 1296tty_wakeup(struct tty *tp, int flags) 1297{ 1298 if (tp->t_flags & TF_ASYNC && tp->t_sigio != NULL) 1299 pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL)); 1300 1301 if (flags & FWRITE) { 1302 cv_broadcast(&tp->t_outwait); 1303 selwakeup(&tp->t_outpoll); 1304 KNOTE_LOCKED(&tp->t_outpoll.si_note, 0); 1305 } 1306 if (flags & FREAD) { 1307 cv_broadcast(&tp->t_inwait); 1308 selwakeup(&tp->t_inpoll); 1309 KNOTE_LOCKED(&tp->t_inpoll.si_note, 0); 1310 } 1311} 1312 1313int 1314tty_wait(struct tty *tp, struct cv *cv) 1315{ 1316 int error; 1317 int revokecnt = tp->t_revokecnt; 1318 1319 tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED); 1320 MPASS(!tty_gone(tp)); 1321 1322 error = cv_wait_sig(cv, tp->t_mtx); 1323 1324 /* Restart the system call when we may have been revoked. */ 1325 if (tp->t_revokecnt != revokecnt) 1326 return (ERESTART); 1327 1328 /* Bail out when the device slipped away. */ 1329 if (tty_gone(tp)) 1330 return (ENXIO); 1331 1332 return (error); 1333} 1334 1335int 1336tty_timedwait(struct tty *tp, struct cv *cv, int hz) 1337{ 1338 int error; 1339 int revokecnt = tp->t_revokecnt; 1340 1341 tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED); 1342 MPASS(!tty_gone(tp)); 1343 1344 error = cv_timedwait_sig(cv, tp->t_mtx, hz); 1345 1346 /* Restart the system call when we may have been revoked. */ 1347 if (tp->t_revokecnt != revokecnt) 1348 return (ERESTART); 1349 1350 /* Bail out when the device slipped away. */ 1351 if (tty_gone(tp)) 1352 return (ENXIO); 1353 1354 return (error); 1355} 1356 1357void 1358tty_flush(struct tty *tp, int flags) 1359{ 1360 if (flags & FWRITE) { 1361 tp->t_flags &= ~TF_HIWAT_OUT; 1362 ttyoutq_flush(&tp->t_outq); 1363 tty_wakeup(tp, FWRITE); 1364 ttydevsw_pktnotify(tp, TIOCPKT_FLUSHWRITE); 1365 } 1366 if (flags & FREAD) { 1367 tty_hiwat_in_unblock(tp); 1368 ttyinq_flush(&tp->t_inq); 1369 ttydevsw_inwakeup(tp); 1370 ttydevsw_pktnotify(tp, TIOCPKT_FLUSHREAD); 1371 } 1372} 1373 1374static int 1375tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, 1376 struct thread *td) 1377{ 1378 int error; 1379 1380 switch (cmd) { 1381 /* 1382 * Modem commands. 1383 * The SER_* and TIOCM_* flags are the same, but one bit 1384 * shifted. I don't know why. 1385 */ 1386 case TIOCSDTR: 1387 ttydevsw_modem(tp, SER_DTR, 0); 1388 return (0); 1389 case TIOCCDTR: 1390 ttydevsw_modem(tp, 0, SER_DTR); 1391 return (0); 1392 case TIOCMSET: { 1393 int bits = *(int *)data; 1394 ttydevsw_modem(tp, 1395 (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1, 1396 ((~bits) & (TIOCM_DTR | TIOCM_RTS)) >> 1); 1397 return (0); 1398 } 1399 case TIOCMBIS: { 1400 int bits = *(int *)data; 1401 ttydevsw_modem(tp, (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1, 0); 1402 return (0); 1403 } 1404 case TIOCMBIC: { 1405 int bits = *(int *)data; 1406 ttydevsw_modem(tp, 0, (bits & (TIOCM_DTR | TIOCM_RTS)) >> 1); 1407 return (0); 1408 } 1409 case TIOCMGET: 1410 *(int *)data = TIOCM_LE + (ttydevsw_modem(tp, 0, 0) << 1); 1411 return (0); 1412 1413 case FIOASYNC: 1414 if (*(int *)data) 1415 tp->t_flags |= TF_ASYNC; 1416 else 1417 tp->t_flags &= ~TF_ASYNC; 1418 return (0); 1419 case FIONBIO: 1420 /* This device supports non-blocking operation. */ 1421 return (0); 1422 case FIONREAD: 1423 *(int *)data = ttyinq_bytescanonicalized(&tp->t_inq); 1424 return (0); 1425 case FIONWRITE: 1426 case TIOCOUTQ: 1427 *(int *)data = ttyoutq_bytesused(&tp->t_outq); 1428 return (0); 1429 case FIOSETOWN: 1430 if (tp->t_session != NULL && !tty_is_ctty(tp, td->td_proc)) 1431 /* Not allowed to set ownership. */ 1432 return (ENOTTY); 1433 1434 /* Temporarily unlock the TTY to set ownership. */ 1435 tty_unlock(tp); 1436 error = fsetown(*(int *)data, &tp->t_sigio); 1437 tty_lock(tp); 1438 return (error); 1439 case FIOGETOWN: 1440 if (tp->t_session != NULL && !tty_is_ctty(tp, td->td_proc)) 1441 /* Not allowed to set ownership. */ 1442 return (ENOTTY); 1443 1444 /* Get ownership. */ 1445 *(int *)data = fgetown(&tp->t_sigio); 1446 return (0); 1447 case TIOCGETA: 1448 /* Obtain terminal flags through tcgetattr(). */ 1449 *(struct termios*)data = tp->t_termios; 1450 return (0); 1451 case TIOCSETA: 1452 case TIOCSETAW: 1453 case TIOCSETAF: { 1454 struct termios *t = data; 1455 1456 /* 1457 * Who makes up these funny rules? According to POSIX, 1458 * input baud rate is set equal to the output baud rate 1459 * when zero. 1460 */ 1461 if (t->c_ispeed == 0) 1462 t->c_ispeed = t->c_ospeed; 1463 1464 /* Discard any unsupported bits. */ 1465 t->c_iflag &= TTYSUP_IFLAG; 1466 t->c_oflag &= TTYSUP_OFLAG; 1467 t->c_lflag &= TTYSUP_LFLAG; 1468 t->c_cflag &= TTYSUP_CFLAG; 1469 1470 /* Set terminal flags through tcsetattr(). */ 1471 if (cmd == TIOCSETAW || cmd == TIOCSETAF) { 1472 error = tty_drain(tp); 1473 if (error) 1474 return (error); 1475 if (cmd == TIOCSETAF) 1476 tty_flush(tp, FREAD); 1477 } 1478 1479 /* 1480 * Only call param() when the flags really change. 1481 */ 1482 if ((t->c_cflag & CIGNORE) == 0 && 1483 (tp->t_termios.c_cflag != t->c_cflag || 1484 ((tp->t_termios.c_iflag ^ t->c_iflag) & 1485 (IXON|IXOFF|IXANY)) || 1486 tp->t_termios.c_ispeed != t->c_ispeed || 1487 tp->t_termios.c_ospeed != t->c_ospeed)) { 1488 error = ttydevsw_param(tp, t); 1489 if (error) 1490 return (error); 1491 1492 /* XXX: CLOCAL? */ 1493 1494 tp->t_termios.c_cflag = t->c_cflag & ~CIGNORE; 1495 tp->t_termios.c_ispeed = t->c_ispeed; 1496 tp->t_termios.c_ospeed = t->c_ospeed; 1497 1498 /* Baud rate has changed - update watermarks. */ 1499 tty_watermarks(tp); 1500 } 1501 1502 /* Copy new non-device driver parameters. */ 1503 tp->t_termios.c_iflag = t->c_iflag; 1504 tp->t_termios.c_oflag = t->c_oflag; 1505 tp->t_termios.c_lflag = t->c_lflag; 1506 memcpy(&tp->t_termios.c_cc, t->c_cc, sizeof t->c_cc); 1507 1508 ttydisc_optimize(tp); 1509 1510 if ((t->c_lflag & ICANON) == 0) { 1511 /* 1512 * When in non-canonical mode, wake up all 1513 * readers. Canonicalize any partial input. VMIN 1514 * and VTIME could also be adjusted. 1515 */ 1516 ttyinq_canonicalize(&tp->t_inq); 1517 tty_wakeup(tp, FREAD); 1518 } 1519 1520 /* 1521 * For packet mode: notify the PTY consumer that VSTOP 1522 * and VSTART may have been changed. 1523 */ 1524 if (tp->t_termios.c_iflag & IXON && 1525 tp->t_termios.c_cc[VSTOP] == CTRL('S') && 1526 tp->t_termios.c_cc[VSTART] == CTRL('Q')) 1527 ttydevsw_pktnotify(tp, TIOCPKT_DOSTOP); 1528 else 1529 ttydevsw_pktnotify(tp, TIOCPKT_NOSTOP); 1530 return (0); 1531 } 1532 case TIOCGETD: 1533 /* For compatibility - we only support TTYDISC. */ 1534 *(int *)data = TTYDISC; 1535 return (0); 1536 case TIOCGPGRP: 1537 if (!tty_is_ctty(tp, td->td_proc)) 1538 return (ENOTTY); 1539 1540 if (tp->t_pgrp != NULL) 1541 *(int *)data = tp->t_pgrp->pg_id; 1542 else 1543 *(int *)data = NO_PID; 1544 return (0); 1545 case TIOCGSID: 1546 if (!tty_is_ctty(tp, td->td_proc)) 1547 return (ENOTTY); 1548 1549 MPASS(tp->t_session); 1550 *(int *)data = tp->t_session->s_sid; 1551 return (0); 1552 case TIOCSCTTY: { 1553 struct proc *p = td->td_proc; 1554 1555 /* XXX: This looks awful. */ 1556 tty_unlock(tp); 1557 sx_xlock(&proctree_lock); 1558 tty_lock(tp); 1559 1560 if (!SESS_LEADER(p)) { 1561 /* Only the session leader may do this. */ 1562 sx_xunlock(&proctree_lock); 1563 return (EPERM); 1564 } 1565 1566 if (tp->t_session != NULL && tp->t_session == p->p_session) { 1567 /* This is already our controlling TTY. */ 1568 sx_xunlock(&proctree_lock); 1569 return (0); 1570 } 1571 1572 if (p->p_session->s_ttyp != NULL || 1573 (tp->t_session != NULL && tp->t_session->s_ttyvp != NULL && 1574 tp->t_session->s_ttyvp->v_type != VBAD)) { 1575 /* 1576 * There is already a relation between a TTY and 1577 * a session, or the caller is not the session 1578 * leader. 1579 * 1580 * Allow the TTY to be stolen when the vnode is 1581 * invalid, but the reference to the TTY is 1582 * still active. This allows immediate reuse of 1583 * TTYs of which the session leader has been 1584 * killed or the TTY revoked. 1585 */ 1586 sx_xunlock(&proctree_lock); 1587 return (EPERM); 1588 } 1589 1590 /* Connect the session to the TTY. */ 1591 tp->t_session = p->p_session; 1592 tp->t_session->s_ttyp = tp; 1593 tp->t_sessioncnt++; 1594 sx_xunlock(&proctree_lock); 1595 1596 /* Assign foreground process group. */ 1597 tp->t_pgrp = p->p_pgrp; 1598 PROC_LOCK(p); 1599 p->p_flag |= P_CONTROLT; 1600 PROC_UNLOCK(p); 1601 1602 return (0); 1603 } 1604 case TIOCSPGRP: { 1605 struct pgrp *pg; 1606 1607 /* 1608 * XXX: Temporarily unlock the TTY to locate the process 1609 * group. This code would be lot nicer if we would ever 1610 * decompose proctree_lock. 1611 */ 1612 tty_unlock(tp); 1613 sx_slock(&proctree_lock); 1614 pg = pgfind(*(int *)data); 1615 if (pg != NULL) 1616 PGRP_UNLOCK(pg); 1617 if (pg == NULL || pg->pg_session != td->td_proc->p_session) { 1618 sx_sunlock(&proctree_lock); 1619 tty_lock(tp); 1620 return (EPERM); 1621 } 1622 tty_lock(tp); 1623 1624 /* 1625 * Determine if this TTY is the controlling TTY after 1626 * relocking the TTY. 1627 */ 1628 if (!tty_is_ctty(tp, td->td_proc)) { 1629 sx_sunlock(&proctree_lock); 1630 return (ENOTTY); 1631 } 1632 tp->t_pgrp = pg; 1633 sx_sunlock(&proctree_lock); 1634 1635 /* Wake up the background process groups. */ 1636 cv_broadcast(&tp->t_bgwait); 1637 return (0); 1638 } 1639 case TIOCFLUSH: { 1640 int flags = *(int *)data; 1641 1642 if (flags == 0) 1643 flags = (FREAD|FWRITE); 1644 else 1645 flags &= (FREAD|FWRITE); 1646 tty_flush(tp, flags); 1647 return (0); 1648 } 1649 case TIOCDRAIN: 1650 /* Drain TTY output. */ 1651 return tty_drain(tp); 1652 case TIOCCONS: 1653 /* Set terminal as console TTY. */ 1654 if (*(int *)data) { 1655 error = priv_check(td, PRIV_TTY_CONSOLE); 1656 if (error) 1657 return (error); 1658 1659 /* 1660 * XXX: constty should really need to be locked! 1661 * XXX: allow disconnected constty's to be stolen! 1662 */ 1663 1664 if (constty == tp) 1665 return (0); 1666 if (constty != NULL) 1667 return (EBUSY); 1668 1669 tty_unlock(tp); 1670 constty_set(tp); 1671 tty_lock(tp); 1672 } else if (constty == tp) { 1673 constty_clear(); 1674 } 1675 return (0); 1676 case TIOCGWINSZ: 1677 /* Obtain window size. */ 1678 *(struct winsize*)data = tp->t_winsize; 1679 return (0); 1680 case TIOCSWINSZ: 1681 /* Set window size. */ 1682 if (bcmp(&tp->t_winsize, data, sizeof(struct winsize)) == 0) 1683 return (0); 1684 tp->t_winsize = *(struct winsize*)data; 1685 tty_signal_pgrp(tp, SIGWINCH); 1686 return (0); 1687 case TIOCEXCL: 1688 tp->t_flags |= TF_EXCLUDE; 1689 return (0); 1690 case TIOCNXCL: 1691 tp->t_flags &= ~TF_EXCLUDE; 1692 return (0); 1693 case TIOCSTOP: 1694 tp->t_flags |= TF_STOPPED; 1695 ttydevsw_pktnotify(tp, TIOCPKT_STOP); 1696 return (0); 1697 case TIOCSTART: 1698 tp->t_flags &= ~TF_STOPPED; 1699 ttydevsw_outwakeup(tp); 1700 ttydevsw_pktnotify(tp, TIOCPKT_START); 1701 return (0); 1702 case TIOCSTAT: 1703 tty_info(tp); 1704 return (0); 1705 case TIOCSTI: 1706 if ((fflag & FREAD) == 0 && priv_check(td, PRIV_TTY_STI)) 1707 return (EPERM); 1708 if (!tty_is_ctty(tp, td->td_proc) && 1709 priv_check(td, PRIV_TTY_STI)) 1710 return (EACCES); 1711 ttydisc_rint(tp, *(char *)data, 0); 1712 ttydisc_rint_done(tp); 1713 return (0); 1714 } 1715 1716#ifdef COMPAT_43TTY 1717 return tty_ioctl_compat(tp, cmd, data, fflag, td); 1718#else /* !COMPAT_43TTY */ 1719 return (ENOIOCTL); 1720#endif /* COMPAT_43TTY */ 1721} 1722 1723int 1724tty_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, struct thread *td) 1725{ 1726 int error; 1727 1728 tty_lock_assert(tp, MA_OWNED); 1729 1730 if (tty_gone(tp)) 1731 return (ENXIO); 1732 1733 error = ttydevsw_ioctl(tp, cmd, data, td); 1734 if (error == ENOIOCTL) 1735 error = tty_generic_ioctl(tp, cmd, data, fflag, td); 1736 1737 return (error); 1738} 1739 1740dev_t 1741tty_udev(struct tty *tp) 1742{ 1743 if (tp->t_dev) 1744 return dev2udev(tp->t_dev); 1745 else 1746 return NODEV; 1747} 1748 1749int 1750tty_checkoutq(struct tty *tp) 1751{ 1752 1753 /* 256 bytes should be enough to print a log message. */ 1754 return (ttyoutq_bytesleft(&tp->t_outq) >= 256); 1755} 1756 1757void 1758tty_hiwat_in_block(struct tty *tp) 1759{ 1760 1761 if ((tp->t_flags & TF_HIWAT_IN) == 0 && 1762 tp->t_termios.c_iflag & IXOFF && 1763 tp->t_termios.c_cc[VSTOP] != _POSIX_VDISABLE) { 1764 /* 1765 * Input flow control. Only enter the high watermark when we 1766 * can successfully store the VSTOP character. 1767 */ 1768 if (ttyoutq_write_nofrag(&tp->t_outq, 1769 &tp->t_termios.c_cc[VSTOP], 1) == 0) 1770 tp->t_flags |= TF_HIWAT_IN; 1771 } else { 1772 /* No input flow control. */ 1773 tp->t_flags |= TF_HIWAT_IN; 1774 } 1775} 1776 1777void 1778tty_hiwat_in_unblock(struct tty *tp) 1779{ 1780 1781 if (tp->t_flags & TF_HIWAT_IN && 1782 tp->t_termios.c_iflag & IXOFF && 1783 tp->t_termios.c_cc[VSTART] != _POSIX_VDISABLE) { 1784 /* 1785 * Input flow control. Only leave the high watermark when we 1786 * can successfully store the VSTART character. 1787 */ 1788 if (ttyoutq_write_nofrag(&tp->t_outq, 1789 &tp->t_termios.c_cc[VSTART], 1) == 0) 1790 tp->t_flags &= ~TF_HIWAT_IN; 1791 } else { 1792 /* No input flow control. */ 1793 tp->t_flags &= ~TF_HIWAT_IN; 1794 } 1795 1796 if (!tty_gone(tp)) 1797 ttydevsw_inwakeup(tp); 1798} 1799 1800/* 1801 * TTY hooks interface. 1802 */ 1803 1804static int 1805ttyhook_defrint(struct tty *tp, char c, int flags) 1806{ 1807 1808 if (ttyhook_rint_bypass(tp, &c, 1) != 1) 1809 return (-1); 1810 1811 return (0); 1812} 1813 1814int 1815ttyhook_register(struct tty **rtp, struct proc *p, int fd, 1816 struct ttyhook *th, void *softc) 1817{ 1818 struct tty *tp; 1819 struct file *fp; 1820 struct cdev *dev; 1821 struct cdevsw *cdp; 1822 struct filedesc *fdp; 1823 int error, ref; 1824 1825 /* Validate the file descriptor. */ 1826 if ((fdp = p->p_fd) == NULL) 1827 return (EBADF); 1828 1829 fp = fget_unlocked(fdp, fd); 1830 if (fp == NULL) 1831 return (EBADF); 1832 if (fp->f_ops == &badfileops) { 1833 error = EBADF; 1834 goto done1; 1835 } 1836 1837#ifdef CAPABILITIES 1838 error = cap_funwrap(fp, CAP_TTYHOOK, &fp); 1839 if (error) 1840 goto done1; 1841#endif 1842 1843 /* 1844 * Make sure the vnode is bound to a character device. 1845 * Unlocked check for the vnode type is ok there, because we 1846 * only shall prevent calling devvn_refthread on the file that 1847 * never has been opened over a character device. 1848 */ 1849 if (fp->f_type != DTYPE_VNODE || fp->f_vnode->v_type != VCHR) { 1850 error = EINVAL; 1851 goto done1; 1852 } 1853 1854 /* Make sure it is a TTY. */ 1855 cdp = devvn_refthread(fp->f_vnode, &dev, &ref); 1856 if (cdp == NULL) { 1857 error = ENXIO; 1858 goto done1; 1859 } 1860 if (dev != fp->f_data) { 1861 error = ENXIO; 1862 goto done2; 1863 } 1864 if (cdp != &ttydev_cdevsw) { 1865 error = ENOTTY; 1866 goto done2; 1867 } 1868 tp = dev->si_drv1; 1869 1870 /* Try to attach the hook to the TTY. */ 1871 error = EBUSY; 1872 tty_lock(tp); 1873 MPASS((tp->t_hook == NULL) == ((tp->t_flags & TF_HOOK) == 0)); 1874 if (tp->t_flags & TF_HOOK) 1875 goto done3; 1876 1877 tp->t_flags |= TF_HOOK; 1878 tp->t_hook = th; 1879 tp->t_hooksoftc = softc; 1880 *rtp = tp; 1881 error = 0; 1882 1883 /* Maybe we can switch into bypass mode now. */ 1884 ttydisc_optimize(tp); 1885 1886 /* Silently convert rint() calls to rint_bypass() when possible. */ 1887 if (!ttyhook_hashook(tp, rint) && ttyhook_hashook(tp, rint_bypass)) 1888 th->th_rint = ttyhook_defrint; 1889 1890done3: tty_unlock(tp); 1891done2: dev_relthread(dev, ref); 1892done1: fdrop(fp, curthread); 1893 return (error); 1894} 1895 1896void 1897ttyhook_unregister(struct tty *tp) 1898{ 1899 1900 tty_lock_assert(tp, MA_OWNED); 1901 MPASS(tp->t_flags & TF_HOOK); 1902 1903 /* Disconnect the hook. */ 1904 tp->t_flags &= ~TF_HOOK; 1905 tp->t_hook = NULL; 1906 1907 /* Maybe we need to leave bypass mode. */ 1908 ttydisc_optimize(tp); 1909 1910 /* Maybe deallocate the TTY as well. */ 1911 tty_rel_free(tp); 1912} 1913 1914/* 1915 * /dev/console handling. 1916 */ 1917 1918static int 1919ttyconsdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 1920{ 1921 struct tty *tp; 1922 1923 /* System has no console device. */ 1924 if (dev_console_filename == NULL) 1925 return (ENXIO); 1926 1927 /* Look up corresponding TTY by device name. */ 1928 sx_slock(&tty_list_sx); 1929 TAILQ_FOREACH(tp, &tty_list, t_list) { 1930 if (strcmp(dev_console_filename, tty_devname(tp)) == 0) { 1931 dev_console->si_drv1 = tp; 1932 break; 1933 } 1934 } 1935 sx_sunlock(&tty_list_sx); 1936 1937 /* System console has no TTY associated. */ 1938 if (dev_console->si_drv1 == NULL) 1939 return (ENXIO); 1940 1941 return (ttydev_open(dev, oflags, devtype, td)); 1942} 1943 1944static int 1945ttyconsdev_write(struct cdev *dev, struct uio *uio, int ioflag) 1946{ 1947 1948 log_console(uio); 1949 1950 return (ttydev_write(dev, uio, ioflag)); 1951} 1952 1953/* 1954 * /dev/console is a little different than normal TTY's. When opened, 1955 * it determines which TTY to use. When data gets written to it, it 1956 * will be logged in the kernel message buffer. 1957 */ 1958static struct cdevsw ttyconsdev_cdevsw = { 1959 .d_version = D_VERSION, 1960 .d_open = ttyconsdev_open, 1961 .d_close = ttydev_close, 1962 .d_read = ttydev_read, 1963 .d_write = ttyconsdev_write, 1964 .d_ioctl = ttydev_ioctl, 1965 .d_kqfilter = ttydev_kqfilter, 1966 .d_poll = ttydev_poll, 1967 .d_mmap = ttydev_mmap, 1968 .d_name = "ttyconsdev", 1969 .d_flags = D_TTY, 1970}; 1971 1972static void 1973ttyconsdev_init(void *unused) 1974{ 1975 1976 dev_console = make_dev_credf(MAKEDEV_ETERNAL, &ttyconsdev_cdevsw, 0, 1977 NULL, UID_ROOT, GID_WHEEL, 0600, "console"); 1978} 1979 1980SYSINIT(tty, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyconsdev_init, NULL); 1981 1982void 1983ttyconsdev_select(const char *name) 1984{ 1985 1986 dev_console_filename = name; 1987} 1988 1989/* 1990 * Debugging routines. 1991 */ 1992 1993#include "opt_ddb.h" 1994#ifdef DDB 1995#include <ddb/ddb.h> 1996#include <ddb/db_sym.h> 1997 1998static struct { 1999 int flag; 2000 char val; 2001} ttystates[] = { 2002#if 0 2003 { TF_NOPREFIX, 'N' }, 2004#endif 2005 { TF_INITLOCK, 'I' }, 2006 { TF_CALLOUT, 'C' }, 2007 2008 /* Keep these together -> 'Oi' and 'Oo'. */ 2009 { TF_OPENED, 'O' }, 2010 { TF_OPENED_IN, 'i' }, 2011 { TF_OPENED_OUT, 'o' }, 2012 { TF_OPENED_CONS, 'c' }, 2013 2014 { TF_GONE, 'G' }, 2015 { TF_OPENCLOSE, 'B' }, 2016 { TF_ASYNC, 'Y' }, 2017 { TF_LITERAL, 'L' }, 2018 2019 /* Keep these together -> 'Hi' and 'Ho'. */ 2020 { TF_HIWAT, 'H' }, 2021 { TF_HIWAT_IN, 'i' }, 2022 { TF_HIWAT_OUT, 'o' }, 2023 2024 { TF_STOPPED, 'S' }, 2025 { TF_EXCLUDE, 'X' }, 2026 { TF_BYPASS, 'l' }, 2027 { TF_ZOMBIE, 'Z' }, 2028 { TF_HOOK, 's' }, 2029 2030 /* Keep these together -> 'bi' and 'bo'. */ 2031 { TF_BUSY, 'b' }, 2032 { TF_BUSY_IN, 'i' }, 2033 { TF_BUSY_OUT, 'o' }, 2034 2035 { 0, '\0'}, 2036}; 2037 2038#define TTY_FLAG_BITS \ 2039 "\20\1NOPREFIX\2INITLOCK\3CALLOUT\4OPENED_IN\5OPENED_OUT\6GONE" \ 2040 "\7OPENCLOSE\10ASYNC\11LITERAL\12HIWAT_IN\13HIWAT_OUT\14STOPPED" \ 2041 "\15EXCLUDE\16BYPASS\17ZOMBIE\20HOOK" 2042 2043#define DB_PRINTSYM(name, addr) \ 2044 db_printf("%s " #name ": ", sep); \ 2045 db_printsym((db_addr_t) addr, DB_STGY_ANY); \ 2046 db_printf("\n"); 2047 2048static void 2049_db_show_devsw(const char *sep, const struct ttydevsw *tsw) 2050{ 2051 db_printf("%sdevsw: ", sep); 2052 db_printsym((db_addr_t)tsw, DB_STGY_ANY); 2053 db_printf(" (%p)\n", tsw); 2054 DB_PRINTSYM(open, tsw->tsw_open); 2055 DB_PRINTSYM(close, tsw->tsw_close); 2056 DB_PRINTSYM(outwakeup, tsw->tsw_outwakeup); 2057 DB_PRINTSYM(inwakeup, tsw->tsw_inwakeup); 2058 DB_PRINTSYM(ioctl, tsw->tsw_ioctl); 2059 DB_PRINTSYM(param, tsw->tsw_param); 2060 DB_PRINTSYM(modem, tsw->tsw_modem); 2061 DB_PRINTSYM(mmap, tsw->tsw_mmap); 2062 DB_PRINTSYM(pktnotify, tsw->tsw_pktnotify); 2063 DB_PRINTSYM(free, tsw->tsw_free); 2064} 2065static void 2066_db_show_hooks(const char *sep, const struct ttyhook *th) 2067{ 2068 db_printf("%shook: ", sep); 2069 db_printsym((db_addr_t)th, DB_STGY_ANY); 2070 db_printf(" (%p)\n", th); 2071 if (th == NULL) 2072 return; 2073 DB_PRINTSYM(rint, th->th_rint); 2074 DB_PRINTSYM(rint_bypass, th->th_rint_bypass); 2075 DB_PRINTSYM(rint_done, th->th_rint_done); 2076 DB_PRINTSYM(rint_poll, th->th_rint_poll); 2077 DB_PRINTSYM(getc_inject, th->th_getc_inject); 2078 DB_PRINTSYM(getc_capture, th->th_getc_capture); 2079 DB_PRINTSYM(getc_poll, th->th_getc_poll); 2080 DB_PRINTSYM(close, th->th_close); 2081} 2082 2083static void 2084_db_show_termios(const char *name, const struct termios *t) 2085{ 2086 2087 db_printf("%s: iflag 0x%x oflag 0x%x cflag 0x%x " 2088 "lflag 0x%x ispeed %u ospeed %u\n", name, 2089 t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag, 2090 t->c_ispeed, t->c_ospeed); 2091} 2092 2093/* DDB command to show TTY statistics. */ 2094DB_SHOW_COMMAND(tty, db_show_tty) 2095{ 2096 struct tty *tp; 2097 2098 if (!have_addr) { 2099 db_printf("usage: show tty <addr>\n"); 2100 return; 2101 } 2102 tp = (struct tty *)addr; 2103 2104 db_printf("0x%p: %s\n", tp, tty_devname(tp)); 2105 db_printf("\tmtx: %p\n", tp->t_mtx); 2106 db_printf("\tflags: %b\n", tp->t_flags, TTY_FLAG_BITS); 2107 db_printf("\trevokecnt: %u\n", tp->t_revokecnt); 2108 2109 /* Buffering mechanisms. */ 2110 db_printf("\tinq: %p begin %u linestart %u reprint %u end %u " 2111 "nblocks %u quota %u\n", &tp->t_inq, tp->t_inq.ti_begin, 2112 tp->t_inq.ti_linestart, tp->t_inq.ti_reprint, tp->t_inq.ti_end, 2113 tp->t_inq.ti_nblocks, tp->t_inq.ti_quota); 2114 db_printf("\toutq: %p begin %u end %u nblocks %u quota %u\n", 2115 &tp->t_outq, tp->t_outq.to_begin, tp->t_outq.to_end, 2116 tp->t_outq.to_nblocks, tp->t_outq.to_quota); 2117 db_printf("\tinlow: %zu\n", tp->t_inlow); 2118 db_printf("\toutlow: %zu\n", tp->t_outlow); 2119 _db_show_termios("\ttermios", &tp->t_termios); 2120 db_printf("\twinsize: row %u col %u xpixel %u ypixel %u\n", 2121 tp->t_winsize.ws_row, tp->t_winsize.ws_col, 2122 tp->t_winsize.ws_xpixel, tp->t_winsize.ws_ypixel); 2123 db_printf("\tcolumn: %u\n", tp->t_column); 2124 db_printf("\twritepos: %u\n", tp->t_writepos); 2125 db_printf("\tcompatflags: 0x%x\n", tp->t_compatflags); 2126 2127 /* Init/lock-state devices. */ 2128 _db_show_termios("\ttermios_init_in", &tp->t_termios_init_in); 2129 _db_show_termios("\ttermios_init_out", &tp->t_termios_init_out); 2130 _db_show_termios("\ttermios_lock_in", &tp->t_termios_lock_in); 2131 _db_show_termios("\ttermios_lock_out", &tp->t_termios_lock_out); 2132 2133 /* Hooks */ 2134 _db_show_devsw("\t", tp->t_devsw); 2135 _db_show_hooks("\t", tp->t_hook); 2136 2137 /* Process info. */ 2138 db_printf("\tpgrp: %p gid %d jobc %d\n", tp->t_pgrp, 2139 tp->t_pgrp ? tp->t_pgrp->pg_id : 0, 2140 tp->t_pgrp ? tp->t_pgrp->pg_jobc : 0); 2141 db_printf("\tsession: %p", tp->t_session); 2142 if (tp->t_session != NULL) 2143 db_printf(" count %u leader %p tty %p sid %d login %s", 2144 tp->t_session->s_count, tp->t_session->s_leader, 2145 tp->t_session->s_ttyp, tp->t_session->s_sid, 2146 tp->t_session->s_login); 2147 db_printf("\n"); 2148 db_printf("\tsessioncnt: %u\n", tp->t_sessioncnt); 2149 db_printf("\tdevswsoftc: %p\n", tp->t_devswsoftc); 2150 db_printf("\thooksoftc: %p\n", tp->t_hooksoftc); 2151 db_printf("\tdev: %p\n", tp->t_dev); 2152} 2153 2154/* DDB command to list TTYs. */ 2155DB_SHOW_ALL_COMMAND(ttys, db_show_all_ttys) 2156{ 2157 struct tty *tp; 2158 size_t isiz, osiz; 2159 int i, j; 2160 2161 /* Make the output look like `pstat -t'. */ 2162 db_printf("PTR "); 2163#if defined(__LP64__) 2164 db_printf(" "); 2165#endif 2166 db_printf(" LINE INQ CAN LIN LOW OUTQ USE LOW " 2167 "COL SESS PGID STATE\n"); 2168 2169 TAILQ_FOREACH(tp, &tty_list, t_list) { 2170 isiz = tp->t_inq.ti_nblocks * TTYINQ_DATASIZE; 2171 osiz = tp->t_outq.to_nblocks * TTYOUTQ_DATASIZE; 2172 2173 db_printf("%p %10s %5zu %4u %4u %4zu %5zu %4u %4zu %5u %5d %5d ", 2174 tp, 2175 tty_devname(tp), 2176 isiz, 2177 tp->t_inq.ti_linestart - tp->t_inq.ti_begin, 2178 tp->t_inq.ti_end - tp->t_inq.ti_linestart, 2179 isiz - tp->t_inlow, 2180 osiz, 2181 tp->t_outq.to_end - tp->t_outq.to_begin, 2182 osiz - tp->t_outlow, 2183 MIN(tp->t_column, 99999), 2184 tp->t_session ? tp->t_session->s_sid : 0, 2185 tp->t_pgrp ? tp->t_pgrp->pg_id : 0); 2186 2187 /* Flag bits. */ 2188 for (i = j = 0; ttystates[i].flag; i++) 2189 if (tp->t_flags & ttystates[i].flag) { 2190 db_printf("%c", ttystates[i].val); 2191 j++; 2192 } 2193 if (j == 0) 2194 db_printf("-"); 2195 db_printf("\n"); 2196 } 2197} 2198#endif /* DDB */ 2199