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

Cache object: 411af714ffa240ca2b609cd50546700e


[ 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.