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