1bc093719SEd Schouten /*- 2bc093719SEd Schouten * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> 3bc093719SEd Schouten * All rights reserved. 4bc093719SEd Schouten * 5bc093719SEd Schouten * Portions of this software were developed under sponsorship from Snow 6bc093719SEd Schouten * B.V., the Netherlands. 7bc093719SEd Schouten * 8bc093719SEd Schouten * Redistribution and use in source and binary forms, with or without 9bc093719SEd Schouten * modification, are permitted provided that the following conditions 10bc093719SEd Schouten * are met: 11bc093719SEd Schouten * 1. Redistributions of source code must retain the above copyright 12bc093719SEd Schouten * notice, this list of conditions and the following disclaimer. 13bc093719SEd Schouten * 2. Redistributions in binary form must reproduce the above copyright 14bc093719SEd Schouten * notice, this list of conditions and the following disclaimer in the 15bc093719SEd Schouten * documentation and/or other materials provided with the distribution. 16bc093719SEd Schouten * 17bc093719SEd Schouten * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18bc093719SEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19bc093719SEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20bc093719SEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21bc093719SEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22bc093719SEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23bc093719SEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24bc093719SEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25bc093719SEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26bc093719SEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27bc093719SEd Schouten * SUCH DAMAGE. 28bc093719SEd Schouten */ 29bc093719SEd Schouten 30bc093719SEd Schouten #include <sys/cdefs.h> 31bc093719SEd Schouten __FBSDID("$FreeBSD$"); 32bc093719SEd Schouten 33bc093719SEd Schouten #include <sys/param.h> 34bc093719SEd Schouten #include <sys/fcntl.h> 35bc093719SEd Schouten #include <sys/filio.h> 36bc093719SEd Schouten #include <sys/kernel.h> 37bc093719SEd Schouten #include <sys/signal.h> 38bc093719SEd Schouten #include <sys/sysctl.h> 39bc093719SEd Schouten #include <sys/systm.h> 40bc093719SEd Schouten #include <sys/tty.h> 41bc093719SEd Schouten #include <sys/ttycom.h> 42bc093719SEd Schouten #include <sys/ttydefaults.h> 43bc093719SEd Schouten #include <sys/uio.h> 44bc093719SEd Schouten #include <sys/vnode.h> 45bc093719SEd Schouten 46bc093719SEd Schouten /* 47bc093719SEd Schouten * Standard TTYDISC `termios' line discipline. 48bc093719SEd Schouten */ 49bc093719SEd Schouten 50bc093719SEd Schouten /* Statistics. */ 511d952ed2SEd Schouten static unsigned long tty_nin = 0; 521d952ed2SEd Schouten SYSCTL_ULONG(_kern, OID_AUTO, tty_nin, CTLFLAG_RD, 53bc093719SEd Schouten &tty_nin, 0, "Total amount of bytes received"); 541d952ed2SEd Schouten static unsigned long tty_nout = 0; 551d952ed2SEd Schouten SYSCTL_ULONG(_kern, OID_AUTO, tty_nout, CTLFLAG_RD, 56bc093719SEd Schouten &tty_nout, 0, "Total amount of bytes transmitted"); 57bc093719SEd Schouten 58bc093719SEd Schouten /* termios comparison macro's. */ 59bc093719SEd Schouten #define CMP_CC(v,c) (tp->t_termios.c_cc[v] != _POSIX_VDISABLE && \ 60bc093719SEd Schouten tp->t_termios.c_cc[v] == (c)) 61bc093719SEd Schouten #define CMP_FLAG(field,opt) (tp->t_termios.c_ ## field ## flag & (opt)) 62bc093719SEd Schouten 63bc093719SEd Schouten /* Characters that cannot be modified through c_cc. */ 64bc093719SEd Schouten #define CTAB '\t' 65bc093719SEd Schouten #define CNL '\n' 66bc093719SEd Schouten #define CCR '\r' 67bc093719SEd Schouten 68bc093719SEd Schouten /* Character is a control character. */ 69bc093719SEd Schouten #define CTL_VALID(c) ((c) == 0x7f || (unsigned char)(c) < 0x20) 70bc093719SEd Schouten /* Control character should be processed on echo. */ 71bc093719SEd Schouten #define CTL_ECHO(c,q) (!(q) && ((c) == CERASE2 || (c) == CTAB || \ 72bc093719SEd Schouten (c) == CNL || (c) == CCR)) 73bc093719SEd Schouten /* Control character should be printed using ^X notation. */ 74bc093719SEd Schouten #define CTL_PRINT(c,q) ((c) == 0x7f || ((unsigned char)(c) < 0x20 && \ 75bc093719SEd Schouten ((q) || ((c) != CTAB && (c) != CNL)))) 76bc093719SEd Schouten /* Character is whitespace. */ 77bc093719SEd Schouten #define CTL_WHITE(c) ((c) == ' ' || (c) == CTAB) 78bc093719SEd Schouten /* Character is alphanumeric. */ 79bc093719SEd Schouten #define CTL_ALNUM(c) (((c) >= '0' && (c) <= '9') || \ 80bc093719SEd Schouten ((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) 81bc093719SEd Schouten 82a1215e37SEd Schouten #define TTY_STACKBUF 256 83a1215e37SEd Schouten 84bc093719SEd Schouten void 85bc093719SEd Schouten ttydisc_open(struct tty *tp) 86bc093719SEd Schouten { 87bc093719SEd Schouten ttydisc_optimize(tp); 88bc093719SEd Schouten } 89bc093719SEd Schouten 90bc093719SEd Schouten void 91bc093719SEd Schouten ttydisc_close(struct tty *tp) 92bc093719SEd Schouten { 93bc093719SEd Schouten 94bc093719SEd Schouten /* Clean up our flags when leaving the discipline. */ 95bc093719SEd Schouten tp->t_flags &= ~(TF_STOPPED|TF_HIWAT|TF_ZOMBIE); 96bc093719SEd Schouten 97bc093719SEd Schouten /* POSIX states we should flush when close() is called. */ 98bc093719SEd Schouten ttyinq_flush(&tp->t_inq); 99bc093719SEd Schouten ttyoutq_flush(&tp->t_outq); 100bc093719SEd Schouten 101bc093719SEd Schouten if (!tty_gone(tp)) { 102bc093719SEd Schouten ttydevsw_inwakeup(tp); 103bc093719SEd Schouten ttydevsw_outwakeup(tp); 104bc093719SEd Schouten } 105a1215e37SEd Schouten 106a1215e37SEd Schouten if (ttyhook_hashook(tp, close)) 107a1215e37SEd Schouten ttyhook_close(tp); 108bc093719SEd Schouten } 109bc093719SEd Schouten 110bc093719SEd Schouten static int 111bc093719SEd Schouten ttydisc_read_canonical(struct tty *tp, struct uio *uio, int ioflag) 112bc093719SEd Schouten { 113bc093719SEd Schouten char breakc[4] = { CNL }; /* enough to hold \n, VEOF and VEOL. */ 114bc093719SEd Schouten int error; 115bc093719SEd Schouten size_t clen, flen = 0, n = 1; 116bc093719SEd Schouten unsigned char lastc = _POSIX_VDISABLE; 117bc093719SEd Schouten 118bc093719SEd Schouten #define BREAK_ADD(c) do { \ 119bc093719SEd Schouten if (tp->t_termios.c_cc[c] != _POSIX_VDISABLE) \ 120bc093719SEd Schouten breakc[n++] = tp->t_termios.c_cc[c]; \ 121bc093719SEd Schouten } while (0) 122bc093719SEd Schouten /* Determine which characters we should trigger on. */ 123bc093719SEd Schouten BREAK_ADD(VEOF); 124bc093719SEd Schouten BREAK_ADD(VEOL); 125bc093719SEd Schouten #undef BREAK_ADD 126bc093719SEd Schouten breakc[n] = '\0'; 127bc093719SEd Schouten 128bc093719SEd Schouten do { 129bc093719SEd Schouten /* 130bc093719SEd Schouten * Quite a tricky case: unlike the old TTY 131bc093719SEd Schouten * implementation, this implementation copies data back 132bc093719SEd Schouten * to userspace in large chunks. Unfortunately, we can't 133bc093719SEd Schouten * calculate the line length on beforehand if it crosses 134bc093719SEd Schouten * ttyinq_block boundaries, because multiple reads could 135bc093719SEd Schouten * then make this code read beyond the newline. 136bc093719SEd Schouten * 137bc093719SEd Schouten * This is why we limit the read to: 138bc093719SEd Schouten * - The size the user has requested 139bc093719SEd Schouten * - The blocksize (done in tty_inq.c) 140bc093719SEd Schouten * - The amount of bytes until the newline 141bc093719SEd Schouten * 142bc093719SEd Schouten * This causes the line length to be recalculated after 143bc093719SEd Schouten * each block has been copied to userspace. This will 144bc093719SEd Schouten * cause the TTY layer to return data in chunks using 145bc093719SEd Schouten * the blocksize (except the first and last blocks). 146bc093719SEd Schouten */ 147bc093719SEd Schouten clen = ttyinq_findchar(&tp->t_inq, breakc, uio->uio_resid, 148bc093719SEd Schouten &lastc); 149bc093719SEd Schouten 150bc093719SEd Schouten /* No more data. */ 151bc093719SEd Schouten if (clen == 0) { 152bc093719SEd Schouten if (ioflag & IO_NDELAY) 153bc093719SEd Schouten return (EWOULDBLOCK); 154bc093719SEd Schouten else if (tp->t_flags & TF_ZOMBIE) 155bc093719SEd Schouten return (0); 156bc093719SEd Schouten 157bc093719SEd Schouten error = tty_wait(tp, &tp->t_inwait); 158bc093719SEd Schouten if (error) 159bc093719SEd Schouten return (error); 160bc093719SEd Schouten continue; 161bc093719SEd Schouten } 162bc093719SEd Schouten 163bc093719SEd Schouten /* Don't send the EOF char back to userspace. */ 164bc093719SEd Schouten if (CMP_CC(VEOF, lastc)) 165bc093719SEd Schouten flen = 1; 166bc093719SEd Schouten 167bc093719SEd Schouten MPASS(flen <= clen); 168bc093719SEd Schouten 169bc093719SEd Schouten /* Read and throw away the EOF character. */ 170bc093719SEd Schouten error = ttyinq_read_uio(&tp->t_inq, tp, uio, clen, flen); 171bc093719SEd Schouten if (error) 172bc093719SEd Schouten return (error); 173bc093719SEd Schouten 174bc093719SEd Schouten } while (uio->uio_resid > 0 && lastc == _POSIX_VDISABLE); 175bc093719SEd Schouten 176bc093719SEd Schouten return (0); 177bc093719SEd Schouten } 178bc093719SEd Schouten 179bc093719SEd Schouten static int 180bc093719SEd Schouten ttydisc_read_raw_no_timer(struct tty *tp, struct uio *uio, int ioflag) 181bc093719SEd Schouten { 182bc093719SEd Schouten size_t vmin = tp->t_termios.c_cc[VMIN]; 183*526d0bd5SKonstantin Belousov ssize_t oresid = uio->uio_resid; 184bc093719SEd Schouten int error; 185bc093719SEd Schouten 186bc093719SEd Schouten MPASS(tp->t_termios.c_cc[VTIME] == 0); 187bc093719SEd Schouten 188bc093719SEd Schouten /* 189bc093719SEd Schouten * This routine implements the easy cases of read()s while in 190bc093719SEd Schouten * non-canonical mode, namely case B and D, where we don't have 191bc093719SEd Schouten * any timers at all. 192bc093719SEd Schouten */ 193bc093719SEd Schouten 194bc093719SEd Schouten for (;;) { 195bc093719SEd Schouten error = ttyinq_read_uio(&tp->t_inq, tp, uio, 196bc093719SEd Schouten uio->uio_resid, 0); 197bc093719SEd Schouten if (error) 198bc093719SEd Schouten return (error); 199bc093719SEd Schouten if (uio->uio_resid == 0 || (oresid - uio->uio_resid) >= vmin) 200bc093719SEd Schouten return (0); 201bc093719SEd Schouten 202bc093719SEd Schouten /* We have to wait for more. */ 203bc093719SEd Schouten if (ioflag & IO_NDELAY) 204bc093719SEd Schouten return (EWOULDBLOCK); 205bc093719SEd Schouten else if (tp->t_flags & TF_ZOMBIE) 206bc093719SEd Schouten return (0); 207bc093719SEd Schouten 208bc093719SEd Schouten error = tty_wait(tp, &tp->t_inwait); 209bc093719SEd Schouten if (error) 210bc093719SEd Schouten return (error); 211bc093719SEd Schouten } 212bc093719SEd Schouten } 213bc093719SEd Schouten 214bc093719SEd Schouten static int 215bc093719SEd Schouten ttydisc_read_raw_read_timer(struct tty *tp, struct uio *uio, int ioflag, 216bc093719SEd Schouten int oresid) 217bc093719SEd Schouten { 218bc093719SEd Schouten size_t vmin = MAX(tp->t_termios.c_cc[VMIN], 1); 219bc093719SEd Schouten unsigned int vtime = tp->t_termios.c_cc[VTIME]; 220bc093719SEd Schouten struct timeval end, now, left; 221bc093719SEd Schouten int error, hz; 222bc093719SEd Schouten 223bc093719SEd Schouten MPASS(tp->t_termios.c_cc[VTIME] != 0); 224bc093719SEd Schouten 225bc093719SEd Schouten /* Determine when the read should be expired. */ 226bc093719SEd Schouten end.tv_sec = vtime / 10; 227bc093719SEd Schouten end.tv_usec = (vtime % 10) * 100000; 228bc093719SEd Schouten getmicrotime(&now); 229bc093719SEd Schouten timevaladd(&end, &now); 230bc093719SEd Schouten 231bc093719SEd Schouten for (;;) { 232bc093719SEd Schouten error = ttyinq_read_uio(&tp->t_inq, tp, uio, 233bc093719SEd Schouten uio->uio_resid, 0); 234bc093719SEd Schouten if (error) 235bc093719SEd Schouten return (error); 236bc093719SEd Schouten if (uio->uio_resid == 0 || (oresid - uio->uio_resid) >= vmin) 237bc093719SEd Schouten return (0); 238bc093719SEd Schouten 239bc093719SEd Schouten /* Calculate how long we should wait. */ 240bc093719SEd Schouten getmicrotime(&now); 241bc093719SEd Schouten if (timevalcmp(&now, &end, >)) 242bc093719SEd Schouten return (0); 243bc093719SEd Schouten left = end; 244bc093719SEd Schouten timevalsub(&left, &now); 245bc093719SEd Schouten hz = tvtohz(&left); 246bc093719SEd Schouten 247bc093719SEd Schouten /* 248bc093719SEd Schouten * We have to wait for more. If the timer expires, we 249bc093719SEd Schouten * should return a 0-byte read. 250bc093719SEd Schouten */ 251bc093719SEd Schouten if (ioflag & IO_NDELAY) 252bc093719SEd Schouten return (EWOULDBLOCK); 253bc093719SEd Schouten else if (tp->t_flags & TF_ZOMBIE) 254bc093719SEd Schouten return (0); 255bc093719SEd Schouten 256bc093719SEd Schouten error = tty_timedwait(tp, &tp->t_inwait, hz); 257bc093719SEd Schouten if (error) 258bc093719SEd Schouten return (error == EWOULDBLOCK ? 0 : error); 259bc093719SEd Schouten } 260bc093719SEd Schouten 261bc093719SEd Schouten return (0); 262bc093719SEd Schouten } 263bc093719SEd Schouten 264bc093719SEd Schouten static int 265bc093719SEd Schouten ttydisc_read_raw_interbyte_timer(struct tty *tp, struct uio *uio, int ioflag) 266bc093719SEd Schouten { 267bc093719SEd Schouten size_t vmin = tp->t_termios.c_cc[VMIN]; 268*526d0bd5SKonstantin Belousov ssize_t oresid = uio->uio_resid; 269bc093719SEd Schouten int error; 270bc093719SEd Schouten 271bc093719SEd Schouten MPASS(tp->t_termios.c_cc[VMIN] != 0); 272bc093719SEd Schouten MPASS(tp->t_termios.c_cc[VTIME] != 0); 273bc093719SEd Schouten 274bc093719SEd Schouten /* 275bc093719SEd Schouten * When using the interbyte timer, the timer should be started 276bc093719SEd Schouten * after the first byte has been received. We just call into the 277bc093719SEd Schouten * generic read timer code after we've received the first byte. 278bc093719SEd Schouten */ 279bc093719SEd Schouten 280bc093719SEd Schouten for (;;) { 281bc093719SEd Schouten error = ttyinq_read_uio(&tp->t_inq, tp, uio, 282bc093719SEd Schouten uio->uio_resid, 0); 283bc093719SEd Schouten if (error) 284bc093719SEd Schouten return (error); 285bc093719SEd Schouten if (uio->uio_resid == 0 || (oresid - uio->uio_resid) >= vmin) 286bc093719SEd Schouten return (0); 287bc093719SEd Schouten 288bc093719SEd Schouten /* 289bc093719SEd Schouten * Not enough data, but we did receive some, which means 290bc093719SEd Schouten * we'll now start using the interbyte timer. 291bc093719SEd Schouten */ 292bc093719SEd Schouten if (oresid != uio->uio_resid) 293bc093719SEd Schouten break; 294bc093719SEd Schouten 295bc093719SEd Schouten /* We have to wait for more. */ 296bc093719SEd Schouten if (ioflag & IO_NDELAY) 297bc093719SEd Schouten return (EWOULDBLOCK); 298bc093719SEd Schouten else if (tp->t_flags & TF_ZOMBIE) 299bc093719SEd Schouten return (0); 300bc093719SEd Schouten 301bc093719SEd Schouten error = tty_wait(tp, &tp->t_inwait); 302bc093719SEd Schouten if (error) 303bc093719SEd Schouten return (error); 304bc093719SEd Schouten } 305bc093719SEd Schouten 306bc093719SEd Schouten return ttydisc_read_raw_read_timer(tp, uio, ioflag, oresid); 307bc093719SEd Schouten } 308bc093719SEd Schouten 309bc093719SEd Schouten int 310bc093719SEd Schouten ttydisc_read(struct tty *tp, struct uio *uio, int ioflag) 311bc093719SEd Schouten { 312bc093719SEd Schouten int error; 313bc093719SEd Schouten 314bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 315bc093719SEd Schouten 316bc093719SEd Schouten if (uio->uio_resid == 0) 317bc093719SEd Schouten return (0); 318bc093719SEd Schouten 319bc093719SEd Schouten if (CMP_FLAG(l, ICANON)) 320bc093719SEd Schouten error = ttydisc_read_canonical(tp, uio, ioflag); 321bc093719SEd Schouten else if (tp->t_termios.c_cc[VTIME] == 0) 322bc093719SEd Schouten error = ttydisc_read_raw_no_timer(tp, uio, ioflag); 323bc093719SEd Schouten else if (tp->t_termios.c_cc[VMIN] == 0) 324bc093719SEd Schouten error = ttydisc_read_raw_read_timer(tp, uio, ioflag, 325bc093719SEd Schouten uio->uio_resid); 326bc093719SEd Schouten else 327bc093719SEd Schouten error = ttydisc_read_raw_interbyte_timer(tp, uio, ioflag); 328bc093719SEd Schouten 329a15ec0a5SEd Schouten if (ttyinq_bytesleft(&tp->t_inq) >= tp->t_inlow || 330a15ec0a5SEd Schouten ttyinq_bytescanonicalized(&tp->t_inq) == 0) { 331bc093719SEd Schouten /* Unset the input watermark when we've got enough space. */ 332bc093719SEd Schouten tty_hiwat_in_unblock(tp); 333bc093719SEd Schouten } 334bc093719SEd Schouten 335bc093719SEd Schouten return (error); 336bc093719SEd Schouten } 337bc093719SEd Schouten 338bc093719SEd Schouten static __inline unsigned int 339bc093719SEd Schouten ttydisc_findchar(const char *obstart, unsigned int oblen) 340bc093719SEd Schouten { 341bc093719SEd Schouten const char *c = obstart; 342bc093719SEd Schouten 343bc093719SEd Schouten while (oblen--) { 344bc093719SEd Schouten if (CTL_VALID(*c)) 345bc093719SEd Schouten break; 346bc093719SEd Schouten c++; 347bc093719SEd Schouten } 348bc093719SEd Schouten 349bc093719SEd Schouten return (c - obstart); 350bc093719SEd Schouten } 351bc093719SEd Schouten 352bc093719SEd Schouten static int 353bc093719SEd Schouten ttydisc_write_oproc(struct tty *tp, char c) 354bc093719SEd Schouten { 355bc093719SEd Schouten unsigned int scnt, error; 356bc093719SEd Schouten 357bc093719SEd Schouten MPASS(CMP_FLAG(o, OPOST)); 358bc093719SEd Schouten MPASS(CTL_VALID(c)); 359bc093719SEd Schouten 360bc093719SEd Schouten #define PRINT_NORMAL() ttyoutq_write_nofrag(&tp->t_outq, &c, 1) 361bc093719SEd Schouten switch (c) { 362bc093719SEd Schouten case CEOF: 363bc093719SEd Schouten /* End-of-text dropping. */ 364bc093719SEd Schouten if (CMP_FLAG(o, ONOEOT)) 365bc093719SEd Schouten return (0); 366bc093719SEd Schouten return PRINT_NORMAL(); 367bc093719SEd Schouten 368bc093719SEd Schouten case CERASE2: 369bc093719SEd Schouten /* Handle backspace to fix tab expansion. */ 370bc093719SEd Schouten if (PRINT_NORMAL() != 0) 371bc093719SEd Schouten return (-1); 372bc093719SEd Schouten if (tp->t_column > 0) 373bc093719SEd Schouten tp->t_column--; 374bc093719SEd Schouten return (0); 375bc093719SEd Schouten 376bc093719SEd Schouten case CTAB: 377bc093719SEd Schouten /* Tab expansion. */ 378bc093719SEd Schouten scnt = 8 - (tp->t_column & 7); 379bc093719SEd Schouten if (CMP_FLAG(o, TAB3)) { 380bc093719SEd Schouten error = ttyoutq_write_nofrag(&tp->t_outq, 381bc093719SEd Schouten " ", scnt); 382bc093719SEd Schouten } else { 383bc093719SEd Schouten error = PRINT_NORMAL(); 384bc093719SEd Schouten } 385bc093719SEd Schouten if (error) 386bc093719SEd Schouten return (-1); 387bc093719SEd Schouten 388bc093719SEd Schouten tp->t_column += scnt; 389bc093719SEd Schouten MPASS((tp->t_column % 8) == 0); 390bc093719SEd Schouten return (0); 391bc093719SEd Schouten 392bc093719SEd Schouten case CNL: 393bc093719SEd Schouten /* Newline conversion. */ 394bc093719SEd Schouten if (CMP_FLAG(o, ONLCR)) { 395bc093719SEd Schouten /* Convert \n to \r\n. */ 396bc093719SEd Schouten error = ttyoutq_write_nofrag(&tp->t_outq, "\r\n", 2); 397bc093719SEd Schouten } else { 398bc093719SEd Schouten error = PRINT_NORMAL(); 399bc093719SEd Schouten } 400bc093719SEd Schouten if (error) 401bc093719SEd Schouten return (-1); 402bc093719SEd Schouten 403bc093719SEd Schouten if (CMP_FLAG(o, ONLCR|ONLRET)) { 404bc093719SEd Schouten tp->t_column = tp->t_writepos = 0; 405bc093719SEd Schouten ttyinq_reprintpos_set(&tp->t_inq); 406bc093719SEd Schouten } 407bc093719SEd Schouten return (0); 408bc093719SEd Schouten 409bc093719SEd Schouten case CCR: 410bc093719SEd Schouten /* Carriage return to newline conversion. */ 411bc093719SEd Schouten if (CMP_FLAG(o, OCRNL)) 412bc093719SEd Schouten c = CNL; 413bc093719SEd Schouten /* Omit carriage returns on column 0. */ 414bc093719SEd Schouten if (CMP_FLAG(o, ONOCR) && tp->t_column == 0) 415bc093719SEd Schouten return (0); 416bc093719SEd Schouten if (PRINT_NORMAL() != 0) 417bc093719SEd Schouten return (-1); 418bc093719SEd Schouten 419bc093719SEd Schouten tp->t_column = tp->t_writepos = 0; 420bc093719SEd Schouten ttyinq_reprintpos_set(&tp->t_inq); 421bc093719SEd Schouten return (0); 422bc093719SEd Schouten } 423bc093719SEd Schouten 424bc093719SEd Schouten /* 425bc093719SEd Schouten * Invisible control character. Print it, but don't 426bc093719SEd Schouten * increase the column count. 427bc093719SEd Schouten */ 428bc093719SEd Schouten return PRINT_NORMAL(); 429bc093719SEd Schouten #undef PRINT_NORMAL 430bc093719SEd Schouten } 431bc093719SEd Schouten 432bc093719SEd Schouten /* 433bc093719SEd Schouten * Just like the old TTY implementation, we need to copy data in chunks 434bc093719SEd Schouten * into a temporary buffer. One of the reasons why we need to do this, 435bc093719SEd Schouten * is because output processing (only TAB3 though) may allow the buffer 436bc093719SEd Schouten * to grow eight times. 437bc093719SEd Schouten */ 438bc093719SEd Schouten int 439bc093719SEd Schouten ttydisc_write(struct tty *tp, struct uio *uio, int ioflag) 440bc093719SEd Schouten { 441a1215e37SEd Schouten char ob[TTY_STACKBUF]; 442bc093719SEd Schouten char *obstart; 443bc093719SEd Schouten int error = 0; 444bc093719SEd Schouten unsigned int oblen = 0; 445bc093719SEd Schouten 446bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 447bc093719SEd Schouten 448bc093719SEd Schouten if (tp->t_flags & TF_ZOMBIE) 449bc093719SEd Schouten return (EIO); 450bc093719SEd Schouten 451bc093719SEd Schouten /* 452bc093719SEd Schouten * We don't need to check whether the process is the foreground 453bc093719SEd Schouten * process group or if we have a carrier. This is already done 454bc093719SEd Schouten * in ttydev_write(). 455bc093719SEd Schouten */ 456bc093719SEd Schouten 457bc093719SEd Schouten while (uio->uio_resid > 0) { 458bc093719SEd Schouten unsigned int nlen; 459bc093719SEd Schouten 460bc093719SEd Schouten MPASS(oblen == 0); 461bc093719SEd Schouten 462bc093719SEd Schouten /* Step 1: read data. */ 463bc093719SEd Schouten obstart = ob; 464bc093719SEd Schouten nlen = MIN(uio->uio_resid, sizeof ob); 46587fe0fa8SEd Schouten tty_unlock(tp); 466bc093719SEd Schouten error = uiomove(ob, nlen, uio); 46787fe0fa8SEd Schouten tty_lock(tp); 468bc093719SEd Schouten if (error != 0) 469bc093719SEd Schouten break; 470bc093719SEd Schouten oblen = nlen; 471bc093719SEd Schouten 472bc093719SEd Schouten if (tty_gone(tp)) { 473bc093719SEd Schouten error = ENXIO; 474bc093719SEd Schouten break; 475bc093719SEd Schouten } 476bc093719SEd Schouten 477bc093719SEd Schouten MPASS(oblen > 0); 478bc093719SEd Schouten 479bc093719SEd Schouten /* Step 2: process data. */ 480bc093719SEd Schouten do { 481bc093719SEd Schouten unsigned int plen, wlen; 482bc093719SEd Schouten 483bc093719SEd Schouten /* Search for special characters for post processing. */ 484bc093719SEd Schouten if (CMP_FLAG(o, OPOST)) { 485bc093719SEd Schouten plen = ttydisc_findchar(obstart, oblen); 486bc093719SEd Schouten } else { 487bc093719SEd Schouten plen = oblen; 488bc093719SEd Schouten } 489bc093719SEd Schouten 490bc093719SEd Schouten if (plen == 0) { 491bc093719SEd Schouten /* 492bc093719SEd Schouten * We're going to process a character 493bc093719SEd Schouten * that needs processing 494bc093719SEd Schouten */ 495bc093719SEd Schouten if (ttydisc_write_oproc(tp, *obstart) == 0) { 496bc093719SEd Schouten obstart++; 497bc093719SEd Schouten oblen--; 498bc093719SEd Schouten 499bc093719SEd Schouten tp->t_writepos = tp->t_column; 500bc093719SEd Schouten ttyinq_reprintpos_set(&tp->t_inq); 501bc093719SEd Schouten continue; 502bc093719SEd Schouten } 503bc093719SEd Schouten } else { 504bc093719SEd Schouten /* We're going to write regular data. */ 505bc093719SEd Schouten wlen = ttyoutq_write(&tp->t_outq, obstart, plen); 506bc093719SEd Schouten obstart += wlen; 507bc093719SEd Schouten oblen -= wlen; 508bc093719SEd Schouten tp->t_column += wlen; 509bc093719SEd Schouten 510bc093719SEd Schouten tp->t_writepos = tp->t_column; 511bc093719SEd Schouten ttyinq_reprintpos_set(&tp->t_inq); 512bc093719SEd Schouten 513bc093719SEd Schouten if (wlen == plen) 514bc093719SEd Schouten continue; 515bc093719SEd Schouten } 516bc093719SEd Schouten 517bc093719SEd Schouten /* Watermark reached. Try to sleep. */ 518bc093719SEd Schouten tp->t_flags |= TF_HIWAT_OUT; 519bc093719SEd Schouten 520bc093719SEd Schouten if (ioflag & IO_NDELAY) { 521bc093719SEd Schouten error = EWOULDBLOCK; 522bc093719SEd Schouten goto done; 523bc093719SEd Schouten } 524bc093719SEd Schouten 525bc093719SEd Schouten /* 526bc093719SEd Schouten * The driver may write back the data 527bc093719SEd Schouten * synchronously. Be sure to check the high 528bc093719SEd Schouten * water mark before going to sleep. 529bc093719SEd Schouten */ 530bc093719SEd Schouten ttydevsw_outwakeup(tp); 531bc093719SEd Schouten if ((tp->t_flags & TF_HIWAT_OUT) == 0) 532bc093719SEd Schouten continue; 533bc093719SEd Schouten 534bc093719SEd Schouten error = tty_wait(tp, &tp->t_outwait); 535bc093719SEd Schouten if (error) 536bc093719SEd Schouten goto done; 537bc093719SEd Schouten 538bc093719SEd Schouten if (tp->t_flags & TF_ZOMBIE) { 539bc093719SEd Schouten error = EIO; 540bc093719SEd Schouten goto done; 541bc093719SEd Schouten } 542bc093719SEd Schouten } while (oblen > 0); 543bc093719SEd Schouten } 544bc093719SEd Schouten 545bc093719SEd Schouten done: 546856ebf85SChristian S.J. Peron if (!tty_gone(tp)) 547bc093719SEd Schouten ttydevsw_outwakeup(tp); 548bc093719SEd Schouten 549bc093719SEd Schouten /* 550bc093719SEd Schouten * Add the amount of bytes that we didn't process back to the 551bc093719SEd Schouten * uio counters. We need to do this to make sure write() doesn't 552bc093719SEd Schouten * count the bytes we didn't store in the queue. 553bc093719SEd Schouten */ 554bc093719SEd Schouten uio->uio_resid += oblen; 555bc093719SEd Schouten return (error); 556bc093719SEd Schouten } 557bc093719SEd Schouten 558bc093719SEd Schouten void 559bc093719SEd Schouten ttydisc_optimize(struct tty *tp) 560bc093719SEd Schouten { 561bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 562bc093719SEd Schouten 56314358b0fSEd Schouten if (ttyhook_hashook(tp, rint_bypass)) { 56414358b0fSEd Schouten tp->t_flags |= TF_BYPASS; 56514358b0fSEd Schouten } else if (ttyhook_hashook(tp, rint)) { 56614358b0fSEd Schouten tp->t_flags &= ~TF_BYPASS; 56714358b0fSEd Schouten } else if (!CMP_FLAG(i, ICRNL|IGNCR|IMAXBEL|INLCR|ISTRIP|IXON) && 568bc093719SEd Schouten (!CMP_FLAG(i, BRKINT) || CMP_FLAG(i, IGNBRK)) && 569bc093719SEd Schouten (!CMP_FLAG(i, PARMRK) || 570bc093719SEd Schouten CMP_FLAG(i, IGNPAR|IGNBRK) == (IGNPAR|IGNBRK)) && 57114358b0fSEd Schouten !CMP_FLAG(l, ECHO|ICANON|IEXTEN|ISIG|PENDIN)) { 572bc093719SEd Schouten tp->t_flags |= TF_BYPASS; 573bc093719SEd Schouten } else { 574bc093719SEd Schouten tp->t_flags &= ~TF_BYPASS; 575bc093719SEd Schouten } 576bc093719SEd Schouten } 577bc093719SEd Schouten 578bc093719SEd Schouten void 579bc093719SEd Schouten ttydisc_modem(struct tty *tp, int open) 580bc093719SEd Schouten { 581bc093719SEd Schouten 582bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 583bc093719SEd Schouten 584bc093719SEd Schouten if (open) 585bc093719SEd Schouten cv_broadcast(&tp->t_dcdwait); 586bc093719SEd Schouten 587bc093719SEd Schouten /* 588bc093719SEd Schouten * Ignore modem status lines when CLOCAL is turned on, but don't 589bc093719SEd Schouten * enter the zombie state when the TTY isn't opened, because 590bc093719SEd Schouten * that would cause the TTY to be in zombie state after being 591bc093719SEd Schouten * opened. 592bc093719SEd Schouten */ 593bc093719SEd Schouten if (!tty_opened(tp) || CMP_FLAG(c, CLOCAL)) 594bc093719SEd Schouten return; 595bc093719SEd Schouten 596bc093719SEd Schouten if (open == 0) { 597bc093719SEd Schouten /* 598bc093719SEd Schouten * Lost carrier. 599bc093719SEd Schouten */ 600bc093719SEd Schouten tp->t_flags |= TF_ZOMBIE; 601bc093719SEd Schouten 602bc093719SEd Schouten tty_signal_sessleader(tp, SIGHUP); 603bc093719SEd Schouten tty_flush(tp, FREAD|FWRITE); 604bc093719SEd Schouten } else { 605bc093719SEd Schouten /* 606bc093719SEd Schouten * Carrier is back again. 607bc093719SEd Schouten */ 608bc093719SEd Schouten 609bc093719SEd Schouten /* XXX: what should we do here? */ 610bc093719SEd Schouten } 611bc093719SEd Schouten } 612bc093719SEd Schouten 613bc093719SEd Schouten static int 614bc093719SEd Schouten ttydisc_echo_force(struct tty *tp, char c, int quote) 615bc093719SEd Schouten { 616bc093719SEd Schouten 617bc093719SEd Schouten if (CMP_FLAG(o, OPOST) && CTL_ECHO(c, quote)) { 618bc093719SEd Schouten /* 619bc093719SEd Schouten * Only perform postprocessing when OPOST is turned on 620bc093719SEd Schouten * and the character is an unquoted BS/TB/NL/CR. 621bc093719SEd Schouten */ 622bc093719SEd Schouten return ttydisc_write_oproc(tp, c); 623bc093719SEd Schouten } else if (CMP_FLAG(l, ECHOCTL) && CTL_PRINT(c, quote)) { 624bc093719SEd Schouten /* 625bc093719SEd Schouten * Only use ^X notation when ECHOCTL is turned on and 626bc093719SEd Schouten * we've got an quoted control character. 62739410373SEd Schouten * 62839410373SEd Schouten * Print backspaces when echoing an end-of-file. 629bc093719SEd Schouten */ 63039410373SEd Schouten char ob[4] = "^?\b\b"; 631bc093719SEd Schouten 632bc093719SEd Schouten /* Print ^X notation. */ 633bc093719SEd Schouten if (c != 0x7f) 634bc093719SEd Schouten ob[1] = c + 'A' - 1; 635bc093719SEd Schouten 63639410373SEd Schouten if (!quote && CMP_CC(VEOF, c)) { 63739410373SEd Schouten return ttyoutq_write_nofrag(&tp->t_outq, ob, 4); 63839410373SEd Schouten } else { 639bc093719SEd Schouten tp->t_column += 2; 640bc093719SEd Schouten return ttyoutq_write_nofrag(&tp->t_outq, ob, 2); 64139410373SEd Schouten } 642bc093719SEd Schouten } else { 643bc093719SEd Schouten /* Can just be printed. */ 644bc093719SEd Schouten tp->t_column++; 645bc093719SEd Schouten return ttyoutq_write_nofrag(&tp->t_outq, &c, 1); 646bc093719SEd Schouten } 647bc093719SEd Schouten } 648bc093719SEd Schouten 649bc093719SEd Schouten static int 650bc093719SEd Schouten ttydisc_echo(struct tty *tp, char c, int quote) 651bc093719SEd Schouten { 652bc093719SEd Schouten 653bc093719SEd Schouten /* 654bc093719SEd Schouten * Only echo characters when ECHO is turned on, or ECHONL when 655bc093719SEd Schouten * the character is an unquoted newline. 656bc093719SEd Schouten */ 657bc093719SEd Schouten if (!CMP_FLAG(l, ECHO) && 658bc093719SEd Schouten (!CMP_FLAG(l, ECHONL) || c != CNL || quote)) 659bc093719SEd Schouten return (0); 660bc093719SEd Schouten 661bc093719SEd Schouten return ttydisc_echo_force(tp, c, quote); 662bc093719SEd Schouten } 663bc093719SEd Schouten 664bc093719SEd Schouten static void 665bc093719SEd Schouten ttydisc_reprint_char(void *d, char c, int quote) 666bc093719SEd Schouten { 667bc093719SEd Schouten struct tty *tp = d; 668bc093719SEd Schouten 669bc093719SEd Schouten ttydisc_echo(tp, c, quote); 670bc093719SEd Schouten } 671bc093719SEd Schouten 672bc093719SEd Schouten static void 673bc093719SEd Schouten ttydisc_reprint(struct tty *tp) 674bc093719SEd Schouten { 675bc093719SEd Schouten cc_t c; 676bc093719SEd Schouten 677bc093719SEd Schouten /* Print ^R\n, followed by the line. */ 678bc093719SEd Schouten c = tp->t_termios.c_cc[VREPRINT]; 679bc093719SEd Schouten if (c != _POSIX_VDISABLE) 680bc093719SEd Schouten ttydisc_echo(tp, c, 0); 681bc093719SEd Schouten ttydisc_echo(tp, CNL, 0); 682bc093719SEd Schouten ttyinq_reprintpos_reset(&tp->t_inq); 683bc093719SEd Schouten 684bc093719SEd Schouten ttyinq_line_iterate_from_linestart(&tp->t_inq, ttydisc_reprint_char, tp); 685bc093719SEd Schouten } 686bc093719SEd Schouten 687bc093719SEd Schouten struct ttydisc_recalc_length { 688bc093719SEd Schouten struct tty *tp; 689bc093719SEd Schouten unsigned int curlen; 690bc093719SEd Schouten }; 691bc093719SEd Schouten 692bc093719SEd Schouten static void 693bc093719SEd Schouten ttydisc_recalc_charlength(void *d, char c, int quote) 694bc093719SEd Schouten { 695bc093719SEd Schouten struct ttydisc_recalc_length *data = d; 696bc093719SEd Schouten struct tty *tp = data->tp; 697bc093719SEd Schouten 698bc093719SEd Schouten if (CTL_PRINT(c, quote)) { 699bc093719SEd Schouten if (CMP_FLAG(l, ECHOCTL)) 700bc093719SEd Schouten data->curlen += 2; 701bc093719SEd Schouten } else if (c == CTAB) { 702bc093719SEd Schouten data->curlen += 8 - (data->curlen & 7); 703bc093719SEd Schouten } else { 704bc093719SEd Schouten data->curlen++; 705bc093719SEd Schouten } 706bc093719SEd Schouten } 707bc093719SEd Schouten 708bc093719SEd Schouten static unsigned int 709bc093719SEd Schouten ttydisc_recalc_linelength(struct tty *tp) 710bc093719SEd Schouten { 711bc093719SEd Schouten struct ttydisc_recalc_length data = { tp, tp->t_writepos }; 712bc093719SEd Schouten 713bc093719SEd Schouten ttyinq_line_iterate_from_reprintpos(&tp->t_inq, 714bc093719SEd Schouten ttydisc_recalc_charlength, &data); 715bc093719SEd Schouten return (data.curlen); 716bc093719SEd Schouten } 717bc093719SEd Schouten 718bc093719SEd Schouten static int 719bc093719SEd Schouten ttydisc_rubchar(struct tty *tp) 720bc093719SEd Schouten { 721bc093719SEd Schouten char c; 722bc093719SEd Schouten int quote; 723bc093719SEd Schouten unsigned int prevpos, tablen; 724bc093719SEd Schouten 725bc093719SEd Schouten if (ttyinq_peekchar(&tp->t_inq, &c, "e) != 0) 726bc093719SEd Schouten return (-1); 727bc093719SEd Schouten ttyinq_unputchar(&tp->t_inq); 728bc093719SEd Schouten 729bc093719SEd Schouten if (CMP_FLAG(l, ECHO)) { 730bc093719SEd Schouten /* 731bc093719SEd Schouten * Remove the character from the screen. This is even 732bc093719SEd Schouten * safe for characters that span multiple characters 733bc093719SEd Schouten * (tabs, quoted, etc). 734bc093719SEd Schouten */ 735bc093719SEd Schouten if (tp->t_writepos >= tp->t_column) { 736bc093719SEd Schouten /* Retype the sentence. */ 737bc093719SEd Schouten ttydisc_reprint(tp); 738bc093719SEd Schouten } else if (CMP_FLAG(l, ECHOE)) { 739bc093719SEd Schouten if (CTL_PRINT(c, quote)) { 740bc093719SEd Schouten /* Remove ^X formatted chars. */ 741bc093719SEd Schouten if (CMP_FLAG(l, ECHOCTL)) { 742bc093719SEd Schouten tp->t_column -= 2; 743bc093719SEd Schouten ttyoutq_write_nofrag(&tp->t_outq, 744bc093719SEd Schouten "\b\b \b\b", 6); 745bc093719SEd Schouten } 746bc093719SEd Schouten } else if (c == ' ') { 747bc093719SEd Schouten /* Space character needs no rubbing. */ 748bc093719SEd Schouten tp->t_column -= 1; 749bc093719SEd Schouten ttyoutq_write_nofrag(&tp->t_outq, "\b", 1); 750bc093719SEd Schouten } else if (c == CTAB) { 751bc093719SEd Schouten /* 752bc093719SEd Schouten * Making backspace work with tabs is 753bc093719SEd Schouten * quite hard. Recalculate the length of 754bc093719SEd Schouten * this character and remove it. 755bc093719SEd Schouten * 756bc093719SEd Schouten * Because terminal settings could be 757bc093719SEd Schouten * changed while the line is being 758bc093719SEd Schouten * inserted, the calculations don't have 759bc093719SEd Schouten * to be correct. Make sure we keep the 760bc093719SEd Schouten * tab length within proper bounds. 761bc093719SEd Schouten */ 762bc093719SEd Schouten prevpos = ttydisc_recalc_linelength(tp); 763bc093719SEd Schouten if (prevpos >= tp->t_column) 764bc093719SEd Schouten tablen = 1; 765bc093719SEd Schouten else 766bc093719SEd Schouten tablen = tp->t_column - prevpos; 767bc093719SEd Schouten if (tablen > 8) 768bc093719SEd Schouten tablen = 8; 769bc093719SEd Schouten 770bc093719SEd Schouten tp->t_column = prevpos; 771bc093719SEd Schouten ttyoutq_write_nofrag(&tp->t_outq, 772bc093719SEd Schouten "\b\b\b\b\b\b\b\b", tablen); 773bc093719SEd Schouten return (0); 774bc093719SEd Schouten } else { 775bc093719SEd Schouten /* 776bc093719SEd Schouten * Remove a regular character by 777bc093719SEd Schouten * punching a space over it. 778bc093719SEd Schouten */ 779bc093719SEd Schouten tp->t_column -= 1; 780bc093719SEd Schouten ttyoutq_write_nofrag(&tp->t_outq, "\b \b", 3); 781bc093719SEd Schouten } 782bc093719SEd Schouten } else { 783bc093719SEd Schouten /* Don't print spaces. */ 784bc093719SEd Schouten ttydisc_echo(tp, tp->t_termios.c_cc[VERASE], 0); 785bc093719SEd Schouten } 786bc093719SEd Schouten } 787bc093719SEd Schouten 788bc093719SEd Schouten return (0); 789bc093719SEd Schouten } 790bc093719SEd Schouten 791bc093719SEd Schouten static void 792bc093719SEd Schouten ttydisc_rubword(struct tty *tp) 793bc093719SEd Schouten { 794bc093719SEd Schouten char c; 795bc093719SEd Schouten int quote, alnum; 796bc093719SEd Schouten 797bc093719SEd Schouten /* Strip whitespace first. */ 798bc093719SEd Schouten for (;;) { 799bc093719SEd Schouten if (ttyinq_peekchar(&tp->t_inq, &c, "e) != 0) 800bc093719SEd Schouten return; 801bc093719SEd Schouten if (!CTL_WHITE(c)) 802bc093719SEd Schouten break; 803bc093719SEd Schouten ttydisc_rubchar(tp); 804bc093719SEd Schouten } 805bc093719SEd Schouten 806bc093719SEd Schouten /* 807bc093719SEd Schouten * Record whether the last character from the previous iteration 808bc093719SEd Schouten * was alphanumeric or not. We need this to implement ALTWERASE. 809bc093719SEd Schouten */ 810bc093719SEd Schouten alnum = CTL_ALNUM(c); 811bc093719SEd Schouten for (;;) { 812bc093719SEd Schouten ttydisc_rubchar(tp); 813bc093719SEd Schouten 814bc093719SEd Schouten if (ttyinq_peekchar(&tp->t_inq, &c, "e) != 0) 815bc093719SEd Schouten return; 816bc093719SEd Schouten if (CTL_WHITE(c)) 817bc093719SEd Schouten return; 818bc093719SEd Schouten if (CMP_FLAG(l, ALTWERASE) && CTL_ALNUM(c) != alnum) 819bc093719SEd Schouten return; 820bc093719SEd Schouten } 821bc093719SEd Schouten } 822bc093719SEd Schouten 823bc093719SEd Schouten int 824bc093719SEd Schouten ttydisc_rint(struct tty *tp, char c, int flags) 825bc093719SEd Schouten { 826bc093719SEd Schouten int signal, quote = 0; 827bc093719SEd Schouten char ob[3] = { 0xff, 0x00 }; 828bc093719SEd Schouten size_t ol; 829bc093719SEd Schouten 830bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 831bc093719SEd Schouten 832bc093719SEd Schouten atomic_add_long(&tty_nin, 1); 833bc093719SEd Schouten 834a1215e37SEd Schouten if (ttyhook_hashook(tp, rint)) 835a1215e37SEd Schouten return ttyhook_rint(tp, c, flags); 836a1215e37SEd Schouten 837bc093719SEd Schouten if (tp->t_flags & TF_BYPASS) 838bc093719SEd Schouten goto processed; 839bc093719SEd Schouten 840bc093719SEd Schouten if (flags) { 841bc093719SEd Schouten if (flags & TRE_BREAK) { 842bc093719SEd Schouten if (CMP_FLAG(i, IGNBRK)) { 843bc093719SEd Schouten /* Ignore break characters. */ 844bc093719SEd Schouten return (0); 845bc093719SEd Schouten } else if (CMP_FLAG(i, BRKINT)) { 846bc093719SEd Schouten /* Generate SIGINT on break. */ 847bc093719SEd Schouten tty_flush(tp, FREAD|FWRITE); 848bc093719SEd Schouten tty_signal_pgrp(tp, SIGINT); 849bc093719SEd Schouten return (0); 850bc093719SEd Schouten } else { 851bc093719SEd Schouten /* Just print it. */ 852bc093719SEd Schouten goto parmrk; 853bc093719SEd Schouten } 854bc093719SEd Schouten } else if (flags & TRE_FRAMING || 855bc093719SEd Schouten (flags & TRE_PARITY && CMP_FLAG(i, INPCK))) { 856bc093719SEd Schouten if (CMP_FLAG(i, IGNPAR)) { 857bc093719SEd Schouten /* Ignore bad characters. */ 858bc093719SEd Schouten return (0); 859bc093719SEd Schouten } else { 860bc093719SEd Schouten /* Just print it. */ 861bc093719SEd Schouten goto parmrk; 862bc093719SEd Schouten } 863bc093719SEd Schouten } 864bc093719SEd Schouten } 865bc093719SEd Schouten 866bc093719SEd Schouten /* Allow any character to perform a wakeup. */ 867bc093719SEd Schouten if (CMP_FLAG(i, IXANY)) 868bc093719SEd Schouten tp->t_flags &= ~TF_STOPPED; 869bc093719SEd Schouten 870bc093719SEd Schouten /* Remove the top bit. */ 871bc093719SEd Schouten if (CMP_FLAG(i, ISTRIP)) 872bc093719SEd Schouten c &= ~0x80; 873bc093719SEd Schouten 874bc093719SEd Schouten /* Skip input processing when we want to print it literally. */ 875bc093719SEd Schouten if (tp->t_flags & TF_LITERAL) { 876bc093719SEd Schouten tp->t_flags &= ~TF_LITERAL; 877bc093719SEd Schouten quote = 1; 878bc093719SEd Schouten goto processed; 879bc093719SEd Schouten } 880bc093719SEd Schouten 881bc093719SEd Schouten /* Special control characters that are implementation dependent. */ 882bc093719SEd Schouten if (CMP_FLAG(l, IEXTEN)) { 883bc093719SEd Schouten /* Accept the next character as literal. */ 884bc093719SEd Schouten if (CMP_CC(VLNEXT, c)) { 885bc093719SEd Schouten if (CMP_FLAG(l, ECHO)) { 886bc093719SEd Schouten if (CMP_FLAG(l, ECHOE)) 887bc093719SEd Schouten ttyoutq_write_nofrag(&tp->t_outq, "^\b", 2); 888bc093719SEd Schouten else 889bc093719SEd Schouten ttydisc_echo(tp, c, 0); 890bc093719SEd Schouten } 891bc093719SEd Schouten tp->t_flags |= TF_LITERAL; 892bc093719SEd Schouten return (0); 893bc093719SEd Schouten } 894bc093719SEd Schouten } 895bc093719SEd Schouten 896bc093719SEd Schouten /* 897bc093719SEd Schouten * Handle signal processing. 898bc093719SEd Schouten */ 899bc093719SEd Schouten if (CMP_FLAG(l, ISIG)) { 900bc093719SEd Schouten if (CMP_FLAG(l, ICANON|IEXTEN) == (ICANON|IEXTEN)) { 901bc093719SEd Schouten if (CMP_CC(VSTATUS, c)) { 902bc093719SEd Schouten tty_signal_pgrp(tp, SIGINFO); 903bc093719SEd Schouten return (0); 904bc093719SEd Schouten } 905bc093719SEd Schouten } 906bc093719SEd Schouten 907bc093719SEd Schouten /* 908bc093719SEd Schouten * When compared to the old implementation, this 909bc093719SEd Schouten * implementation also flushes the output queue. POSIX 910bc093719SEd Schouten * is really brief about this, but does makes us assume 911bc093719SEd Schouten * we have to do so. 912bc093719SEd Schouten */ 913bc093719SEd Schouten signal = 0; 914bc093719SEd Schouten if (CMP_CC(VINTR, c)) { 915bc093719SEd Schouten signal = SIGINT; 916bc093719SEd Schouten } else if (CMP_CC(VQUIT, c)) { 917bc093719SEd Schouten signal = SIGQUIT; 918bc093719SEd Schouten } else if (CMP_CC(VSUSP, c)) { 919bc093719SEd Schouten signal = SIGTSTP; 920bc093719SEd Schouten } 921bc093719SEd Schouten 922bc093719SEd Schouten if (signal != 0) { 923bc093719SEd Schouten /* 924bc093719SEd Schouten * Echo the character before signalling the 925bc093719SEd Schouten * processes. 926bc093719SEd Schouten */ 927bc093719SEd Schouten if (!CMP_FLAG(l, NOFLSH)) 928bc093719SEd Schouten tty_flush(tp, FREAD|FWRITE); 929bc093719SEd Schouten ttydisc_echo(tp, c, 0); 930bc093719SEd Schouten tty_signal_pgrp(tp, signal); 931bc093719SEd Schouten return (0); 932bc093719SEd Schouten } 933bc093719SEd Schouten } 934bc093719SEd Schouten 935bc093719SEd Schouten /* 936bc093719SEd Schouten * Handle start/stop characters. 937bc093719SEd Schouten */ 938bc093719SEd Schouten if (CMP_FLAG(i, IXON)) { 939bc093719SEd Schouten if (CMP_CC(VSTOP, c)) { 940bc093719SEd Schouten /* Stop it if we aren't stopped yet. */ 941bc093719SEd Schouten if ((tp->t_flags & TF_STOPPED) == 0) { 942bc093719SEd Schouten tp->t_flags |= TF_STOPPED; 943bc093719SEd Schouten return (0); 944bc093719SEd Schouten } 945bc093719SEd Schouten /* 946bc093719SEd Schouten * Fallthrough: 947bc093719SEd Schouten * When VSTART == VSTOP, we should make this key 948bc093719SEd Schouten * toggle it. 949bc093719SEd Schouten */ 950bc093719SEd Schouten if (!CMP_CC(VSTART, c)) 951bc093719SEd Schouten return (0); 952bc093719SEd Schouten } 953bc093719SEd Schouten if (CMP_CC(VSTART, c)) { 954bc093719SEd Schouten tp->t_flags &= ~TF_STOPPED; 955bc093719SEd Schouten return (0); 956bc093719SEd Schouten } 957bc093719SEd Schouten } 958bc093719SEd Schouten 959bc093719SEd Schouten /* Conversion of CR and NL. */ 960bc093719SEd Schouten switch (c) { 961bc093719SEd Schouten case CCR: 962bc093719SEd Schouten if (CMP_FLAG(i, IGNCR)) 963bc093719SEd Schouten return (0); 964bc093719SEd Schouten if (CMP_FLAG(i, ICRNL)) 965bc093719SEd Schouten c = CNL; 966bc093719SEd Schouten break; 967bc093719SEd Schouten case CNL: 968bc093719SEd Schouten if (CMP_FLAG(i, INLCR)) 969bc093719SEd Schouten c = CCR; 970bc093719SEd Schouten break; 971bc093719SEd Schouten } 972bc093719SEd Schouten 973bc093719SEd Schouten /* Canonical line editing. */ 974bc093719SEd Schouten if (CMP_FLAG(l, ICANON)) { 975bc093719SEd Schouten if (CMP_CC(VERASE, c) || CMP_CC(VERASE2, c)) { 976bc093719SEd Schouten ttydisc_rubchar(tp); 977bc093719SEd Schouten return (0); 978bc093719SEd Schouten } else if (CMP_CC(VKILL, c)) { 979bc093719SEd Schouten while (ttydisc_rubchar(tp) == 0); 980bc093719SEd Schouten return (0); 981bc093719SEd Schouten } else if (CMP_FLAG(l, IEXTEN)) { 982bc093719SEd Schouten if (CMP_CC(VWERASE, c)) { 983bc093719SEd Schouten ttydisc_rubword(tp); 984bc093719SEd Schouten return (0); 985bc093719SEd Schouten } else if (CMP_CC(VREPRINT, c)) { 986bc093719SEd Schouten ttydisc_reprint(tp); 987bc093719SEd Schouten return (0); 988bc093719SEd Schouten } 989bc093719SEd Schouten } 990bc093719SEd Schouten } 991bc093719SEd Schouten 992bc093719SEd Schouten processed: 993bc093719SEd Schouten if (CMP_FLAG(i, PARMRK) && (unsigned char)c == 0xff) { 994bc093719SEd Schouten /* Print 0xff 0xff. */ 995bc093719SEd Schouten ob[1] = 0xff; 996bc093719SEd Schouten ol = 2; 997bc093719SEd Schouten quote = 1; 998bc093719SEd Schouten } else { 999bc093719SEd Schouten ob[0] = c; 1000bc093719SEd Schouten ol = 1; 1001bc093719SEd Schouten } 1002bc093719SEd Schouten 1003bc093719SEd Schouten goto print; 1004bc093719SEd Schouten 1005bc093719SEd Schouten parmrk: 1006bc093719SEd Schouten if (CMP_FLAG(i, PARMRK)) { 1007bc093719SEd Schouten /* Prepend 0xff 0x00 0x.. */ 1008bc093719SEd Schouten ob[2] = c; 1009bc093719SEd Schouten ol = 3; 1010bc093719SEd Schouten quote = 1; 1011bc093719SEd Schouten } else { 1012bc093719SEd Schouten ob[0] = c; 1013bc093719SEd Schouten ol = 1; 1014bc093719SEd Schouten } 1015bc093719SEd Schouten 1016bc093719SEd Schouten print: 1017bc093719SEd Schouten /* See if we can store this on the input queue. */ 1018bc093719SEd Schouten if (ttyinq_write_nofrag(&tp->t_inq, ob, ol, quote) != 0) { 1019a15ec0a5SEd Schouten if (CMP_FLAG(i, IMAXBEL)) 1020a15ec0a5SEd Schouten ttyoutq_write_nofrag(&tp->t_outq, "\a", 1); 1021a15ec0a5SEd Schouten 1022a15ec0a5SEd Schouten /* 1023a15ec0a5SEd Schouten * Prevent a deadlock here. It may be possible that a 1024a15ec0a5SEd Schouten * user has entered so much data, there is no data 1025a15ec0a5SEd Schouten * available to read(), but the buffers are full anyway. 1026a15ec0a5SEd Schouten * 1027a15ec0a5SEd Schouten * Only enter the high watermark if the device driver 1028a15ec0a5SEd Schouten * can actually transmit something. 1029a15ec0a5SEd Schouten */ 1030a15ec0a5SEd Schouten if (ttyinq_bytescanonicalized(&tp->t_inq) == 0) 1031a15ec0a5SEd Schouten return (0); 1032a15ec0a5SEd Schouten 1033bc093719SEd Schouten tty_hiwat_in_block(tp); 1034bc093719SEd Schouten return (-1); 1035bc093719SEd Schouten } 1036bc093719SEd Schouten 1037bc093719SEd Schouten /* 1038bc093719SEd Schouten * In raw mode, we canonicalize after receiving a single 1039bc093719SEd Schouten * character. Otherwise, we canonicalize when we receive a 1040bc093719SEd Schouten * newline, VEOL or VEOF, but only when it isn't quoted. 1041bc093719SEd Schouten */ 1042bc093719SEd Schouten if (!CMP_FLAG(l, ICANON) || 1043bc093719SEd Schouten (!quote && (c == CNL || CMP_CC(VEOL, c) || CMP_CC(VEOF, c)))) { 1044bc093719SEd Schouten ttyinq_canonicalize(&tp->t_inq); 1045bc093719SEd Schouten } 1046bc093719SEd Schouten 1047bc093719SEd Schouten ttydisc_echo(tp, c, quote); 1048bc093719SEd Schouten 1049bc093719SEd Schouten return (0); 1050bc093719SEd Schouten } 1051bc093719SEd Schouten 1052bc093719SEd Schouten size_t 10535c67885aSEd Schouten ttydisc_rint_simple(struct tty *tp, const void *buf, size_t len) 10545c67885aSEd Schouten { 10555c67885aSEd Schouten const char *cbuf; 10565c67885aSEd Schouten 10575c67885aSEd Schouten if (ttydisc_can_bypass(tp)) 10585c67885aSEd Schouten return (ttydisc_rint_bypass(tp, buf, len)); 10595c67885aSEd Schouten 10605c67885aSEd Schouten for (cbuf = buf; len-- > 0; cbuf++) { 10615c67885aSEd Schouten if (ttydisc_rint(tp, *cbuf, 0) != 0) 10625c67885aSEd Schouten break; 10635c67885aSEd Schouten } 10645c67885aSEd Schouten 10655c67885aSEd Schouten return (cbuf - (const char *)buf); 10665c67885aSEd Schouten } 10675c67885aSEd Schouten 10685c67885aSEd Schouten size_t 1069d344ffe5SEd Schouten ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len) 1070bc093719SEd Schouten { 1071bc093719SEd Schouten size_t ret; 1072bc093719SEd Schouten 1073bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 1074bc093719SEd Schouten 1075bc093719SEd Schouten MPASS(tp->t_flags & TF_BYPASS); 1076bc093719SEd Schouten 1077bc093719SEd Schouten atomic_add_long(&tty_nin, len); 1078bc093719SEd Schouten 1079a1215e37SEd Schouten if (ttyhook_hashook(tp, rint_bypass)) 1080a1215e37SEd Schouten return ttyhook_rint_bypass(tp, buf, len); 1081a1215e37SEd Schouten 1082bc093719SEd Schouten ret = ttyinq_write(&tp->t_inq, buf, len, 0); 1083bc093719SEd Schouten ttyinq_canonicalize(&tp->t_inq); 1084d40b91cbSEd Schouten if (ret < len) 1085d40b91cbSEd Schouten tty_hiwat_in_block(tp); 1086bc093719SEd Schouten 1087bc093719SEd Schouten return (ret); 1088bc093719SEd Schouten } 1089bc093719SEd Schouten 1090bc093719SEd Schouten void 1091bc093719SEd Schouten ttydisc_rint_done(struct tty *tp) 1092bc093719SEd Schouten { 1093bc093719SEd Schouten 1094bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 1095bc093719SEd Schouten 1096a1215e37SEd Schouten if (ttyhook_hashook(tp, rint_done)) 1097a1215e37SEd Schouten ttyhook_rint_done(tp); 1098a1215e37SEd Schouten 1099bc093719SEd Schouten /* Wake up readers. */ 1100bc093719SEd Schouten tty_wakeup(tp, FREAD); 1101bc093719SEd Schouten /* Wake up driver for echo. */ 1102bc093719SEd Schouten ttydevsw_outwakeup(tp); 1103bc093719SEd Schouten } 1104bc093719SEd Schouten 1105a1215e37SEd Schouten size_t 1106a1215e37SEd Schouten ttydisc_rint_poll(struct tty *tp) 1107a1215e37SEd Schouten { 1108a1215e37SEd Schouten size_t l; 1109a1215e37SEd Schouten 1110a1215e37SEd Schouten tty_lock_assert(tp, MA_OWNED); 1111a1215e37SEd Schouten 1112a1215e37SEd Schouten if (ttyhook_hashook(tp, rint_poll)) 1113a1215e37SEd Schouten return ttyhook_rint_poll(tp); 1114a1215e37SEd Schouten 1115a1215e37SEd Schouten /* 1116a1215e37SEd Schouten * XXX: Still allow character input when there's no space in the 1117a1215e37SEd Schouten * buffers, but we haven't entered the high watermark. This is 1118a1215e37SEd Schouten * to allow backspace characters to be inserted when in 1119a1215e37SEd Schouten * canonical mode. 1120a1215e37SEd Schouten */ 1121a1215e37SEd Schouten l = ttyinq_bytesleft(&tp->t_inq); 1122a1215e37SEd Schouten if (l == 0 && (tp->t_flags & TF_HIWAT_IN) == 0) 1123a1215e37SEd Schouten return (1); 1124a1215e37SEd Schouten 1125a1215e37SEd Schouten return (l); 1126a1215e37SEd Schouten } 1127a1215e37SEd Schouten 1128bc093719SEd Schouten static void 1129bc093719SEd Schouten ttydisc_wakeup_watermark(struct tty *tp) 1130bc093719SEd Schouten { 1131bc093719SEd Schouten size_t c; 1132bc093719SEd Schouten 1133bc093719SEd Schouten c = ttyoutq_bytesleft(&tp->t_outq); 1134bc093719SEd Schouten if (tp->t_flags & TF_HIWAT_OUT) { 1135bc093719SEd Schouten /* Only allow us to run when we're below the watermark. */ 1136bc093719SEd Schouten if (c < tp->t_outlow) 1137bc093719SEd Schouten return; 1138bc093719SEd Schouten 1139bc093719SEd Schouten /* Reset the watermark. */ 1140bc093719SEd Schouten tp->t_flags &= ~TF_HIWAT_OUT; 1141bc093719SEd Schouten } else { 1142bc093719SEd Schouten /* Only run when we have data at all. */ 1143bc093719SEd Schouten if (c == 0) 1144bc093719SEd Schouten return; 1145bc093719SEd Schouten } 1146bc093719SEd Schouten tty_wakeup(tp, FWRITE); 1147bc093719SEd Schouten } 1148bc093719SEd Schouten 1149bc093719SEd Schouten size_t 1150bc093719SEd Schouten ttydisc_getc(struct tty *tp, void *buf, size_t len) 1151bc093719SEd Schouten { 1152bc093719SEd Schouten 1153bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 1154bc093719SEd Schouten 1155bc093719SEd Schouten if (tp->t_flags & TF_STOPPED) 1156bc093719SEd Schouten return (0); 1157bc093719SEd Schouten 1158a1215e37SEd Schouten if (ttyhook_hashook(tp, getc_inject)) 1159a1215e37SEd Schouten return ttyhook_getc_inject(tp, buf, len); 1160bc093719SEd Schouten 1161a1215e37SEd Schouten len = ttyoutq_read(&tp->t_outq, buf, len); 1162a1215e37SEd Schouten 1163a1215e37SEd Schouten if (ttyhook_hashook(tp, getc_capture)) 1164a1215e37SEd Schouten ttyhook_getc_capture(tp, buf, len); 1165a1215e37SEd Schouten 1166a1215e37SEd Schouten ttydisc_wakeup_watermark(tp); 1167ffffa83bSEd Schouten atomic_add_long(&tty_nout, len); 1168bc093719SEd Schouten 1169ffffa83bSEd Schouten return (len); 1170bc093719SEd Schouten } 1171bc093719SEd Schouten 1172bc093719SEd Schouten int 1173bc093719SEd Schouten ttydisc_getc_uio(struct tty *tp, struct uio *uio) 1174bc093719SEd Schouten { 1175a1215e37SEd Schouten int error = 0; 1176*526d0bd5SKonstantin Belousov ssize_t obytes = uio->uio_resid; 1177a1215e37SEd Schouten size_t len; 1178a1215e37SEd Schouten char buf[TTY_STACKBUF]; 1179bc093719SEd Schouten 1180bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 1181bc093719SEd Schouten 1182bc093719SEd Schouten if (tp->t_flags & TF_STOPPED) 1183bc093719SEd Schouten return (0); 1184bc093719SEd Schouten 1185a1215e37SEd Schouten /* 1186a1215e37SEd Schouten * When a TTY hook is attached, we cannot perform unbuffered 1187a1215e37SEd Schouten * copying to userspace. Just call ttydisc_getc() and 1188a1215e37SEd Schouten * temporarily store data in a shadow buffer. 1189a1215e37SEd Schouten */ 1190a1215e37SEd Schouten if (ttyhook_hashook(tp, getc_capture) || 1191a1215e37SEd Schouten ttyhook_hashook(tp, getc_inject)) { 1192a1215e37SEd Schouten while (uio->uio_resid > 0) { 1193a1215e37SEd Schouten /* Read to shadow buffer. */ 1194a1215e37SEd Schouten len = ttydisc_getc(tp, buf, 1195a1215e37SEd Schouten MIN(uio->uio_resid, sizeof buf)); 1196a1215e37SEd Schouten if (len == 0) 1197a1215e37SEd Schouten break; 1198bc093719SEd Schouten 1199a1215e37SEd Schouten /* Copy to userspace. */ 1200a1215e37SEd Schouten tty_unlock(tp); 1201a1215e37SEd Schouten error = uiomove(buf, len, uio); 1202a1215e37SEd Schouten tty_lock(tp); 1203a1215e37SEd Schouten 1204a1215e37SEd Schouten if (error != 0) 1205a1215e37SEd Schouten break; 1206a1215e37SEd Schouten } 1207a1215e37SEd Schouten } else { 1208a1215e37SEd Schouten error = ttyoutq_read_uio(&tp->t_outq, tp, uio); 1209a1215e37SEd Schouten 1210a1215e37SEd Schouten ttydisc_wakeup_watermark(tp); 1211bc093719SEd Schouten atomic_add_long(&tty_nout, obytes - uio->uio_resid); 1212a1215e37SEd Schouten } 1213bc093719SEd Schouten 1214bc093719SEd Schouten return (error); 1215bc093719SEd Schouten } 1216bc093719SEd Schouten 1217a1215e37SEd Schouten size_t 1218a1215e37SEd Schouten ttydisc_getc_poll(struct tty *tp) 1219a1215e37SEd Schouten { 1220a1215e37SEd Schouten 1221a1215e37SEd Schouten tty_lock_assert(tp, MA_OWNED); 1222a1215e37SEd Schouten 1223a1215e37SEd Schouten if (tp->t_flags & TF_STOPPED) 1224a1215e37SEd Schouten return (0); 1225a1215e37SEd Schouten 1226a1215e37SEd Schouten if (ttyhook_hashook(tp, getc_poll)) 1227a1215e37SEd Schouten return ttyhook_getc_poll(tp); 1228a1215e37SEd Schouten 1229a1215e37SEd Schouten return ttyoutq_bytesused(&tp->t_outq); 1230a1215e37SEd Schouten } 1231a1215e37SEd Schouten 1232bc093719SEd Schouten /* 1233bc093719SEd Schouten * XXX: not really related to the TTYDISC, but we'd better put 1234bc093719SEd Schouten * tty_putchar() here, because we need to perform proper output 1235bc093719SEd Schouten * processing. 1236bc093719SEd Schouten */ 1237bc093719SEd Schouten 1238bc093719SEd Schouten int 1239bc093719SEd Schouten tty_putchar(struct tty *tp, char c) 1240bc093719SEd Schouten { 1241bc093719SEd Schouten tty_lock_assert(tp, MA_OWNED); 1242bc093719SEd Schouten 1243bc093719SEd Schouten if (tty_gone(tp)) 1244bc093719SEd Schouten return (-1); 1245bc093719SEd Schouten 1246bc093719SEd Schouten ttydisc_echo_force(tp, c, 0); 1247bc093719SEd Schouten tp->t_writepos = tp->t_column; 1248bc093719SEd Schouten ttyinq_reprintpos_set(&tp->t_inq); 1249bc093719SEd Schouten 1250bc093719SEd Schouten ttydevsw_outwakeup(tp); 1251bc093719SEd Schouten return (0); 1252bc093719SEd Schouten } 1253