LCOV - code coverage report
Current view: top level - tty - tty_ioctl.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 13.5 % 347 47
Test Date: 2025-08-26 15:45:50 Functions: 28.6 % 28 8

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0
       2              : /*
       3              :  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
       4              :  *
       5              :  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
       6              :  * which can be dynamically activated and de-activated by the line
       7              :  * discipline handling modules (like SLIP).
       8              :  */
       9              : 
      10              : #include <linux/bits.h>
      11              : #include <linux/types.h>
      12              : #include <linux/termios.h>
      13              : #include <linux/errno.h>
      14              : #include <linux/sched/signal.h>
      15              : #include <linux/kernel.h>
      16              : #include <linux/major.h>
      17              : #include <linux/tty.h>
      18              : #include <linux/fcntl.h>
      19              : #include <linux/string.h>
      20              : #include <linux/mm.h>
      21              : #include <linux/module.h>
      22              : #include <linux/bitops.h>
      23              : #include <linux/mutex.h>
      24              : #include <linux/compat.h>
      25              : #include <linux/termios_internal.h>
      26              : #include "tty.h"
      27              : 
      28              : #include <asm/io.h>
      29              : #include <linux/uaccess.h>
      30              : 
      31              : #undef  DEBUG
      32              : 
      33              : /*
      34              :  * Internal flag options for termios setting behavior
      35              :  */
      36              : #define TERMIOS_FLUSH   BIT(0)
      37              : #define TERMIOS_WAIT    BIT(1)
      38              : #define TERMIOS_TERMIO  BIT(2)
      39              : #define TERMIOS_OLD     BIT(3)
      40              : 
      41              : /**
      42              :  * tty_chars_in_buffer - characters pending
      43              :  * @tty: terminal
      44              :  *
      45              :  * Returns: the number of bytes of data in the device private output queue. If
      46              :  * no private method is supplied there is assumed to be no queue on the device.
      47              :  */
      48           92 : unsigned int tty_chars_in_buffer(struct tty_struct *tty)
      49              : {
      50           92 :         if (tty->ops->chars_in_buffer)
      51           53 :                 return tty->ops->chars_in_buffer(tty);
      52           39 :         return 0;
      53           92 : }
      54              : EXPORT_SYMBOL(tty_chars_in_buffer);
      55              : 
      56              : /**
      57              :  * tty_write_room - write queue space
      58              :  * @tty: terminal
      59              :  *
      60              :  * Returns: the number of bytes that can be queued to this device at the present
      61              :  * time. The result should be treated as a guarantee and the driver cannot
      62              :  * offer a value it later shrinks by more than the number of bytes written. If
      63              :  * no method is provided, 2K is always returned and data may be lost as there
      64              :  * will be no flow control.
      65              :  */
      66          146 : unsigned int tty_write_room(struct tty_struct *tty)
      67              : {
      68          146 :         if (tty->ops->write_room)
      69          146 :                 return tty->ops->write_room(tty);
      70            0 :         return 2048;
      71          146 : }
      72              : EXPORT_SYMBOL(tty_write_room);
      73              : 
      74              : /**
      75              :  * tty_driver_flush_buffer - discard internal buffer
      76              :  * @tty: terminal
      77              :  *
      78              :  * Discard the internal output buffer for this device. If no method is provided,
      79              :  * then either the buffer cannot be hardware flushed or there is no buffer
      80              :  * driver side.
      81              :  */
      82            0 : void tty_driver_flush_buffer(struct tty_struct *tty)
      83              : {
      84            0 :         if (tty->ops->flush_buffer)
      85            0 :                 tty->ops->flush_buffer(tty);
      86            0 : }
      87              : EXPORT_SYMBOL(tty_driver_flush_buffer);
      88              : 
      89              : /**
      90              :  * tty_unthrottle - flow control
      91              :  * @tty: terminal
      92              :  *
      93              :  * Indicate that a @tty may continue transmitting data down the stack. Takes
      94              :  * the &tty_struct->termios_rwsem to protect against parallel
      95              :  * throttle/unthrottle and also to ensure the driver can consistently reference
      96              :  * its own termios data at this point when implementing software flow control.
      97              :  *
      98              :  * Drivers should however remember that the stack can issue a throttle, then
      99              :  * change flow control method, then unthrottle.
     100              :  */
     101           12 : void tty_unthrottle(struct tty_struct *tty)
     102              : {
     103           12 :         down_write(&tty->termios_rwsem);
     104           12 :         if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
     105            0 :             tty->ops->unthrottle)
     106            0 :                 tty->ops->unthrottle(tty);
     107           12 :         tty->flow_change = TTY_FLOW_NO_CHANGE;
     108           12 :         up_write(&tty->termios_rwsem);
     109           12 : }
     110              : EXPORT_SYMBOL(tty_unthrottle);
     111              : 
     112              : /**
     113              :  * tty_throttle_safe - flow control
     114              :  * @tty: terminal
     115              :  *
     116              :  * Indicate that a @tty should stop transmitting data down the stack.
     117              :  * tty_throttle_safe() will only attempt throttle if @tty->flow_change is
     118              :  * %TTY_THROTTLE_SAFE. Prevents an accidental throttle due to race conditions
     119              :  * when throttling is conditional on factors evaluated prior to throttling.
     120              :  *
     121              :  * Returns: %true if @tty is throttled (or was already throttled)
     122              :  */
     123            0 : bool tty_throttle_safe(struct tty_struct *tty)
     124              : {
     125            0 :         guard(mutex)(&tty->throttle_mutex);
     126              : 
     127            0 :         if (tty_throttled(tty))
     128            0 :                 return true;
     129              : 
     130            0 :         if (tty->flow_change != TTY_THROTTLE_SAFE)
     131            0 :                 return false;
     132              : 
     133            0 :         set_bit(TTY_THROTTLED, &tty->flags);
     134            0 :         if (tty->ops->throttle)
     135            0 :                 tty->ops->throttle(tty);
     136              : 
     137            0 :         return true;
     138            0 : }
     139              : 
     140              : /**
     141              :  * tty_unthrottle_safe - flow control
     142              :  * @tty: terminal
     143              :  *
     144              :  * Similar to tty_unthrottle() but will only attempt unthrottle if
     145              :  * @tty->flow_change is %TTY_UNTHROTTLE_SAFE. Prevents an accidental unthrottle
     146              :  * due to race conditions when unthrottling is conditional on factors evaluated
     147              :  * prior to unthrottling.
     148              :  *
     149              :  * Returns: %true if @tty is unthrottled (or was already unthrottled)
     150              :  */
     151            0 : bool tty_unthrottle_safe(struct tty_struct *tty)
     152              : {
     153            0 :         guard(mutex)(&tty->throttle_mutex);
     154              : 
     155            0 :         if (!tty_throttled(tty))
     156            0 :                 return true;
     157              : 
     158            0 :         if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
     159            0 :                 return false;
     160              : 
     161            0 :         clear_bit(TTY_THROTTLED, &tty->flags);
     162            0 :         if (tty->ops->unthrottle)
     163            0 :                 tty->ops->unthrottle(tty);
     164              : 
     165            0 :         return true;
     166            0 : }
     167              : 
     168              : /**
     169              :  * tty_wait_until_sent - wait for I/O to finish
     170              :  * @tty: tty we are waiting for
     171              :  * @timeout: how long we will wait
     172              :  *
     173              :  * Wait for characters pending in a tty driver to hit the wire, or for a
     174              :  * timeout to occur (eg due to flow control).
     175              :  *
     176              :  * Locking: none
     177              :  */
     178              : 
     179            6 : void tty_wait_until_sent(struct tty_struct *tty, long timeout)
     180              : {
     181            6 :         if (!timeout)
     182            0 :                 timeout = MAX_SCHEDULE_TIMEOUT;
     183              : 
     184            6 :         timeout = wait_event_interruptible_timeout(tty->write_wait,
     185              :                         !tty_chars_in_buffer(tty), timeout);
     186            6 :         if (timeout <= 0)
     187            0 :                 return;
     188              : 
     189            6 :         if (timeout == MAX_SCHEDULE_TIMEOUT)
     190            0 :                 timeout = 0;
     191              : 
     192            6 :         if (tty->ops->wait_until_sent)
     193            0 :                 tty->ops->wait_until_sent(tty, timeout);
     194            6 : }
     195              : EXPORT_SYMBOL(tty_wait_until_sent);
     196              : 
     197              : 
     198              : /*
     199              :  *              Termios Helper Methods
     200              :  */
     201              : 
     202            0 : static void unset_locked_termios(struct tty_struct *tty, const struct ktermios *old)
     203              : {
     204            0 :         struct ktermios *termios = &tty->termios;
     205            0 :         struct ktermios *locked  = &tty->termios_locked;
     206            0 :         int     i;
     207              : 
     208              : #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
     209              : 
     210            0 :         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
     211            0 :         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
     212            0 :         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
     213            0 :         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
     214            0 :         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
     215            0 :         for (i = 0; i < NCCS; i++)
     216            0 :                 termios->c_cc[i] = locked->c_cc[i] ?
     217            0 :                         old->c_cc[i] : termios->c_cc[i];
     218              :         /* FIXME: What should we do for i/ospeed */
     219            0 : }
     220              : 
     221              : /**
     222              :  * tty_termios_copy_hw - copy hardware settings
     223              :  * @new: new termios
     224              :  * @old: old termios
     225              :  *
     226              :  * Propagate the hardware specific terminal setting bits from the @old termios
     227              :  * structure to the @new one. This is used in cases where the hardware does not
     228              :  * support reconfiguration or as a helper in some cases where only minimal
     229              :  * reconfiguration is supported.
     230              :  */
     231            0 : void tty_termios_copy_hw(struct ktermios *new, const struct ktermios *old)
     232              : {
     233              :         /* The bits a dumb device handles in software. Smart devices need
     234              :            to always provide a set_termios method */
     235            0 :         new->c_cflag &= HUPCL | CREAD | CLOCAL;
     236            0 :         new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
     237            0 :         new->c_ispeed = old->c_ispeed;
     238            0 :         new->c_ospeed = old->c_ospeed;
     239            0 : }
     240              : EXPORT_SYMBOL(tty_termios_copy_hw);
     241              : 
     242              : /**
     243              :  * tty_termios_hw_change - check for setting change
     244              :  * @a: termios
     245              :  * @b: termios to compare
     246              :  *
     247              :  * Check if any of the bits that affect a dumb device have changed between the
     248              :  * two termios structures, or a speed change is needed.
     249              :  *
     250              :  * Returns: %true if change is needed
     251              :  */
     252            0 : bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
     253              : {
     254            0 :         if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
     255            0 :                 return true;
     256            0 :         if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
     257            0 :                 return true;
     258            0 :         return false;
     259            0 : }
     260              : EXPORT_SYMBOL(tty_termios_hw_change);
     261              : 
     262              : /**
     263              :  * tty_get_char_size - get size of a character
     264              :  * @cflag: termios cflag value
     265              :  *
     266              :  * Returns: size (in bits) of a character depending on @cflag's %CSIZE setting
     267              :  */
     268            0 : unsigned char tty_get_char_size(unsigned int cflag)
     269              : {
     270            0 :         switch (cflag & CSIZE) {
     271              :         case CS5:
     272            0 :                 return 5;
     273              :         case CS6:
     274            0 :                 return 6;
     275              :         case CS7:
     276            0 :                 return 7;
     277            0 :         case CS8:
     278              :         default:
     279            0 :                 return 8;
     280              :         }
     281            0 : }
     282              : EXPORT_SYMBOL_GPL(tty_get_char_size);
     283              : 
     284              : /**
     285              :  * tty_get_frame_size - get size of a frame
     286              :  * @cflag: termios cflag value
     287              :  *
     288              :  * Get the size (in bits) of a frame depending on @cflag's %CSIZE, %CSTOPB, and
     289              :  * %PARENB setting. The result is a sum of character size, start and stop bits
     290              :  * -- one bit each -- second stop bit (if set), and parity bit (if set).
     291              :  *
     292              :  * Returns: size (in bits) of a frame depending on @cflag's setting.
     293              :  */
     294            0 : unsigned char tty_get_frame_size(unsigned int cflag)
     295              : {
     296            0 :         unsigned char bits = 2 + tty_get_char_size(cflag);
     297              : 
     298            0 :         if (cflag & CSTOPB)
     299            0 :                 bits++;
     300            0 :         if (cflag & PARENB)
     301            0 :                 bits++;
     302            0 :         if (cflag & ADDRB)
     303            0 :                 bits++;
     304              : 
     305            0 :         return bits;
     306            0 : }
     307              : EXPORT_SYMBOL_GPL(tty_get_frame_size);
     308              : 
     309              : /**
     310              :  * tty_set_termios - update termios values
     311              :  * @tty: tty to update
     312              :  * @new_termios: desired new value
     313              :  *
     314              :  * Perform updates to the termios values set on this @tty. A master pty's
     315              :  * termios should never be set.
     316              :  *
     317              :  * Locking: &tty_struct->termios_rwsem
     318              :  */
     319            0 : int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
     320              : {
     321            0 :         struct ktermios old_termios;
     322            0 :         struct tty_ldisc *ld;
     323              : 
     324            0 :         WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
     325              :                 tty->driver->subtype == PTY_TYPE_MASTER);
     326              :         /*
     327              :          *      Perform the actual termios internal changes under lock.
     328              :          */
     329              : 
     330              : 
     331              :         /* FIXME: we need to decide on some locking/ordering semantics
     332              :            for the set_termios notification eventually */
     333            0 :         down_write(&tty->termios_rwsem);
     334            0 :         old_termios = tty->termios;
     335            0 :         tty->termios = *new_termios;
     336            0 :         unset_locked_termios(tty, &old_termios);
     337              :         /* Reset any ADDRB changes, ADDRB is changed through ->rs485_config() */
     338            0 :         tty->termios.c_cflag ^= (tty->termios.c_cflag ^ old_termios.c_cflag) & ADDRB;
     339              : 
     340            0 :         if (tty->ops->set_termios)
     341            0 :                 tty->ops->set_termios(tty, &old_termios);
     342              :         else
     343            0 :                 tty_termios_copy_hw(&tty->termios, &old_termios);
     344              : 
     345            0 :         ld = tty_ldisc_ref(tty);
     346            0 :         if (ld != NULL) {
     347            0 :                 if (ld->ops->set_termios)
     348            0 :                         ld->ops->set_termios(tty, &old_termios);
     349            0 :                 tty_ldisc_deref(ld);
     350            0 :         }
     351            0 :         up_write(&tty->termios_rwsem);
     352            0 :         return 0;
     353            0 : }
     354              : EXPORT_SYMBOL_GPL(tty_set_termios);
     355              : 
     356              : 
     357              : /*
     358              :  * Translate a "termio" structure into a "termios". Ugh.
     359              :  */
     360            0 : __weak int user_termio_to_kernel_termios(struct ktermios *termios,
     361              :                                                 struct termio __user *termio)
     362              : {
     363            0 :         struct termio v;
     364              : 
     365            0 :         if (copy_from_user(&v, termio, sizeof(struct termio)))
     366            0 :                 return -EFAULT;
     367              : 
     368            0 :         termios->c_iflag = (0xffff0000 & termios->c_iflag) | v.c_iflag;
     369            0 :         termios->c_oflag = (0xffff0000 & termios->c_oflag) | v.c_oflag;
     370            0 :         termios->c_cflag = (0xffff0000 & termios->c_cflag) | v.c_cflag;
     371            0 :         termios->c_lflag = (0xffff0000 & termios->c_lflag) | v.c_lflag;
     372            0 :         termios->c_line = (0xffff0000 & termios->c_lflag) | v.c_line;
     373            0 :         memcpy(termios->c_cc, v.c_cc, NCC);
     374            0 :         return 0;
     375            0 : }
     376              : 
     377              : /*
     378              :  * Translate a "termios" structure into a "termio". Ugh.
     379              :  */
     380            0 : __weak int kernel_termios_to_user_termio(struct termio __user *termio,
     381              :                                                 struct ktermios *termios)
     382              : {
     383            0 :         struct termio v;
     384            0 :         memset(&v, 0, sizeof(struct termio));
     385            0 :         v.c_iflag = termios->c_iflag;
     386            0 :         v.c_oflag = termios->c_oflag;
     387            0 :         v.c_cflag = termios->c_cflag;
     388            0 :         v.c_lflag = termios->c_lflag;
     389            0 :         v.c_line = termios->c_line;
     390            0 :         memcpy(v.c_cc, termios->c_cc, NCC);
     391            0 :         return copy_to_user(termio, &v, sizeof(struct termio));
     392            0 : }
     393              : 
     394              : #ifdef TCGETS2
     395            0 : __weak int user_termios_to_kernel_termios(struct ktermios *k,
     396              :                                                  struct termios2 __user *u)
     397              : {
     398            0 :         return copy_from_user(k, u, sizeof(struct termios2));
     399              : }
     400            0 : __weak int kernel_termios_to_user_termios(struct termios2 __user *u,
     401              :                                                  struct ktermios *k)
     402              : {
     403            0 :         return copy_to_user(u, k, sizeof(struct termios2));
     404              : }
     405            0 : __weak int user_termios_to_kernel_termios_1(struct ktermios *k,
     406              :                                                    struct termios __user *u)
     407              : {
     408            0 :         return copy_from_user(k, u, sizeof(struct termios));
     409              : }
     410           18 : __weak int kernel_termios_to_user_termios_1(struct termios __user *u,
     411              :                                                    struct ktermios *k)
     412              : {
     413           18 :         return copy_to_user(u, k, sizeof(struct termios));
     414              : }
     415              : 
     416              : #else
     417              : 
     418              : __weak int user_termios_to_kernel_termios(struct ktermios *k,
     419              :                                                  struct termios __user *u)
     420              : {
     421              :         return copy_from_user(k, u, sizeof(struct termios));
     422              : }
     423              : __weak int kernel_termios_to_user_termios(struct termios __user *u,
     424              :                                                  struct ktermios *k)
     425              : {
     426              :         return copy_to_user(u, k, sizeof(struct termios));
     427              : }
     428              : #endif /* TCGETS2 */
     429              : 
     430              : /**
     431              :  * set_termios - set termios values for a tty
     432              :  * @tty: terminal device
     433              :  * @arg: user data
     434              :  * @opt: option information
     435              :  *
     436              :  * Helper function to prepare termios data and run necessary other functions
     437              :  * before using tty_set_termios() to do the actual changes.
     438              :  *
     439              :  * Locking: called functions take &tty_struct->ldisc_sem and
     440              :  * &tty_struct->termios_rwsem locks
     441              :  *
     442              :  * Returns: 0 on success, an error otherwise
     443              :  */
     444            0 : static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
     445              : {
     446            0 :         struct ktermios tmp_termios;
     447            0 :         struct tty_ldisc *ld;
     448            0 :         int retval = tty_check_change(tty);
     449              : 
     450            0 :         if (retval)
     451            0 :                 return retval;
     452              : 
     453            0 :         down_read(&tty->termios_rwsem);
     454            0 :         tmp_termios = tty->termios;
     455            0 :         up_read(&tty->termios_rwsem);
     456              : 
     457            0 :         if (opt & TERMIOS_TERMIO) {
     458            0 :                 if (user_termio_to_kernel_termios(&tmp_termios,
     459            0 :                                                 (struct termio __user *)arg))
     460            0 :                         return -EFAULT;
     461              : #ifdef TCGETS2
     462            0 :         } else if (opt & TERMIOS_OLD) {
     463            0 :                 if (user_termios_to_kernel_termios_1(&tmp_termios,
     464            0 :                                                 (struct termios __user *)arg))
     465            0 :                         return -EFAULT;
     466            0 :         } else {
     467            0 :                 if (user_termios_to_kernel_termios(&tmp_termios,
     468            0 :                                                 (struct termios2 __user *)arg))
     469            0 :                         return -EFAULT;
     470              :         }
     471              : #else
     472              :         } else if (user_termios_to_kernel_termios(&tmp_termios,
     473              :                                         (struct termios __user *)arg))
     474              :                 return -EFAULT;
     475              : #endif
     476              : 
     477              :         /* If old style Bfoo values are used then load c_ispeed/c_ospeed
     478              :          * with the real speed so its unconditionally usable */
     479            0 :         tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
     480            0 :         tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
     481              : 
     482            0 :         if (opt & (TERMIOS_FLUSH|TERMIOS_WAIT)) {
     483              : retry_write_wait:
     484            0 :                 retval = wait_event_interruptible(tty->write_wait, !tty_chars_in_buffer(tty));
     485            0 :                 if (retval < 0)
     486            0 :                         return retval;
     487              : 
     488            0 :                 if (tty_write_lock(tty, false) < 0)
     489            0 :                         goto retry_write_wait;
     490              : 
     491              :                 /* Racing writer? */
     492            0 :                 if (tty_chars_in_buffer(tty)) {
     493            0 :                         tty_write_unlock(tty);
     494            0 :                         goto retry_write_wait;
     495              :                 }
     496              : 
     497            0 :                 ld = tty_ldisc_ref(tty);
     498            0 :                 if (ld != NULL) {
     499            0 :                         if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
     500            0 :                                 ld->ops->flush_buffer(tty);
     501            0 :                         tty_ldisc_deref(ld);
     502            0 :                 }
     503              : 
     504            0 :                 if ((opt & TERMIOS_WAIT) && tty->ops->wait_until_sent) {
     505            0 :                         tty->ops->wait_until_sent(tty, 0);
     506            0 :                         if (signal_pending(current)) {
     507            0 :                                 tty_write_unlock(tty);
     508            0 :                                 return -ERESTARTSYS;
     509              :                         }
     510            0 :                 }
     511              : 
     512            0 :                 tty_set_termios(tty, &tmp_termios);
     513              : 
     514            0 :                 tty_write_unlock(tty);
     515            0 :         } else {
     516            0 :                 tty_set_termios(tty, &tmp_termios);
     517              :         }
     518              : 
     519              :         /* FIXME: Arguably if tmp_termios == tty->termios AND the
     520              :            actual requested termios was not tmp_termios then we may
     521              :            want to return an error as no user requested change has
     522              :            succeeded */
     523            0 :         return 0;
     524            0 : }
     525              : 
     526           18 : static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
     527              : {
     528           18 :         down_read(&tty->termios_rwsem);
     529           18 :         *kterm = tty->termios;
     530           18 :         up_read(&tty->termios_rwsem);
     531           18 : }
     532              : 
     533            0 : static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
     534              : {
     535            0 :         down_read(&tty->termios_rwsem);
     536            0 :         *kterm = tty->termios_locked;
     537            0 :         up_read(&tty->termios_rwsem);
     538            0 : }
     539              : 
     540            0 : static int get_termio(struct tty_struct *tty, struct termio __user *termio)
     541              : {
     542            0 :         struct ktermios kterm;
     543            0 :         copy_termios(tty, &kterm);
     544            0 :         if (kernel_termios_to_user_termio(termio, &kterm))
     545            0 :                 return -EFAULT;
     546            0 :         return 0;
     547            0 : }
     548              : 
     549              : #ifdef TIOCGETP
     550              : /*
     551              :  * These are deprecated, but there is limited support..
     552              :  *
     553              :  * The "sg_flags" translation is a joke..
     554              :  */
     555              : static int get_sgflags(struct tty_struct *tty)
     556              : {
     557              :         int flags = 0;
     558              : 
     559              :         if (!L_ICANON(tty)) {
     560              :                 if (L_ISIG(tty))
     561              :                         flags |= 0x02;          /* cbreak */
     562              :                 else
     563              :                         flags |= 0x20;          /* raw */
     564              :         }
     565              :         if (L_ECHO(tty))
     566              :                 flags |= 0x08;                  /* echo */
     567              :         if (O_OPOST(tty))
     568              :                 if (O_ONLCR(tty))
     569              :                         flags |= 0x10;          /* crmod */
     570              :         return flags;
     571              : }
     572              : 
     573              : static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     574              : {
     575              :         struct sgttyb tmp;
     576              : 
     577              :         down_read(&tty->termios_rwsem);
     578              :         tmp.sg_ispeed = tty->termios.c_ispeed;
     579              :         tmp.sg_ospeed = tty->termios.c_ospeed;
     580              :         tmp.sg_erase = tty->termios.c_cc[VERASE];
     581              :         tmp.sg_kill = tty->termios.c_cc[VKILL];
     582              :         tmp.sg_flags = get_sgflags(tty);
     583              :         up_read(&tty->termios_rwsem);
     584              : 
     585              :         return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     586              : }
     587              : 
     588              : static void set_sgflags(struct ktermios *termios, int flags)
     589              : {
     590              :         termios->c_iflag = ICRNL | IXON;
     591              :         termios->c_oflag = 0;
     592              :         termios->c_lflag = ISIG | ICANON;
     593              :         if (flags & 0x02) { /* cbreak */
     594              :                 termios->c_iflag = 0;
     595              :                 termios->c_lflag &= ~ICANON;
     596              :         }
     597              :         if (flags & 0x08) {         /* echo */
     598              :                 termios->c_lflag |= ECHO | ECHOE | ECHOK |
     599              :                                     ECHOCTL | ECHOKE | IEXTEN;
     600              :         }
     601              :         if (flags & 0x10) {         /* crmod */
     602              :                 termios->c_oflag |= OPOST | ONLCR;
     603              :         }
     604              :         if (flags & 0x20) { /* raw */
     605              :                 termios->c_iflag = 0;
     606              :                 termios->c_lflag &= ~(ISIG | ICANON);
     607              :         }
     608              :         if (!(termios->c_lflag & ICANON)) {
     609              :                 termios->c_cc[VMIN] = 1;
     610              :                 termios->c_cc[VTIME] = 0;
     611              :         }
     612              : }
     613              : 
     614              : /**
     615              :  * set_sgttyb - set legacy terminal values
     616              :  * @tty: tty structure
     617              :  * @sgttyb: pointer to old style terminal structure
     618              :  *
     619              :  * Updates a terminal from the legacy BSD style terminal information structure.
     620              :  *
     621              :  * Locking: &tty_struct->termios_rwsem
     622              :  *
     623              :  * Returns: 0 on success, an error otherwise
     624              :  */
     625              : static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     626              : {
     627              :         int retval;
     628              :         struct sgttyb tmp;
     629              :         struct ktermios termios;
     630              : 
     631              :         retval = tty_check_change(tty);
     632              :         if (retval)
     633              :                 return retval;
     634              : 
     635              :         if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
     636              :                 return -EFAULT;
     637              : 
     638              :         down_write(&tty->termios_rwsem);
     639              :         termios = tty->termios;
     640              :         termios.c_cc[VERASE] = tmp.sg_erase;
     641              :         termios.c_cc[VKILL] = tmp.sg_kill;
     642              :         set_sgflags(&termios, tmp.sg_flags);
     643              :         /* Try and encode into Bfoo format */
     644              :         tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
     645              :                                                 termios.c_ospeed);
     646              :         up_write(&tty->termios_rwsem);
     647              :         tty_set_termios(tty, &termios);
     648              :         return 0;
     649              : }
     650              : #endif
     651              : 
     652              : #ifdef TIOCGETC
     653              : static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     654              : {
     655              :         struct tchars tmp;
     656              : 
     657              :         down_read(&tty->termios_rwsem);
     658              :         tmp.t_intrc = tty->termios.c_cc[VINTR];
     659              :         tmp.t_quitc = tty->termios.c_cc[VQUIT];
     660              :         tmp.t_startc = tty->termios.c_cc[VSTART];
     661              :         tmp.t_stopc = tty->termios.c_cc[VSTOP];
     662              :         tmp.t_eofc = tty->termios.c_cc[VEOF];
     663              :         tmp.t_brkc = tty->termios.c_cc[VEOL2];       /* what is brkc anyway? */
     664              :         up_read(&tty->termios_rwsem);
     665              :         return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     666              : }
     667              : 
     668              : static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     669              : {
     670              :         struct tchars tmp;
     671              : 
     672              :         if (copy_from_user(&tmp, tchars, sizeof(tmp)))
     673              :                 return -EFAULT;
     674              :         down_write(&tty->termios_rwsem);
     675              :         tty->termios.c_cc[VINTR] = tmp.t_intrc;
     676              :         tty->termios.c_cc[VQUIT] = tmp.t_quitc;
     677              :         tty->termios.c_cc[VSTART] = tmp.t_startc;
     678              :         tty->termios.c_cc[VSTOP] = tmp.t_stopc;
     679              :         tty->termios.c_cc[VEOF] = tmp.t_eofc;
     680              :         tty->termios.c_cc[VEOL2] = tmp.t_brkc;       /* what is brkc anyway? */
     681              :         up_write(&tty->termios_rwsem);
     682              :         return 0;
     683              : }
     684              : #endif
     685              : 
     686              : #ifdef TIOCGLTC
     687              : static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     688              : {
     689              :         struct ltchars tmp;
     690              : 
     691              :         down_read(&tty->termios_rwsem);
     692              :         tmp.t_suspc = tty->termios.c_cc[VSUSP];
     693              :         /* what is dsuspc anyway? */
     694              :         tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
     695              :         tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
     696              :         /* what is flushc anyway? */
     697              :         tmp.t_flushc = tty->termios.c_cc[VEOL2];
     698              :         tmp.t_werasc = tty->termios.c_cc[VWERASE];
     699              :         tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
     700              :         up_read(&tty->termios_rwsem);
     701              :         return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     702              : }
     703              : 
     704              : static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     705              : {
     706              :         struct ltchars tmp;
     707              : 
     708              :         if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
     709              :                 return -EFAULT;
     710              : 
     711              :         down_write(&tty->termios_rwsem);
     712              :         tty->termios.c_cc[VSUSP] = tmp.t_suspc;
     713              :         /* what is dsuspc anyway? */
     714              :         tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
     715              :         tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
     716              :         /* what is flushc anyway? */
     717              :         tty->termios.c_cc[VEOL2] = tmp.t_flushc;
     718              :         tty->termios.c_cc[VWERASE] = tmp.t_werasc;
     719              :         tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
     720              :         up_write(&tty->termios_rwsem);
     721              :         return 0;
     722              : }
     723              : #endif
     724              : 
     725              : /**
     726              :  * tty_change_softcar - carrier change ioctl helper
     727              :  * @tty: tty to update
     728              :  * @enable: enable/disable %CLOCAL
     729              :  *
     730              :  * Perform a change to the %CLOCAL state and call into the driver layer to make
     731              :  * it visible.
     732              :  *
     733              :  * Locking: &tty_struct->termios_rwsem.
     734              :  *
     735              :  * Returns: 0 on success, an error otherwise
     736              :  */
     737            0 : static int tty_change_softcar(struct tty_struct *tty, bool enable)
     738              : {
     739            0 :         int ret = 0;
     740            0 :         struct ktermios old;
     741            0 :         tcflag_t bit = enable ? CLOCAL : 0;
     742              : 
     743            0 :         down_write(&tty->termios_rwsem);
     744            0 :         old = tty->termios;
     745            0 :         tty->termios.c_cflag &= ~CLOCAL;
     746            0 :         tty->termios.c_cflag |= bit;
     747            0 :         if (tty->ops->set_termios)
     748            0 :                 tty->ops->set_termios(tty, &old);
     749            0 :         if (C_CLOCAL(tty) != bit)
     750            0 :                 ret = -EINVAL;
     751            0 :         up_write(&tty->termios_rwsem);
     752            0 :         return ret;
     753            0 : }
     754              : 
     755              : /**
     756              :  * tty_mode_ioctl - mode related ioctls
     757              :  * @tty: tty for the ioctl
     758              :  * @cmd: command
     759              :  * @arg: ioctl argument
     760              :  *
     761              :  * Perform non-line discipline specific mode control ioctls. This is designed
     762              :  * to be called by line disciplines to ensure they provide consistent mode
     763              :  * setting.
     764              :  */
     765           18 : int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
     766              : {
     767           18 :         struct tty_struct *real_tty;
     768           18 :         void __user *p = (void __user *)arg;
     769           18 :         int ret = 0;
     770           18 :         struct ktermios kterm;
     771              : 
     772           18 :         if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
     773           18 :             tty->driver->subtype == PTY_TYPE_MASTER)
     774            0 :                 real_tty = tty->link;
     775              :         else
     776           18 :                 real_tty = tty;
     777              : 
     778           18 :         switch (cmd) {
     779              : #ifdef TIOCGETP
     780              :         case TIOCGETP:
     781              :                 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
     782              :         case TIOCSETP:
     783              :         case TIOCSETN:
     784              :                 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
     785              : #endif
     786              : #ifdef TIOCGETC
     787              :         case TIOCGETC:
     788              :                 return get_tchars(real_tty, p);
     789              :         case TIOCSETC:
     790              :                 return set_tchars(real_tty, p);
     791              : #endif
     792              : #ifdef TIOCGLTC
     793              :         case TIOCGLTC:
     794              :                 return get_ltchars(real_tty, p);
     795              :         case TIOCSLTC:
     796              :                 return set_ltchars(real_tty, p);
     797              : #endif
     798              :         case TCSETSF:
     799            0 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
     800              :         case TCSETSW:
     801            0 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
     802              :         case TCSETS:
     803            0 :                 return set_termios(real_tty, p, TERMIOS_OLD);
     804              : #ifndef TCGETS2
     805              :         case TCGETS:
     806              :                 copy_termios(real_tty, &kterm);
     807              :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
     808              :                         ret = -EFAULT;
     809              :                 return ret;
     810              : #else
     811              :         case TCGETS:
     812           18 :                 copy_termios(real_tty, &kterm);
     813           18 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
     814            0 :                         ret = -EFAULT;
     815           18 :                 return ret;
     816              :         case TCGETS2:
     817            0 :                 copy_termios(real_tty, &kterm);
     818            0 :                 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
     819            0 :                         ret = -EFAULT;
     820            0 :                 return ret;
     821              :         case TCSETSF2:
     822            0 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
     823              :         case TCSETSW2:
     824            0 :                 return set_termios(real_tty, p, TERMIOS_WAIT);
     825              :         case TCSETS2:
     826            0 :                 return set_termios(real_tty, p, 0);
     827              : #endif
     828              :         case TCGETA:
     829            0 :                 return get_termio(real_tty, p);
     830              :         case TCSETAF:
     831            0 :                 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
     832              :         case TCSETAW:
     833            0 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
     834              :         case TCSETA:
     835            0 :                 return set_termios(real_tty, p, TERMIOS_TERMIO);
     836              : #ifndef TCGETS2
     837              :         case TIOCGLCKTRMIOS:
     838              :                 copy_termios_locked(real_tty, &kterm);
     839              :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
     840              :                         ret = -EFAULT;
     841              :                 return ret;
     842              :         case TIOCSLCKTRMIOS:
     843              :                 if (!checkpoint_restore_ns_capable(&init_user_ns))
     844              :                         return -EPERM;
     845              :                 copy_termios_locked(real_tty, &kterm);
     846              :                 if (user_termios_to_kernel_termios(&kterm,
     847              :                                                (struct termios __user *) arg))
     848              :                         return -EFAULT;
     849              :                 down_write(&real_tty->termios_rwsem);
     850              :                 real_tty->termios_locked = kterm;
     851              :                 up_write(&real_tty->termios_rwsem);
     852              :                 return 0;
     853              : #else
     854              :         case TIOCGLCKTRMIOS:
     855            0 :                 copy_termios_locked(real_tty, &kterm);
     856            0 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
     857            0 :                         ret = -EFAULT;
     858            0 :                 return ret;
     859              :         case TIOCSLCKTRMIOS:
     860            0 :                 if (!checkpoint_restore_ns_capable(&init_user_ns))
     861            0 :                         return -EPERM;
     862            0 :                 copy_termios_locked(real_tty, &kterm);
     863            0 :                 if (user_termios_to_kernel_termios_1(&kterm,
     864            0 :                                                (struct termios __user *) arg))
     865            0 :                         return -EFAULT;
     866            0 :                 down_write(&real_tty->termios_rwsem);
     867            0 :                 real_tty->termios_locked = kterm;
     868            0 :                 up_write(&real_tty->termios_rwsem);
     869            0 :                 return ret;
     870              : #endif
     871              : #ifdef TCGETX
     872              :         case TCGETX:
     873              :         case TCSETX:
     874              :         case TCSETXW:
     875              :         case TCSETXF:
     876            0 :                 return -ENOTTY;
     877              : #endif
     878              :         case TIOCGSOFTCAR:
     879            0 :                 copy_termios(real_tty, &kterm);
     880            0 :                 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
     881              :                                                 (int __user *)arg);
     882            0 :                 return ret;
     883              :         case TIOCSSOFTCAR:
     884            0 :                 if (get_user(arg, (unsigned int __user *) arg))
     885            0 :                         return -EFAULT;
     886            0 :                 return tty_change_softcar(real_tty, arg);
     887              :         default:
     888            0 :                 return -ENOIOCTLCMD;
     889              :         }
     890           18 : }
     891              : EXPORT_SYMBOL_GPL(tty_mode_ioctl);
     892              : 
     893              : 
     894              : /* Caller guarantees ldisc reference is held */
     895            0 : static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
     896              : {
     897            0 :         struct tty_ldisc *ld = tty->ldisc;
     898              : 
     899            0 :         switch (arg) {
     900              :         case TCIFLUSH:
     901            0 :                 if (ld && ld->ops->flush_buffer) {
     902            0 :                         ld->ops->flush_buffer(tty);
     903            0 :                         tty_unthrottle(tty);
     904            0 :                 }
     905            0 :                 break;
     906              :         case TCIOFLUSH:
     907            0 :                 if (ld && ld->ops->flush_buffer) {
     908            0 :                         ld->ops->flush_buffer(tty);
     909            0 :                         tty_unthrottle(tty);
     910            0 :                 }
     911              :                 fallthrough;
     912              :         case TCOFLUSH:
     913            0 :                 tty_driver_flush_buffer(tty);
     914            0 :                 break;
     915              :         default:
     916            0 :                 return -EINVAL;
     917              :         }
     918            0 :         return 0;
     919            0 : }
     920              : 
     921            0 : int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
     922              : {
     923            0 :         struct tty_ldisc *ld;
     924            0 :         int retval = tty_check_change(tty);
     925            0 :         if (retval)
     926            0 :                 return retval;
     927              : 
     928            0 :         ld = tty_ldisc_ref_wait(tty);
     929            0 :         retval = __tty_perform_flush(tty, arg);
     930            0 :         if (ld)
     931            0 :                 tty_ldisc_deref(ld);
     932            0 :         return retval;
     933            0 : }
     934              : EXPORT_SYMBOL_GPL(tty_perform_flush);
     935              : 
     936           18 : int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd,
     937              :                 unsigned long arg)
     938              : {
     939           18 :         int retval;
     940              : 
     941           18 :         switch (cmd) {
     942              :         case TCXONC:
     943            0 :                 retval = tty_check_change(tty);
     944            0 :                 if (retval)
     945            0 :                         return retval;
     946            0 :                 switch (arg) {
     947              :                 case TCOOFF:
     948            0 :                         spin_lock_irq(&tty->flow.lock);
     949            0 :                         if (!tty->flow.tco_stopped) {
     950            0 :                                 tty->flow.tco_stopped = true;
     951            0 :                                 __stop_tty(tty);
     952            0 :                         }
     953            0 :                         spin_unlock_irq(&tty->flow.lock);
     954            0 :                         break;
     955              :                 case TCOON:
     956            0 :                         spin_lock_irq(&tty->flow.lock);
     957            0 :                         if (tty->flow.tco_stopped) {
     958            0 :                                 tty->flow.tco_stopped = false;
     959            0 :                                 __start_tty(tty);
     960            0 :                         }
     961            0 :                         spin_unlock_irq(&tty->flow.lock);
     962            0 :                         break;
     963              :                 case TCIOFF:
     964            0 :                         if (STOP_CHAR(tty) != __DISABLED_CHAR)
     965            0 :                                 retval = tty_send_xchar(tty, STOP_CHAR(tty));
     966            0 :                         break;
     967              :                 case TCION:
     968            0 :                         if (START_CHAR(tty) != __DISABLED_CHAR)
     969            0 :                                 retval = tty_send_xchar(tty, START_CHAR(tty));
     970            0 :                         break;
     971              :                 default:
     972            0 :                         return -EINVAL;
     973              :                 }
     974            0 :                 return retval;
     975              :         case TCFLSH:
     976            0 :                 retval = tty_check_change(tty);
     977            0 :                 if (retval)
     978            0 :                         return retval;
     979            0 :                 return __tty_perform_flush(tty, arg);
     980              :         default:
     981              :                 /* Try the mode commands */
     982           18 :                 return tty_mode_ioctl(tty, cmd, arg);
     983              :         }
     984           18 : }
     985              : EXPORT_SYMBOL(n_tty_ioctl_helper);
        

Generated by: LCOV version 2.0-1