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