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