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 ttyinq_unputchar(&tp->t_inq); 848 } else { 849 /* Find codepoint and width. */ 850 codepoint = 851 teken_utf8_bytes_to_codepoint(bytes, 852 nb); 853 if (codepoint == 854 TEKEN_UTF8_INVALID_CODEPOINT || 855 (cwidth = teken_wcwidth( 856 codepoint)) == -1) { 857 /* 858 * Place all bytes back into the 859 * inq and fall back to 860 * default behaviour. 861 */ 862 cwidth = 1; 863 ttyinq_write(&tp->t_inq, bytes, 864 nb, 0); 865 ttyinq_unputchar(&tp->t_inq); 866 } 867 } 868 tp->t_column -= cwidth; 869 /* 870 * Delete character by punching 871 * 'cwidth' spaces over it. 872 */ 873 if (cwidth == 1) 874 ttyoutq_write_nofrag(&tp->t_outq, 875 "\b \b", 3); 876 else if (cwidth == 2) 877 ttyoutq_write_nofrag(&tp->t_outq, 878 "\b\b \b\b", 6); 879 } else { 880 /* 881 * Remove a regular character by 882 * punching a space over it. 883 */ 884 tp->t_column -= 1; 885 ttyoutq_write_nofrag(&tp->t_outq, "\b \b", 3); 886 } 887 } else { 888 /* Don't print spaces. */ 889 ttydisc_echo(tp, tp->t_termios.c_cc[VERASE], 0); 890 } 891 } 892 893 return (0); 894 } 895 896 static void 897 ttydisc_rubword(struct tty *tp) 898 { 899 char c; 900 int quote, alnum; 901 902 /* Strip whitespace first. */ 903 for (;;) { 904 if (ttyinq_peekchar(&tp->t_inq, &c, "e) != 0) 905 return; 906 if (!CTL_WHITE(c)) 907 break; 908 ttydisc_rubchar(tp); 909 } 910 911 /* 912 * Record whether the last character from the previous iteration 913 * was alphanumeric or not. We need this to implement ALTWERASE. 914 */ 915 alnum = CTL_ALNUM(c); 916 for (;;) { 917 ttydisc_rubchar(tp); 918 919 if (ttyinq_peekchar(&tp->t_inq, &c, "e) != 0) 920 return; 921 if (CTL_WHITE(c)) 922 return; 923 if (CMP_FLAG(l, ALTWERASE) && CTL_ALNUM(c) != alnum) 924 return; 925 } 926 } 927 928 int 929 ttydisc_rint(struct tty *tp, char c, int flags) 930 { 931 int signal, quote = 0; 932 char ob[3] = { 0xff, 0x00 }; 933 size_t ol; 934 935 tty_assert_locked(tp); 936 937 atomic_add_long(&tty_nin, 1); 938 939 if (ttyhook_hashook(tp, rint)) 940 return ttyhook_rint(tp, c, flags); 941 942 if (tp->t_flags & TF_BYPASS) 943 goto processed; 944 945 if (flags) { 946 if (flags & TRE_BREAK) { 947 if (CMP_FLAG(i, IGNBRK)) { 948 /* Ignore break characters. */ 949 return (0); 950 } else if (CMP_FLAG(i, BRKINT)) { 951 /* Generate SIGINT on break. */ 952 tty_flush(tp, FREAD|FWRITE); 953 tty_signal_pgrp(tp, SIGINT); 954 return (0); 955 } else { 956 /* Just print it. */ 957 goto parmrk; 958 } 959 } else if (flags & TRE_FRAMING || 960 (flags & TRE_PARITY && CMP_FLAG(i, INPCK))) { 961 if (CMP_FLAG(i, IGNPAR)) { 962 /* Ignore bad characters. */ 963 return (0); 964 } else { 965 /* Just print it. */ 966 goto parmrk; 967 } 968 } 969 } 970 971 /* Allow any character to perform a wakeup. */ 972 if (CMP_FLAG(i, IXANY)) { 973 tp->t_flags &= ~TF_STOPPED; 974 tp->t_termios.c_lflag &= ~FLUSHO; 975 } 976 977 /* Remove the top bit. */ 978 if (CMP_FLAG(i, ISTRIP)) 979 c &= ~0x80; 980 981 /* Skip input processing when we want to print it literally. */ 982 if (tp->t_flags & TF_LITERAL) { 983 tp->t_flags &= ~TF_LITERAL; 984 quote = 1; 985 goto processed; 986 } 987 988 /* Special control characters that are implementation dependent. */ 989 if (CMP_FLAG(l, IEXTEN)) { 990 /* Accept the next character as literal. */ 991 if (CMP_CC(VLNEXT, c)) { 992 if (CMP_FLAG(l, ECHO)) { 993 if (CMP_FLAG(l, ECHOE)) 994 ttyoutq_write_nofrag(&tp->t_outq, "^\b", 2); 995 else 996 ttydisc_echo(tp, c, 0); 997 } 998 tp->t_flags |= TF_LITERAL; 999 return (0); 1000 } 1001 /* Discard processing */ 1002 if (CMP_CC(VDISCARD, c)) { 1003 if (CMP_FLAG(l, FLUSHO)) { 1004 tp->t_termios.c_lflag &= ~FLUSHO; 1005 } else { 1006 tty_flush(tp, FWRITE); 1007 ttydisc_echo(tp, c, 0); 1008 if (tp->t_inq.ti_end > 0) 1009 ttydisc_reprint(tp); 1010 tp->t_termios.c_lflag |= FLUSHO; 1011 } 1012 } 1013 } 1014 1015 /* 1016 * Handle signal processing. 1017 */ 1018 if (CMP_FLAG(l, ISIG)) { 1019 if (CMP_FLAG(l, ICANON|IEXTEN) == (ICANON|IEXTEN)) { 1020 if (CMP_CC(VSTATUS, c)) { 1021 tty_signal_pgrp(tp, SIGINFO); 1022 return (0); 1023 } 1024 } 1025 1026 /* 1027 * When compared to the old implementation, this 1028 * implementation also flushes the output queue. POSIX 1029 * is really brief about this, but does makes us assume 1030 * we have to do so. 1031 */ 1032 signal = 0; 1033 if (CMP_CC(VINTR, c)) { 1034 signal = SIGINT; 1035 } else if (CMP_CC(VQUIT, c)) { 1036 signal = SIGQUIT; 1037 } else if (CMP_CC(VSUSP, c)) { 1038 signal = SIGTSTP; 1039 } 1040 1041 if (signal != 0) { 1042 /* 1043 * Echo the character before signalling the 1044 * processes. 1045 */ 1046 if (!CMP_FLAG(l, NOFLSH)) 1047 tty_flush(tp, FREAD|FWRITE); 1048 ttydisc_echo(tp, c, 0); 1049 tty_signal_pgrp(tp, signal); 1050 return (0); 1051 } 1052 } 1053 1054 /* 1055 * Handle start/stop characters. 1056 */ 1057 if (CMP_FLAG(i, IXON)) { 1058 if (CMP_CC(VSTOP, c)) { 1059 /* Stop it if we aren't stopped yet. */ 1060 if ((tp->t_flags & TF_STOPPED) == 0) { 1061 tp->t_flags |= TF_STOPPED; 1062 return (0); 1063 } 1064 /* 1065 * Fallthrough: 1066 * When VSTART == VSTOP, we should make this key 1067 * toggle it. 1068 */ 1069 if (!CMP_CC(VSTART, c)) 1070 return (0); 1071 } 1072 if (CMP_CC(VSTART, c)) { 1073 tp->t_flags &= ~TF_STOPPED; 1074 return (0); 1075 } 1076 } 1077 1078 /* Conversion of CR and NL. */ 1079 switch (c) { 1080 case CCR: 1081 if (CMP_FLAG(i, IGNCR)) 1082 return (0); 1083 if (CMP_FLAG(i, ICRNL)) 1084 c = CNL; 1085 break; 1086 case CNL: 1087 if (CMP_FLAG(i, INLCR)) 1088 c = CCR; 1089 break; 1090 } 1091 1092 /* Canonical line editing. */ 1093 if (CMP_FLAG(l, ICANON)) { 1094 if (CMP_CC(VERASE, c) || CMP_CC(VERASE2, c)) { 1095 ttydisc_rubchar(tp); 1096 return (0); 1097 } else if (CMP_CC(VKILL, c)) { 1098 while (ttydisc_rubchar(tp) == 0); 1099 return (0); 1100 } else if (CMP_FLAG(l, IEXTEN)) { 1101 if (CMP_CC(VWERASE, c)) { 1102 ttydisc_rubword(tp); 1103 return (0); 1104 } else if (CMP_CC(VREPRINT, c)) { 1105 ttydisc_reprint(tp); 1106 return (0); 1107 } 1108 } 1109 } 1110 1111 processed: 1112 if (CMP_FLAG(i, PARMRK) && (unsigned char)c == 0xff) { 1113 /* Print 0xff 0xff. */ 1114 ob[1] = 0xff; 1115 ol = 2; 1116 quote = 1; 1117 } else { 1118 ob[0] = c; 1119 ol = 1; 1120 } 1121 1122 goto print; 1123 1124 parmrk: 1125 if (CMP_FLAG(i, PARMRK)) { 1126 /* Prepend 0xff 0x00 0x.. */ 1127 ob[2] = c; 1128 ol = 3; 1129 quote = 1; 1130 } else { 1131 ob[0] = c; 1132 ol = 1; 1133 } 1134 1135 print: 1136 /* See if we can store this on the input queue. */ 1137 if (ttyinq_write_nofrag(&tp->t_inq, ob, ol, quote) != 0) { 1138 if (CMP_FLAG(i, IMAXBEL)) 1139 ttyoutq_write_nofrag(&tp->t_outq, "\a", 1); 1140 1141 /* 1142 * Prevent a deadlock here. It may be possible that a 1143 * user has entered so much data, there is no data 1144 * available to read(), but the buffers are full anyway. 1145 * 1146 * Only enter the high watermark if the device driver 1147 * can actually transmit something. 1148 */ 1149 if (ttyinq_bytescanonicalized(&tp->t_inq) == 0) 1150 return (0); 1151 1152 tty_hiwat_in_block(tp); 1153 return (-1); 1154 } 1155 1156 /* 1157 * In raw mode, we canonicalize after receiving a single 1158 * character. Otherwise, we canonicalize when we receive a 1159 * newline, VEOL or VEOF, but only when it isn't quoted. 1160 */ 1161 if (!CMP_FLAG(l, ICANON) || 1162 (!quote && (c == CNL || CMP_CC(VEOL, c) || CMP_CC(VEOF, c)))) { 1163 ttyinq_canonicalize(&tp->t_inq); 1164 } 1165 1166 ttydisc_echo(tp, c, quote); 1167 1168 return (0); 1169 } 1170 1171 size_t 1172 ttydisc_rint_simple(struct tty *tp, const void *buf, size_t len) 1173 { 1174 const char *cbuf; 1175 1176 if (ttydisc_can_bypass(tp)) 1177 return (ttydisc_rint_bypass(tp, buf, len)); 1178 1179 for (cbuf = buf; len-- > 0; cbuf++) { 1180 if (ttydisc_rint(tp, *cbuf, 0) != 0) 1181 break; 1182 } 1183 1184 return (cbuf - (const char *)buf); 1185 } 1186 1187 size_t 1188 ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len) 1189 { 1190 size_t ret; 1191 1192 tty_assert_locked(tp); 1193 1194 MPASS(tp->t_flags & TF_BYPASS); 1195 1196 atomic_add_long(&tty_nin, len); 1197 1198 if (ttyhook_hashook(tp, rint_bypass)) 1199 return ttyhook_rint_bypass(tp, buf, len); 1200 1201 ret = ttyinq_write(&tp->t_inq, buf, len, 0); 1202 ttyinq_canonicalize(&tp->t_inq); 1203 if (ret < len) 1204 tty_hiwat_in_block(tp); 1205 1206 return (ret); 1207 } 1208 1209 void 1210 ttydisc_rint_done(struct tty *tp) 1211 { 1212 1213 tty_assert_locked(tp); 1214 1215 if (ttyhook_hashook(tp, rint_done)) 1216 ttyhook_rint_done(tp); 1217 1218 /* Wake up readers. */ 1219 tty_wakeup(tp, FREAD); 1220 /* Wake up driver for echo. */ 1221 ttydevsw_outwakeup(tp); 1222 } 1223 1224 size_t 1225 ttydisc_rint_poll(struct tty *tp) 1226 { 1227 size_t l; 1228 1229 tty_assert_locked(tp); 1230 1231 if (ttyhook_hashook(tp, rint_poll)) 1232 return ttyhook_rint_poll(tp); 1233 1234 /* 1235 * XXX: Still allow character input when there's no space in the 1236 * buffers, but we haven't entered the high watermark. This is 1237 * to allow backspace characters to be inserted when in 1238 * canonical mode. 1239 */ 1240 l = ttyinq_bytesleft(&tp->t_inq); 1241 if (l == 0 && (tp->t_flags & TF_HIWAT_IN) == 0) 1242 return (1); 1243 1244 return (l); 1245 } 1246 1247 static void 1248 ttydisc_wakeup_watermark(struct tty *tp) 1249 { 1250 size_t c; 1251 1252 c = ttyoutq_bytesleft(&tp->t_outq); 1253 if (tp->t_flags & TF_HIWAT_OUT) { 1254 /* Only allow us to run when we're below the watermark. */ 1255 if (c < tp->t_outlow) 1256 return; 1257 1258 /* Reset the watermark. */ 1259 tp->t_flags &= ~TF_HIWAT_OUT; 1260 } else { 1261 /* Only run when we have data at all. */ 1262 if (c == 0) 1263 return; 1264 } 1265 tty_wakeup(tp, FWRITE); 1266 } 1267 1268 size_t 1269 ttydisc_getc(struct tty *tp, void *buf, size_t len) 1270 { 1271 1272 tty_assert_locked(tp); 1273 1274 if (tp->t_flags & TF_STOPPED) 1275 return (0); 1276 1277 if (ttyhook_hashook(tp, getc_inject)) 1278 return ttyhook_getc_inject(tp, buf, len); 1279 1280 len = ttyoutq_read(&tp->t_outq, buf, len); 1281 1282 if (ttyhook_hashook(tp, getc_capture)) 1283 ttyhook_getc_capture(tp, buf, len); 1284 1285 ttydisc_wakeup_watermark(tp); 1286 atomic_add_long(&tty_nout, len); 1287 1288 return (len); 1289 } 1290 1291 int 1292 ttydisc_getc_uio(struct tty *tp, struct uio *uio) 1293 { 1294 int error = 0; 1295 ssize_t obytes = uio->uio_resid; 1296 size_t len; 1297 char buf[TTY_STACKBUF]; 1298 1299 tty_assert_locked(tp); 1300 1301 if (tp->t_flags & TF_STOPPED) 1302 return (0); 1303 1304 /* 1305 * When a TTY hook is attached, we cannot perform unbuffered 1306 * copying to userspace. Just call ttydisc_getc() and 1307 * temporarily store data in a shadow buffer. 1308 */ 1309 if (ttyhook_hashook(tp, getc_capture) || 1310 ttyhook_hashook(tp, getc_inject)) { 1311 while (uio->uio_resid > 0) { 1312 /* Read to shadow buffer. */ 1313 len = ttydisc_getc(tp, buf, 1314 MIN(uio->uio_resid, sizeof buf)); 1315 if (len == 0) 1316 break; 1317 1318 /* Copy to userspace. */ 1319 tty_unlock(tp); 1320 error = uiomove(buf, len, uio); 1321 tty_lock(tp); 1322 1323 if (error != 0) 1324 break; 1325 } 1326 } else { 1327 error = ttyoutq_read_uio(&tp->t_outq, tp, uio); 1328 1329 ttydisc_wakeup_watermark(tp); 1330 atomic_add_long(&tty_nout, obytes - uio->uio_resid); 1331 } 1332 1333 return (error); 1334 } 1335 1336 size_t 1337 ttydisc_getc_poll(struct tty *tp) 1338 { 1339 1340 tty_assert_locked(tp); 1341 1342 if (tp->t_flags & TF_STOPPED) 1343 return (0); 1344 1345 if (ttyhook_hashook(tp, getc_poll)) 1346 return ttyhook_getc_poll(tp); 1347 1348 return ttyoutq_bytesused(&tp->t_outq); 1349 } 1350 1351 /* 1352 * XXX: not really related to the TTYDISC, but we'd better put 1353 * tty_putchar() here, because we need to perform proper output 1354 * processing. 1355 */ 1356 1357 int 1358 tty_putstrn(struct tty *tp, const char *p, size_t n) 1359 { 1360 size_t i; 1361 1362 tty_assert_locked(tp); 1363 1364 if (tty_gone(tp)) 1365 return (-1); 1366 1367 for (i = 0; i < n; i++) 1368 ttydisc_echo_force(tp, p[i], 0); 1369 1370 tp->t_writepos = tp->t_column; 1371 ttyinq_reprintpos_set(&tp->t_inq); 1372 1373 ttydevsw_outwakeup(tp); 1374 return (0); 1375 } 1376 1377 int 1378 tty_putchar(struct tty *tp, char c) 1379 { 1380 return (tty_putstrn(tp, &c, 1)); 1381 } 1382