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