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