source: rtems-libbsd/freebsd/sys/kern/tty_ttydisc.c @ 4a8f953

55-freebsd-126-freebsd-12
Last change on this file since 4a8f953 was 4a8f953, checked in by Kevin Kirspel <kevin-kirspel@…>, on 05/04/17 at 12:27:58

Updating FREEBSD for tty support

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