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