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