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