cregit-Linux how code gets into the kernel

Release 4.14 drivers/tty/pty.c

Directory: drivers/tty
// SPDX-License-Identifier: GPL-2.0
/*
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Added support for a Unix98-style ptmx device.
 *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
 *
 */

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/fcntl.h>
#include <linux/sched/signal.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/devpts_fs.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/mount.h>
#include <linux/file.h>
#include <linux/ioctl.h>


#undef TTY_DEBUG_HANGUP
#ifdef TTY_DEBUG_HANGUP

# define tty_debug_hangup(tty, f, args...)	tty_debug(tty, f, ##args)
#else

# define tty_debug_hangup(tty, f, args...)	do {} while (0)
#endif

#ifdef CONFIG_UNIX98_PTYS

static struct tty_driver *ptm_driver;

static struct tty_driver *pts_driver;
static DEFINE_MUTEX(devpts_mutex);
#endif


static void pty_close(struct tty_struct *tty, struct file *filp) { BUG_ON(!tty); if (tty->driver->subtype == PTY_TYPE_MASTER) WARN_ON(tty->count > 1); else { if (tty_io_error(tty)) return; if (tty->count > 2) return; } set_bit(TTY_IO_ERROR, &tty->flags); wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); spin_lock_irq(&tty->ctrl_lock); tty->packet = 0; spin_unlock_irq(&tty->ctrl_lock); /* Review - krefs on tty_link ?? */ if (!tty->link) return; set_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS if (tty->driver == ptm_driver) { mutex_lock(&devpts_mutex); if (tty->link->driver_data) devpts_pty_kill(tty->link->driver_data); mutex_unlock(&devpts_mutex); } #endif tty_vhangup(tty->link); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13058.30%1346.43%
Peter Hurley4218.83%414.29%
Alan Cox219.42%310.71%
Greg Kroah-Hartman135.83%13.57%
Zou Nan hai62.69%13.57%
Brian Bloniarz31.35%13.57%
Jiri Slaby20.90%13.57%
Al Viro20.90%13.57%
Eric W. Biedermann20.90%13.57%
Arnd Bergmann10.45%13.57%
Sukadev Bhattiprolu10.45%13.57%
Total223100.00%28100.00%

/* * The unthrottle routine is called by the line discipline to signal * that it can receive more characters. For PTY's, the TTY_THROTTLED * flag is always set, to force the line discipline to always call the * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE * characters in the queue. This is necessary since each time this * happens, we need to wake up any sleeping processes that could be * (1) trying to send data to the pty, or (2) waiting in wait_until_sent() * for the pty buffer to be drained. */
static void pty_unthrottle(struct tty_struct *tty) { tty_wakeup(tty->link); set_bit(TTY_THROTTLED, &tty->flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2692.86%150.00%
Alan Cox27.14%150.00%
Total28100.00%2100.00%

/** * pty_write - write to a pty * @tty: the tty we write from * @buf: kernel buffer of data * @count: bytes to write * * Our "hardware" write method. Data is coming from the ldisc which * may be in a non sleeping state. We simply throw this at the other * end of the link as if we were an IRQ handler receiving stuff for * the other side of the pty/tty pair. */
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) { struct tty_struct *to = tty->link; if (tty->stopped) return 0; if (c > 0) { /* Stuff the data into the input queue of the other end */ c = tty_insert_flip_string(to->port, buf, c); /* And shovel */ if (c) tty_flip_buffer_push(to->port); } return c; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5573.33%654.55%
Alan Cox1013.33%19.09%
Linus Torvalds68.00%218.18%
Jiri Slaby45.33%218.18%
Total75100.00%11100.00%

/** * pty_write_room - write space * @tty: tty we are writing from * * Report how many bytes the ldisc can send into the queue for * the other device. */
static int pty_write_room(struct tty_struct *tty) { if (tty->stopped) return 0; return tty_buffer_space_avail(tty->link->port); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1550.00%125.00%
Linus Torvalds930.00%125.00%
Alan Cox310.00%125.00%
Peter Hurley310.00%125.00%
Total30100.00%4100.00%

/** * pty_chars_in_buffer - characters currently in our tx queue * @tty: our tty * * Report how much we have in the transmit queue. As everything is * instantly at the other end this is easy to implement. */
static int pty_chars_in_buffer(struct tty_struct *tty) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1178.57%266.67%
Alan Cox321.43%133.33%
Total14100.00%3100.00%

/* Set the lock flag on a pty */
static int pty_set_lock(struct tty_struct *tty, int __user *arg) { int val; if (get_user(val, arg)) return -EFAULT; if (val) set_bit(TTY_PTY_LOCK, &tty->flags); else clear_bit(TTY_PTY_LOCK, &tty->flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5998.33%150.00%
Al Viro11.67%150.00%
Total60100.00%2100.00%


static int pty_get_lock(struct tty_struct *tty, int __user *arg) { int locked = test_bit(TTY_PTY_LOCK, &tty->flags); return put_user(locked, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Cyrill V. Gorcunov37100.00%1100.00%
Total37100.00%1100.00%

/* Set the packet mode on a pty */
static int pty_set_pktmode(struct tty_struct *tty, int __user *arg) { int pktmode; if (get_user(pktmode, arg)) return -EFAULT; spin_lock_irq(&tty->ctrl_lock); if (pktmode) { if (!tty->packet) { tty->link->ctrl_status = 0; smp_mb(); tty->packet = 1; } } else tty->packet = 0; spin_unlock_irq(&tty->ctrl_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrill V. Gorcunov7987.78%133.33%
Peter Hurley1112.22%266.67%
Total90100.00%3100.00%

/* Get the packet mode of a pty */
static int pty_get_pktmode(struct tty_struct *tty, int __user *arg) { int pktmode = tty->packet; return put_user(pktmode, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Cyrill V. Gorcunov31100.00%1100.00%
Total31100.00%1100.00%

/* Send a signal to the slave */
static int pty_signal(struct tty_struct *tty, int sig) { struct pid *pgrp; if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP) return -EINVAL; if (tty->link) { pgrp = tty_get_pgrp(tty->link); if (pgrp) kill_pgrp(pgrp, sig, 1); put_pid(pgrp); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Howard Chu5269.33%133.33%
Peter Hurley2330.67%266.67%
Total75100.00%3100.00%


static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; if (!to) return; tty_buffer_flush(to, NULL); if (to->packet) { spin_lock_irq(&tty->ctrl_lock); tty->ctrl_status |= TIOCPKT_FLUSHWRITE; wake_up_interruptible(&to->read_wait); spin_unlock_irq(&tty->ctrl_lock); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4867.61%450.00%
Alan Cox1419.72%112.50%
Peter Hurley811.27%225.00%
Wang YanQing11.41%112.50%
Total71100.00%8100.00%


static int pty_open(struct tty_struct *tty, struct file *filp) { if (!tty || !tty->link) return -ENODEV; if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) goto out; if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) goto out; if (tty->driver->subtype == PTY_TYPE_SLAVE && tty->link->count != 1) goto out; clear_bit(TTY_IO_ERROR, &tty->flags); clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); return 0; out: set_bit(TTY_IO_ERROR, &tty->flags); return -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9973.88%975.00%
Peter Hurley3526.12%325.00%
Total134100.00%12100.00%


static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty); int old_flow = ((old_termios->c_iflag & IXON) && (old_termios->c_cc[VSTOP] == '\023') && (old_termios->c_cc[VSTART] == '\021')); int new_flow = (I_IXON(tty) && STOP_CHAR(tty) == '\023' && START_CHAR(tty) == '\021'); if ((old_flow != new_flow) || extproc) { spin_lock_irq(&tty->ctrl_lock); if (old_flow != new_flow) { tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); if (new_flow) tty->ctrl_status |= TIOCPKT_DOSTOP; else tty->ctrl_status |= TIOCPKT_NOSTOP; } if (extproc) tty->ctrl_status |= TIOCPKT_IOCTL; spin_unlock_irq(&tty->ctrl_lock); wake_up_interruptible(&tty->link->read_wait); } } tty->termios.c_cflag &= ~(CSIZE | PARENB); tty->termios.c_cflag |= (CS8 | CREAD); }

Contributors

PersonTokensPropCommitsCommitProp
Peter Hurley17480.93%350.00%
Linus Torvalds (pre-git)3817.67%116.67%
Alan Cox31.40%233.33%
Total215100.00%6100.00%

/** * pty_do_resize - resize event * @tty: tty being resized * @ws: window size being set. * * Update the termios variables and send the necessary signals to * peform a terminal resize correctly */
static int pty_resize(struct tty_struct *tty, struct winsize *ws) { struct pid *pgrp, *rpgrp; struct tty_struct *pty = tty->link; /* For a PTY we need to lock the tty side */ mutex_lock(&tty->winsize_mutex); if (!memcmp(ws, &tty->winsize, sizeof(*ws))) goto done; /* Signal the foreground process group of both ptys */ pgrp = tty_get_pgrp(tty); rpgrp = tty_get_pgrp(pty); if (pgrp) kill_pgrp(pgrp, SIGWINCH, 1); if (rpgrp != pgrp && rpgrp) kill_pgrp(rpgrp, SIGWINCH, 1); put_pid(pgrp); put_pid(rpgrp); tty->winsize = *ws; pty->winsize = *ws; /* Never used so will go away soon */ done: mutex_unlock(&tty->winsize_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox13994.56%125.00%
Peter Hurley74.76%250.00%
Josh Triplett10.68%125.00%
Total147100.00%4100.00%

/** * pty_start - start() handler * pty_stop - stop() handler * @tty: tty being flow-controlled * * Propagates the TIOCPKT status to the master pty. * * NB: only the master pty can be in packet mode so only the slave * needs start()/stop() handlers */
static void pty_start(struct tty_struct *tty) { unsigned long flags; if (tty->link && tty->link->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status &= ~TIOCPKT_STOP; tty->ctrl_status |= TIOCPKT_START; spin_unlock_irqrestore(&tty->ctrl_lock, flags); wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); } }

Contributors

PersonTokensPropCommitsCommitProp
Peter Hurley74100.00%2100.00%
Total74100.00%2100.00%


static void pty_stop(struct tty_struct *tty) { unsigned long flags; if (tty->link && tty->link->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status &= ~TIOCPKT_START; tty->ctrl_status |= TIOCPKT_STOP; spin_unlock_irqrestore(&tty->ctrl_lock, flags); wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); } }

Contributors

PersonTokensPropCommitsCommitProp
Peter Hurley74100.00%2100.00%
Total74100.00%2100.00%

/** * pty_common_install - set up the pty pair * @driver: the pty driver * @tty: the tty being instantiated * @legacy: true if this is BSD style * * Perform the initial set up for the tty/pty pair. Called from the * tty layer when the port is first opened. * * Locking: the caller must hold the tty_mutex */
static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, bool legacy) { struct tty_struct *o_tty; struct tty_port *ports[2]; int idx = tty->index; int retval = -ENOMEM; /* Opening the slave first has always returned -EIO */ if (driver->subtype != PTY_TYPE_MASTER) return -EIO; ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); if (!ports[0] || !ports[1]) goto err; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ goto err; } o_tty = alloc_tty_struct(driver->other, idx); if (!o_tty) goto err_put_module; tty_set_lock_subclass(o_tty); lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE); if (legacy) { /* We always use new tty termios data so we can do this the easy way .. */ tty_init_termios(tty); tty_init_termios(o_tty); driver->other->ttys[idx] = o_tty; driver->ttys[idx] = tty; } else { memset(&tty->termios_locked, 0, sizeof(tty->termios_locked)); tty->termios = driver->init_termios; memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked)); o_tty->termios = driver->other->init_termios; } /* * Everything allocated ... set up the o_tty structure. */ tty_driver_kref_get(driver->other); /* Establish the links in both directions */ tty->link = o_tty; o_tty->link = tty; tty_port_init(ports[0]); tty_port_init(ports[1]); tty_buffer_set_limit(ports[0], 8192); tty_buffer_set_limit(ports[1], 8192); o_tty->port = ports[0]; tty->port = ports[1]; o_tty->port->itty = o_tty; tty_buffer_set_lock_subclass(o_tty->port); tty_driver_kref_get(driver); tty->count++; o_tty->count++; return 0; err_put_module: module_put(driver->other->owner); err: kfree(ports[0]); kfree(ports[1]); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Slaby17143.96%430.77%
Alan Cox14035.99%215.38%
Peter Hurley6015.42%538.46%
Rasmus Villemoes184.63%215.38%
Total389100.00%13100.00%


static void pty_cleanup(struct tty_struct *tty) { tty_port_put(tty->port); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Slaby18100.00%2100.00%
Total18100.00%2100.00%

/* Traditional BSD devices */ #ifdef CONFIG_LEGACY_PTYS
static int pty_install(struct tty_driver *driver, struct tty_struct *tty) { return pty_common_install(driver, tty, true); }

Contributors

PersonTokensPropCommitsCommitProp
Jiri Slaby26100.00%1100.00%
Total26100.00%1100.00%


static void pty_remove(struct tty_driver *driver, struct tty_struct *tty) { struct tty_struct *pair = tty->link; driver->ttys[tty->index] = NULL; if (pair) pair->driver->ttys[pair->index] = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox53100.00%1100.00%
Total53100.00%1100.00%


static int pty_bsd_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { switch (cmd) { case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ return pty_set_lock(tty, (int __user *) arg); case TIOCGPTLCK: /* Get PT Lock status */ return pty_get_lock(tty, (int __user *)arg); case TIOCPKT: /* Set PT packet mode */ return pty_set_pktmode(tty, (int __user *)arg); case TIOCGPKT: /* Get PT packet mode */ return pty_get_pktmode(tty, (int __user *)arg); case TIOCSIG: /* Send signal to other side of pty */ return pty_signal(tty, (int) arg); case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */ return -EINVAL; } return -ENOIOCTLCMD; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrill V. Gorcunov5142.50%233.33%
Christoph Hellwig3730.83%116.67%
Howard Chu1512.50%116.67%
Andrew Morton97.50%116.67%
Jiri Slaby86.67%116.67%
Total120100.00%6100.00%


static long pty_bsd_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { /* * PTY ioctls don't require any special translation between 32-bit and * 64-bit userspace, they are already compatible. */ return pty_bsd_ioctl(tty, cmd, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Aleksa Sarai30100.00%1100.00%
Total30100.00%1100.00%

static int legacy_count = CONFIG_LEGACY_PTY_COUNT; /* * not really modular, but the easiest way to keep compat with existing * bootargs behaviour is to continue using module_param here. */ module_param(legacy_count, int, 0); /* * The master side of a pty can do TIOCSPTLCK and thus * has pty_bsd_ioctl. */ static const struct tty_operations master_pty_ops_bsd = { .install = pty_install, .open = pty_open, .close = pty_close, .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .ioctl = pty_bsd_ioctl, .compat_ioctl = pty_bsd_compat_ioctl, .cleanup = pty_cleanup, .resize = pty_resize, .remove = pty_remove }; static const struct tty_operations slave_pty_ops_bsd = { .install = pty_install, .open = pty_open, .close = pty_close, .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .cleanup = pty_cleanup, .resize = pty_resize, .start = pty_start, .stop = pty_stop, .remove = pty_remove };
static void __init legacy_pty_init(void) { struct tty_driver *pty_driver, *pty_slave_driver; if (legacy_count <= 0) return; pty_driver = tty_alloc_driver(legacy_count, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(pty_driver)) panic("Couldn't allocate pty driver"); pty_slave_driver = tty_alloc_driver(legacy_count, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(pty_slave_driver)) panic("Couldn't allocate pty slave driver"); pty_driver->driver_name = "pty_master"; pty_driver->name = "pty"; pty_driver->major = PTY_MASTER_MAJOR; pty_driver->minor_start = 0; pty_driver->type = TTY_DRIVER_TYPE_PTY; pty_driver->subtype = PTY_TYPE_MASTER; pty_driver->init_termios = tty_std_termios; pty_driver->init_termios.c_iflag = 0; pty_driver->init_termios.c_oflag = 0; pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pty_driver->init_termios.c_lflag = 0; pty_driver->init_termios.c_ispeed = 38400; pty_driver->init_termios.c_ospeed = 38400; pty_driver->other = pty_slave_driver; tty_set_operations(pty_driver, &master_pty_ops_bsd); pty_slave_driver->driver_name = "pty_slave"; pty_slave_driver->name = "ttyp"; pty_slave_driver->major = PTY_SLAVE_MAJOR; pty_slave_driver->minor_start = 0; pty_slave_driver->type = TTY_DRIVER_TYPE_PTY; pty_slave_driver->subtype = PTY_TYPE_SLAVE; pty_slave_driver->init_termios = tty_std_termios; pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pty_slave_driver->init_termios.c_ispeed = 38400; pty_slave_driver->init_termios.c_ospeed = 38400; pty_slave_driver->other = pty_driver; tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd); if (tty_register_driver(pty_driver)) panic("Couldn't register pty driver"); if (tty_register_driver(pty_slave_driver)) panic("Couldn't register pty slave driver"); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15051.72%1052.63%
Al Viro6422.07%15.26%
Alan Cox3211.03%15.26%
Jiri Slaby144.83%15.26%
Linus Torvalds103.45%15.26%
Kay Sievers93.10%15.26%
Dan Carpenter62.07%15.26%
Christoph Hellwig31.03%15.26%
Andrew Morton20.69%210.53%
Total290100.00%19100.00%

#else
static inline void legacy_pty_init(void) { }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig8100.00%1100.00%
Total8100.00%1100.00%

#endif /* Unix98 devices */ #ifdef CONFIG_UNIX98_PTYS static struct cdev ptmx_cdev; /** * ptm_open_peer - open the peer of a pty * @master: the open struct file of the ptmx device node * @tty: the master of the pty being opened * @flags: the flags for open * * Provide a race free way for userspace to open the slave end of a pty * (where they have the master fd and cannot access or trust the mount * namespace /dev/pts was mounted inside). */
int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags) { int fd = -1; struct file *filp; int retval = -EINVAL; struct path path; if (tty->driver != ptm_driver) return -EIO; fd = get_unused_fd_flags(0); if (fd < 0) { retval = fd; goto err; } /* Compute the slave's path */ path.mnt = devpts_mntget(master, tty->driver_data); if (IS_ERR(path.mnt)) { retval = PTR_ERR(path.mnt); goto err_put; } path.dentry = tty->link->driver_data; filp = dentry_open(&path, flags, current_cred()); mntput(path.mnt); if (IS_ERR(filp)) { retval = PTR_ERR(filp); goto err_put; } fd_install(fd, filp); return fd; err_put: put_unused_fd(fd); err: return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Arnd Bergmann10155.80%150.00%
Eric W. Biedermann8044.20%150.00%
Total181100.00%2100.00%


static int pty_unix98_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { switch (cmd) { case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ return pty_set_lock(tty, (int __user *)arg); case TIOCGPTLCK: /* Get PT Lock status */ return pty_get_lock(tty, (int __user *)arg); case TIOCPKT: /* Set PT packet mode */ return pty_set_pktmode(tty, (int __user *)arg); case TIOCGPKT: /* Get PT packet mode */ return pty_get_pktmode(tty, (int __user *)arg); case TIOCGPTN: /* Get PT Number */ return put_user(tty->index, (unsigned int __user *)arg); case TIOCSIG: /* Send signal to other side of pty */ return pty_signal(tty, (int) arg); } return -ENOIOCTLCMD; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig6650.00%125.00%
Cyrill V. Gorcunov5138.64%250.00%
Howard Chu1511.36%125.00%
Total132100.00%4100.00%


static long pty_unix98_compat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { /* * PTY ioctls don't require any special translation between 32-bit and * 64-bit userspace, they are already compatible. */ return pty_unix98_ioctl(tty, cmd, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Aleksa Sarai30100.00%1100.00%
Total30100.00%1100.00%

/** * ptm_unix98_lookup - find a pty master * @driver: ptm driver * @idx: tty index * * Look up a pty master device. Called under the tty_mutex for now. * This provides our locking. */
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, struct file *file, int idx) { /* Master must be open via /dev/ptmx */ return ERR_PTR(-EIO); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox1965.52%125.00%
Konstantin Khlebnikov517.24%125.00%
Sukadev Bhattiprolu310.34%125.00%
Linus Torvalds26.90%125.00%
Total29100.00%4100.00%

/** * pts_unix98_lookup - find a pty slave * @driver: pts driver * @idx: tty index * * Look up a pty master device. Called under the tty_mutex for now. * This provides our locking for the tty pointer. */
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, struct file *file, int idx) { struct tty_struct *tty; mutex_lock(&devpts_mutex); tty = devpts_get_priv(file->f_path.dentry); mutex_unlock(&devpts_mutex); /* Master must be open before slave */ if (!tty) return ERR_PTR(-EIO); return tty; }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox5483.08%240.00%
Linus Torvalds710.77%120.00%
Sukadev Bhattiprolu34.62%120.00%
Jiri Slaby11.54%120.00%
Total65100.00%5100.00%


static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) { return pty_common_install(driver, tty, false); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox2492.31%266.67%
Jiri Slaby27.69%133.33%
Total26100.00%3100.00%

/* this is called once with whichever end is closed last */
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) { struct pts_fs_info *fsi; if (tty->driver->subtype == PTY_TYPE_MASTER) fsi = tty->driver_data; else fsi = tty->link->driver_data; if (fsi) { devpts_kill_index(fsi, tty->index); devpts_release(fsi); } }

Contributors

PersonTokensPropCommitsCommitProp
Herton Ronaldo Krzesinski2842.42%112.50%
Jiri Slaby2334.85%337.50%
Colin Ian King69.09%112.50%
Linus Torvalds69.09%112.50%
Alan Cox23.03%112.50%
Eric W. Biedermann11.52%112.50%
Total66100.00%8100.00%


static void pty_show_fdinfo(struct tty_struct *tty, struct seq_file *m) { seq_printf(m, "tty-index:\t%d\n", tty->index); }

Contributors

PersonTokensPropCommitsCommitProp
Masatake YAMATO27100.00%1100.00%
Total27100.00%1100.00%

static const struct tty_operations ptm_unix98_ops = { .lookup = ptm_unix98_lookup, .install = pty_unix98_install, .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .ioctl = pty_unix98_ioctl, .compat_ioctl = pty_unix98_compat_ioctl, .resize = pty_resize, .cleanup = pty_cleanup, .show_fdinfo = pty_show_fdinfo, }; static const struct tty_operations pty_unix98_ops = { .lookup = pts_unix98_lookup, .install = pty_unix98_install, .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .start = pty_start, .stop = pty_stop, .cleanup = pty_cleanup, }; /** * ptmx_open - open a unix 98 pty master * @inode: inode of device file * @filp: file pointer to tty * * Allocate a unix98 pty master device from the ptmx driver. * * Locking: tty_mutex protects the init_dev work. tty->count should * protect the rest. * allocated_ptys_lock handles the list of free pty numbers */
static int ptmx_open(struct inode *inode, struct file *filp) { struct pts_fs_info *fsi; struct tty_struct *tty; struct dentry *dentry; int retval; int index; nonseekable_open(inode, filp); /* We refuse fsnotify events on ptmx, since it's a shared resource */ filp->f_mode |= FMODE_NONOTIFY; retval = tty_alloc_file(filp); if (retval) return retval; fsi = devpts_acquire(filp); if (IS_ERR(fsi)) { retval = PTR_ERR(fsi); goto out_free_file; } /* find a device that is not in use. */ mutex_lock(&devpts_mutex); index = devpts_new_index(fsi); mutex_unlock(&devpts_mutex); retval = index; if (index < 0) goto out_put_fsi; mutex_lock(&tty_mutex); tty = tty_init_dev(ptm_driver, index); /* The tty returned here is locked so we can safely drop the mutex */ mutex_unlock(&tty_mutex); retval = PTR_ERR(tty); if (IS_ERR(tty)) goto out; /* * From here on out, the tty is "live", and the index and * fsi will be killed/put by the tty_release() */ set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty->driver_data = fsi; tty_add_file(tty, filp); dentry = devpts_pty_new(fsi, index, tty->link); if (IS_ERR(dentry)) { retval = PTR_ERR(dentry); goto err_release; } tty->link->driver_data = dentry; retval = ptm_driver->ops->open(tty, filp); if (retval) goto err_release; tty_debug_hangup(tty, "opening (count=%d)\n", tty->count); tty_unlock(tty); return 0; err_release: tty_unlock(tty); // This will also put-ref the fsi tty_release(inode, filp); return retval; out: devpts_kill_index(fsi, index); out_put_fsi: devpts_release(fsi); out_free_file: tty_free_file(filp); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox14646.95%625.00%
Linus Torvalds6420.58%312.50%
Jiri Slaby4113.18%416.67%
Peter Hurley227.07%312.50%
Eric W. Biedermann185.79%28.33%
Arnd Bergmann82.57%14.17%
Nicholas Piggin61.93%28.33%
Sukadev Bhattiprolu41.29%14.17%
Greg Kroah-Hartman10.32%14.17%
Herton Ronaldo Krzesinski10.32%14.17%
Total311100.00%24100.00%

static struct file_operations ptmx_fops __ro_after_init;
static void __init unix98_pty_init(void) { ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(ptm_driver)) panic("Couldn't allocate Unix98 ptm driver"); pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(pts_driver)) panic("Couldn't allocate Unix98 pts driver"); ptm_driver->driver_name = "pty_master"; ptm_driver->name = "ptm"; ptm_driver->major = UNIX98_PTY_MASTER_MAJOR; ptm_driver->minor_start = 0; ptm_driver->type = TTY_DRIVER_TYPE_PTY; ptm_driver->subtype = PTY_TYPE_MASTER; ptm_driver->init_termios = tty_std_termios; ptm_driver->init_termios.c_iflag = 0; ptm_driver->init_termios.c_oflag = 0; ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; ptm_driver->init_termios.c_lflag = 0; ptm_driver->init_termios.c_ispeed = 38400; ptm_driver->init_termios.c_ospeed = 38400; ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &ptm_unix98_ops); pts_driver->driver_name = "pty_slave"; pts_driver->name = "pts"; pts_driver->major = UNIX98_PTY_SLAVE_MAJOR; pts_driver->minor_start = 0; pts_driver->type = TTY_DRIVER_TYPE_PTY; pts_driver->subtype = PTY_TYPE_SLAVE; pts_driver->init_termios = tty_std_termios; pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pts_driver->init_termios.c_ispeed = 38400; pts_driver->init_termios.c_ospeed = 38400; pts_driver->other = ptm_driver; tty_set_operations(pts_driver, &pty_unix98_ops); if (tty_register_driver(ptm_driver)) panic("Couldn't register Unix98 ptm driver"); if (tty_register_driver(pts_driver)) panic("Couldn't register Unix98 pts driver"); /* Now create the /dev/ptmx special device */ tty_default_fops(&ptmx_fops); ptmx_fops.open = ptmx_open; cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver"); device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro12534.63%211.11%
Alan Cox11130.75%422.22%
Linus Torvalds (pre-git)8523.55%738.89%
Jiri Slaby226.09%15.56%
Christoph Hellwig92.49%15.56%
Dan Carpenter61.66%15.56%
Andrew Morton20.55%15.56%
Cong Ding10.28%15.56%
Total361100.00%18100.00%

#else
static inline void unix98_pty_init(void) { }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig8100.00%1100.00%
Total8100.00%1100.00%

#endif
static int __init pty_init(void) { legacy_pty_init(); unix98_pty_init(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig1477.78%133.33%
Linus Torvalds (pre-git)422.22%266.67%
Total18100.00%3100.00%

device_initcall(pty_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
Alan Cox100024.60%2114.19%
Linus Torvalds (pre-git)77719.11%3322.30%
Peter Hurley59214.56%2416.22%
Jiri Slaby3568.76%1711.49%
Cyrill V. Gorcunov2516.17%21.35%
Al Viro1944.77%42.70%
Linus Torvalds1694.16%74.73%
Christoph Hellwig1503.69%10.68%
Arnd Bergmann1102.71%32.03%
Eric W. Biedermann1022.51%21.35%
Howard Chu832.04%10.68%
Aleksa Sarai791.94%21.35%
Masatake YAMATO330.81%10.68%
Herton Ronaldo Krzesinski290.71%10.68%
Kay Sievers240.59%10.68%
Andrew Morton190.47%32.03%
Rasmus Villemoes190.47%21.35%
Greg Kroah-Hartman150.37%32.03%
Dan Carpenter120.30%10.68%
Sukadev Bhattiprolu110.27%10.68%
Nicholas Piggin60.15%21.35%
Zou Nan hai60.15%10.68%
Colin Ian King60.15%10.68%
Konstantin Khlebnikov50.12%10.68%
Brian Bloniarz30.07%10.68%
Paul Gortmaker20.05%10.68%
Cong Ding20.05%21.35%
Alexey Dobriyan20.05%10.68%
Adrian Bunk10.02%10.68%
Roel Kluin10.02%10.68%
Daniel Mack10.02%10.68%
Ingo Molnar10.02%10.68%
Josh Triplett10.02%10.68%
Wang YanQing10.02%10.68%
Kees Cook10.02%10.68%
Tejun Heo10.02%10.68%
Total4065100.00%148100.00%
Directory: drivers/tty
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.