The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_ttydisc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    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: releng/12.0/sys/kern/tty_ttydisc.c 326271 2017-11-27 15:20:12Z pfg $");
   34 
   35 #include <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. */
   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) >= '' && (c) <= '9') || \
   82     ((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
   83 
   84 #define TTY_STACKBUF    256
   85 
   86 void
   87 ttydisc_open(struct tty *tp)
   88 {
   89         ttydisc_optimize(tp);
   90 }
   91 
   92 void
   93 ttydisc_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 
  109 static int
  110 ttydisc_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 
  182 static int
  183 ttydisc_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 
  221 static int
  222 ttydisc_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 
  275 static int
  276 ttydisc_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 
  324 int
  325 ttydisc_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 
  353 static __inline unsigned int
  354 ttydisc_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 
  367 static int
  368 ttydisc_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  */
  453 int
  454 ttydisc_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 
  560 done:
  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 
  573 void
  574 ttydisc_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 
  593 void
  594 ttydisc_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 
  628 static int
  629 ttydisc_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 
  664 static int
  665 ttydisc_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 
  679 static void
  680 ttydisc_reprint_char(void *d, char c, int quote)
  681 {
  682         struct tty *tp = d;
  683 
  684         ttydisc_echo(tp, c, quote);
  685 }
  686 
  687 static void
  688 ttydisc_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 
  702 struct ttydisc_recalc_length {
  703         struct tty *tp;
  704         unsigned int curlen;
  705 };
  706 
  707 static void
  708 ttydisc_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 
  723 static unsigned int
  724 ttydisc_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 
  733 static int
  734 ttydisc_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 
  806 static void
  807 ttydisc_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 
  838 int
  839 ttydisc_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                                 tty_signal_pgrp(tp, SIGINFO);
  918                                 return (0);
  919                         }
  920                 }
  921 
  922                 /*
  923                  * When compared to the old implementation, this
  924                  * implementation also flushes the output queue. POSIX
  925                  * is really brief about this, but does makes us assume
  926                  * we have to do so.
  927                  */
  928                 signal = 0;
  929                 if (CMP_CC(VINTR, c)) {
  930                         signal = SIGINT;
  931                 } else if (CMP_CC(VQUIT, c)) {
  932                         signal = SIGQUIT;
  933                 } else if (CMP_CC(VSUSP, c)) {
  934                         signal = SIGTSTP;
  935                 }
  936 
  937                 if (signal != 0) {
  938                         /*
  939                          * Echo the character before signalling the
  940                          * processes.
  941                          */
  942                         if (!CMP_FLAG(l, NOFLSH))
  943                                 tty_flush(tp, FREAD|FWRITE);
  944                         ttydisc_echo(tp, c, 0);
  945                         tty_signal_pgrp(tp, signal);
  946                         return (0);
  947                 }
  948         }
  949 
  950         /*
  951          * Handle start/stop characters.
  952          */
  953         if (CMP_FLAG(i, IXON)) {
  954                 if (CMP_CC(VSTOP, c)) {
  955                         /* Stop it if we aren't stopped yet. */
  956                         if ((tp->t_flags & TF_STOPPED) == 0) {
  957                                 tp->t_flags |= TF_STOPPED;
  958                                 return (0);
  959                         }
  960                         /*
  961                          * Fallthrough:
  962                          * When VSTART == VSTOP, we should make this key
  963                          * toggle it.
  964                          */
  965                         if (!CMP_CC(VSTART, c))
  966                                 return (0);
  967                 }
  968                 if (CMP_CC(VSTART, c)) {
  969                         tp->t_flags &= ~TF_STOPPED;
  970                         return (0);
  971                 }
  972         }
  973 
  974         /* Conversion of CR and NL. */
  975         switch (c) {
  976         case CCR:
  977                 if (CMP_FLAG(i, IGNCR))
  978                         return (0);
  979                 if (CMP_FLAG(i, ICRNL))
  980                         c = CNL;
  981                 break;
  982         case CNL:
  983                 if (CMP_FLAG(i, INLCR))
  984                         c = CCR;
  985                 break;
  986         }
  987 
  988         /* Canonical line editing. */
  989         if (CMP_FLAG(l, ICANON)) {
  990                 if (CMP_CC(VERASE, c) || CMP_CC(VERASE2, c)) {
  991                         ttydisc_rubchar(tp);
  992                         return (0);
  993                 } else if (CMP_CC(VKILL, c)) {
  994                         while (ttydisc_rubchar(tp) == 0);
  995                         return (0);
  996                 } else if (CMP_FLAG(l, IEXTEN)) {
  997                         if (CMP_CC(VWERASE, c)) {
  998                                 ttydisc_rubword(tp);
  999                                 return (0);
 1000                         } else if (CMP_CC(VREPRINT, c)) {
 1001                                 ttydisc_reprint(tp);
 1002                                 return (0);
 1003                         }
 1004                 }
 1005         }
 1006 
 1007 processed:
 1008         if (CMP_FLAG(i, PARMRK) && (unsigned char)c == 0xff) {
 1009                 /* Print 0xff 0xff. */
 1010                 ob[1] = 0xff;
 1011                 ol = 2;
 1012                 quote = 1;
 1013         } else {
 1014                 ob[0] = c;
 1015                 ol = 1;
 1016         }
 1017 
 1018         goto print;
 1019 
 1020 parmrk:
 1021         if (CMP_FLAG(i, PARMRK)) {
 1022                 /* Prepend 0xff 0x00 0x.. */
 1023                 ob[2] = c;
 1024                 ol = 3;
 1025                 quote = 1;
 1026         } else {
 1027                 ob[0] = c;
 1028                 ol = 1;
 1029         }
 1030 
 1031 print:
 1032         /* See if we can store this on the input queue. */
 1033         if (ttyinq_write_nofrag(&tp->t_inq, ob, ol, quote) != 0) {
 1034                 if (CMP_FLAG(i, IMAXBEL))
 1035                         ttyoutq_write_nofrag(&tp->t_outq, "\a", 1);
 1036 
 1037                 /*
 1038                  * Prevent a deadlock here. It may be possible that a
 1039                  * user has entered so much data, there is no data
 1040                  * available to read(), but the buffers are full anyway.
 1041                  *
 1042                  * Only enter the high watermark if the device driver
 1043                  * can actually transmit something.
 1044                  */
 1045                 if (ttyinq_bytescanonicalized(&tp->t_inq) == 0)
 1046                         return (0);
 1047 
 1048                 tty_hiwat_in_block(tp);
 1049                 return (-1);
 1050         }
 1051 
 1052         /*
 1053          * In raw mode, we canonicalize after receiving a single
 1054          * character. Otherwise, we canonicalize when we receive a
 1055          * newline, VEOL or VEOF, but only when it isn't quoted.
 1056          */
 1057         if (!CMP_FLAG(l, ICANON) ||
 1058             (!quote && (c == CNL || CMP_CC(VEOL, c) || CMP_CC(VEOF, c)))) {
 1059                 ttyinq_canonicalize(&tp->t_inq);
 1060         }
 1061 
 1062         ttydisc_echo(tp, c, quote);
 1063 
 1064         return (0);
 1065 }
 1066 
 1067 size_t
 1068 ttydisc_rint_simple(struct tty *tp, const void *buf, size_t len)
 1069 {
 1070         const char *cbuf;
 1071 
 1072         if (ttydisc_can_bypass(tp))
 1073                 return (ttydisc_rint_bypass(tp, buf, len));
 1074 
 1075         for (cbuf = buf; len-- > 0; cbuf++) {
 1076                 if (ttydisc_rint(tp, *cbuf, 0) != 0)
 1077                         break;
 1078         }
 1079 
 1080         return (cbuf - (const char *)buf);
 1081 }
 1082 
 1083 size_t
 1084 ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len)
 1085 {
 1086         size_t ret;
 1087 
 1088         tty_lock_assert(tp, MA_OWNED);
 1089 
 1090         MPASS(tp->t_flags & TF_BYPASS);
 1091 
 1092         atomic_add_long(&tty_nin, len);
 1093 
 1094         if (ttyhook_hashook(tp, rint_bypass))
 1095                 return ttyhook_rint_bypass(tp, buf, len);
 1096 
 1097         ret = ttyinq_write(&tp->t_inq, buf, len, 0);
 1098         ttyinq_canonicalize(&tp->t_inq);
 1099         if (ret < len)
 1100                 tty_hiwat_in_block(tp);
 1101 
 1102         return (ret);
 1103 }
 1104 
 1105 void
 1106 ttydisc_rint_done(struct tty *tp)
 1107 {
 1108 
 1109         tty_lock_assert(tp, MA_OWNED);
 1110 
 1111         if (ttyhook_hashook(tp, rint_done))
 1112                 ttyhook_rint_done(tp);
 1113 
 1114         /* Wake up readers. */
 1115         tty_wakeup(tp, FREAD);
 1116         /* Wake up driver for echo. */
 1117         ttydevsw_outwakeup(tp);
 1118 }
 1119 
 1120 size_t
 1121 ttydisc_rint_poll(struct tty *tp)
 1122 {
 1123         size_t l;
 1124 
 1125         tty_lock_assert(tp, MA_OWNED);
 1126 
 1127         if (ttyhook_hashook(tp, rint_poll))
 1128                 return ttyhook_rint_poll(tp);
 1129 
 1130         /*
 1131          * XXX: Still allow character input when there's no space in the
 1132          * buffers, but we haven't entered the high watermark. This is
 1133          * to allow backspace characters to be inserted when in
 1134          * canonical mode.
 1135          */
 1136         l = ttyinq_bytesleft(&tp->t_inq);
 1137         if (l == 0 && (tp->t_flags & TF_HIWAT_IN) == 0)
 1138                 return (1);
 1139 
 1140         return (l);
 1141 }
 1142 
 1143 static void
 1144 ttydisc_wakeup_watermark(struct tty *tp)
 1145 {
 1146         size_t c;
 1147 
 1148         c = ttyoutq_bytesleft(&tp->t_outq);
 1149         if (tp->t_flags & TF_HIWAT_OUT) {
 1150                 /* Only allow us to run when we're below the watermark. */
 1151                 if (c < tp->t_outlow)
 1152                         return;
 1153 
 1154                 /* Reset the watermark. */
 1155                 tp->t_flags &= ~TF_HIWAT_OUT;
 1156         } else {
 1157                 /* Only run when we have data at all. */
 1158                 if (c == 0)
 1159                         return;
 1160         }
 1161         tty_wakeup(tp, FWRITE);
 1162 }
 1163 
 1164 size_t
 1165 ttydisc_getc(struct tty *tp, void *buf, size_t len)
 1166 {
 1167 
 1168         tty_lock_assert(tp, MA_OWNED);
 1169 
 1170         if (tp->t_flags & TF_STOPPED)
 1171                 return (0);
 1172 
 1173         if (ttyhook_hashook(tp, getc_inject))
 1174                 return ttyhook_getc_inject(tp, buf, len);
 1175 
 1176         len = ttyoutq_read(&tp->t_outq, buf, len);
 1177 
 1178         if (ttyhook_hashook(tp, getc_capture))
 1179                 ttyhook_getc_capture(tp, buf, len);
 1180 
 1181         ttydisc_wakeup_watermark(tp);
 1182         atomic_add_long(&tty_nout, len);
 1183 
 1184         return (len);
 1185 }
 1186 
 1187 int
 1188 ttydisc_getc_uio(struct tty *tp, struct uio *uio)
 1189 {
 1190         int error = 0;
 1191         ssize_t obytes = uio->uio_resid;
 1192         size_t len;
 1193         char buf[TTY_STACKBUF];
 1194 
 1195         tty_lock_assert(tp, MA_OWNED);
 1196 
 1197         if (tp->t_flags & TF_STOPPED)
 1198                 return (0);
 1199 
 1200         /*
 1201          * When a TTY hook is attached, we cannot perform unbuffered
 1202          * copying to userspace. Just call ttydisc_getc() and
 1203          * temporarily store data in a shadow buffer.
 1204          */
 1205         if (ttyhook_hashook(tp, getc_capture) ||
 1206             ttyhook_hashook(tp, getc_inject)) {
 1207                 while (uio->uio_resid > 0) {
 1208                         /* Read to shadow buffer. */
 1209                         len = ttydisc_getc(tp, buf,
 1210                             MIN(uio->uio_resid, sizeof buf));
 1211                         if (len == 0)
 1212                                 break;
 1213 
 1214                         /* Copy to userspace. */
 1215                         tty_unlock(tp);
 1216                         error = uiomove(buf, len, uio);
 1217                         tty_lock(tp);
 1218 
 1219                         if (error != 0)
 1220                                 break;
 1221                 }
 1222         } else {
 1223                 error = ttyoutq_read_uio(&tp->t_outq, tp, uio);
 1224 
 1225                 ttydisc_wakeup_watermark(tp);
 1226                 atomic_add_long(&tty_nout, obytes - uio->uio_resid);
 1227         }
 1228 
 1229         return (error);
 1230 }
 1231 
 1232 size_t
 1233 ttydisc_getc_poll(struct tty *tp)
 1234 {
 1235 
 1236         tty_lock_assert(tp, MA_OWNED);
 1237 
 1238         if (tp->t_flags & TF_STOPPED)
 1239                 return (0);
 1240 
 1241         if (ttyhook_hashook(tp, getc_poll))
 1242                 return ttyhook_getc_poll(tp);
 1243 
 1244         return ttyoutq_bytesused(&tp->t_outq);
 1245 }
 1246 
 1247 /*
 1248  * XXX: not really related to the TTYDISC, but we'd better put
 1249  * tty_putchar() here, because we need to perform proper output
 1250  * processing.
 1251  */
 1252 
 1253 int
 1254 tty_putchar(struct tty *tp, char c)
 1255 {
 1256         tty_lock_assert(tp, MA_OWNED);
 1257 
 1258         if (tty_gone(tp))
 1259                 return (-1);
 1260 
 1261         ttydisc_echo_force(tp, c, 0);
 1262         tp->t_writepos = tp->t_column;
 1263         ttyinq_reprintpos_set(&tp->t_inq);
 1264 
 1265         ttydevsw_outwakeup(tp);
 1266         return (0);
 1267 }

Cache object: ba8b35207dc39843ff41b94321a8622a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.