Eric W. Biedermanpty: Repair TIOCGPTPEER311fc659 years agoHistory
3224 lines · 78.2 KB · C
RawDownload
/* *  Copyright (C) 1991, 1992  Linus Torvalds */ /* * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles * or rs-channels. It also implements echoing, cooked mode etc. * * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. * * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the * tty_struct and tty_queue structures.  Previously there was an array * of 256 tty_struct's which was statically allocated, and the * tty_queue structures were allocated at boot time.  Both are now * dynamically allocated only when the tty is open. * * Also restructured routines so that there is more of a separation * between the high-level tty routines (tty_io.c and tty_ioctl.c) and * the low-level tty routines (serial.c, pty.c, console.c).  This * makes for cleaner and more compact code.  -TYT, 9/17/92 * * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines * which can be dynamically activated and de-activated by the line * discipline handling modules (like SLIP). * * NOTE: pay no attention to the line discipline code (yet); its * interface is still subject to change in this version... * -- TYT, 1/31/92 * * Added functionality to the OPOST tty handling.  No delays, but all * other bits should be there. *	-- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. * * Rewrote canonical mode and added more termios flags. * 	-- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 * * Reorganized FASYNC support so mouse code can share it. *	-- ctm@ardi.com, 9Sep95 * * New TIOCLINUX variants added. *	-- mj@k332.feld.cvut.cz, 19-Nov-95 * * Restrict vt switching via ioctl() *      -- grif@cs.ucr.edu, 5-Dec-95 * * Move console and virtual terminal code to more appropriate files, * implement CONFIG_VT and generalize console device interface. *	-- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97 * * Rewrote tty_init_dev and tty_release_dev to eliminate races. *	-- Bill Hawes <whawes@star.net>, June 97 * * Added devfs support. *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998 * * Added support for a Unix98-style ptmx device. *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998 * * Reduced memory usage for older ARM systems *      -- Russell King <rmk@arm.linux.org.uk> * * Move do_SAK() into process context.  Less stack use in devfs functions. * alloc_tty_struct() always uses kmalloc() *			 -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01 */ #include <linux/types.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/fcntl.h>#include <linux/sched/signal.h>#include <linux/sched/task.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/devpts_fs.h>#include <linux/file.h>#include <linux/fdtable.h>#include <linux/console.h>#include <linux/timer.h>#include <linux/ctype.h>#include <linux/kd.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/module.h>#include <linux/device.h>#include <linux/wait.h>#include <linux/bitops.h>#include <linux/delay.h>#include <linux/seq_file.h>#include <linux/serial.h>#include <linux/ratelimit.h> #include <linux/uaccess.h> #include <linux/kbd_kern.h>#include <linux/vt_kern.h>#include <linux/selection.h> #include <linux/kmod.h>#include <linux/nsproxy.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 #define TTY_PARANOIA_CHECK 1#define CHECK_TTY_COUNT 1 struct ktermios tty_std_termios = {	/* for the benefit of tty drivers  */	.c_iflag = ICRNL | IXON,	.c_oflag = OPOST | ONLCR,	.c_cflag = B38400 | CS8 | CREAD | HUPCL,	.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |		   ECHOCTL | ECHOKE | IEXTEN,	.c_cc = INIT_C_CC,	.c_ispeed = 38400,	.c_ospeed = 38400,	/* .c_line = N_TTY, */}; EXPORT_SYMBOL(tty_std_termios); /* This list gets poked at by procfs and various bits of boot up code. This   could do with some rationalisation such as pulling the tty proc function   into this file */ LIST_HEAD(tty_drivers);			/* linked list of tty drivers */ /* Mutex to protect creating and releasing a tty */DEFINE_MUTEX(tty_mutex); static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);ssize_t redirected_tty_write(struct file *, const char __user *,							size_t, loff_t *);static unsigned int tty_poll(struct file *, poll_table *);static int tty_open(struct inode *, struct file *);long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);#ifdef CONFIG_COMPATstatic long tty_compat_ioctl(struct file *file, unsigned int cmd,				unsigned long arg);#else#define tty_compat_ioctl NULL#endifstatic int __tty_fasync(int fd, struct file *filp, int on);static int tty_fasync(int fd, struct file *filp, int on);static void release_tty(struct tty_struct *tty, int idx); /** *	free_tty_struct		-	free a disused tty *	@tty: tty struct to free * *	Free the write buffers, tty queue and tty memory itself. * *	Locking: none. Must be called after tty is definitely unused */ static void free_tty_struct(struct tty_struct *tty){	tty_ldisc_deinit(tty);	put_device(tty->dev);	kfree(tty->write_buf);	tty->magic = 0xDEADDEAD;	kfree(tty);} static inline struct tty_struct *file_tty(struct file *file){	return ((struct tty_file_private *)file->private_data)->tty;} int tty_alloc_file(struct file *file){	struct tty_file_private *priv; 	priv = kmalloc(sizeof(*priv), GFP_KERNEL);	if (!priv)		return -ENOMEM; 	file->private_data = priv; 	return 0;} /* Associate a new file with the tty structure */void tty_add_file(struct tty_struct *tty, struct file *file){	struct tty_file_private *priv = file->private_data; 	priv->tty = tty;	priv->file = file; 	spin_lock(&tty->files_lock);	list_add(&priv->list, &tty->tty_files);	spin_unlock(&tty->files_lock);} /** * tty_free_file - free file->private_data * * This shall be used only for fail path handling when tty_add_file was not * called yet. */void tty_free_file(struct file *file){	struct tty_file_private *priv = file->private_data; 	file->private_data = NULL;	kfree(priv);} /* Delete file from its tty */static void tty_del_file(struct file *file){	struct tty_file_private *priv = file->private_data;	struct tty_struct *tty = priv->tty; 	spin_lock(&tty->files_lock);	list_del(&priv->list);	spin_unlock(&tty->files_lock);	tty_free_file(file);} /** *	tty_name	-	return tty naming *	@tty: tty structure * *	Convert a tty structure into a name. The name reflects the kernel *	naming policy and if udev is in use may not reflect user space * *	Locking: none */ const char *tty_name(const struct tty_struct *tty){	if (!tty) /* Hmm.  NULL pointer.  That's fun. */		return "NULL tty";	return tty->name;} EXPORT_SYMBOL(tty_name); const char *tty_driver_name(const struct tty_struct *tty){	if (!tty || !tty->driver)		return "";	return tty->driver->name;} static int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,			      const char *routine){#ifdef TTY_PARANOIA_CHECK	if (!tty) {		pr_warn("(%d:%d): %s: NULL tty\n",			imajor(inode), iminor(inode), routine);		return 1;	}	if (tty->magic != TTY_MAGIC) {		pr_warn("(%d:%d): %s: bad magic number\n",			imajor(inode), iminor(inode), routine);		return 1;	}#endif	return 0;} /* Caller must hold tty_lock */static int check_tty_count(struct tty_struct *tty, const char *routine){#ifdef CHECK_TTY_COUNT	struct list_head *p;	int count = 0; 	spin_lock(&tty->files_lock);	list_for_each(p, &tty->tty_files) {		count++;	}	spin_unlock(&tty->files_lock);	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&	    tty->driver->subtype == PTY_TYPE_SLAVE &&	    tty->link && tty->link->count)		count++;	if (tty->count != count) {		tty_warn(tty, "%s: tty->count(%d) != #fd's(%d)\n",			 routine, tty->count, count);		return count;	}#endif	return 0;} /** *	get_tty_driver		-	find device of a tty *	@dev_t: device identifier *	@index: returns the index of the tty * *	This routine returns a tty driver structure, given a device number *	and also passes back the index number. * *	Locking: caller must hold tty_mutex */ static struct tty_driver *get_tty_driver(dev_t device, int *index){	struct tty_driver *p; 	list_for_each_entry(p, &tty_drivers, tty_drivers) {		dev_t base = MKDEV(p->major, p->minor_start);		if (device < base || device >= base + p->num)			continue;		*index = device - base;		return tty_driver_kref_get(p);	}	return NULL;} /** *	tty_dev_name_to_number	-	return dev_t for device name *	@name: user space name of device under /dev *	@number: pointer to dev_t that this function will populate * *	This function converts device names like ttyS0 or ttyUSB1 into dev_t *	like (4, 64) or (188, 1). If no corresponding driver is registered then *	the function returns -ENODEV. * *	Locking: this acquires tty_mutex to protect the tty_drivers list from *		being modified while we are traversing it, and makes sure to *		release it before exiting. */int tty_dev_name_to_number(const char *name, dev_t *number){	struct tty_driver *p;	int ret;	int index, prefix_length = 0;	const char *str; 	for (str = name; *str && !isdigit(*str); str++)		; 	if (!*str)		return -EINVAL; 	ret = kstrtoint(str, 10, &index);	if (ret)		return ret; 	prefix_length = str - name;	mutex_lock(&tty_mutex); 	list_for_each_entry(p, &tty_drivers, tty_drivers)		if (prefix_length == strlen(p->name) && strncmp(name,					p->name, prefix_length) == 0) {			if (index < p->num) {				*number = MKDEV(p->major, p->minor_start + index);				goto out;			}		} 	/* if here then driver wasn't found */	ret = -ENODEV;out:	mutex_unlock(&tty_mutex);	return ret;}EXPORT_SYMBOL_GPL(tty_dev_name_to_number); #ifdef CONFIG_CONSOLE_POLL /** *	tty_find_polling_driver	-	find device of a polled tty *	@name: name string to match *	@line: pointer to resulting tty line nr * *	This routine returns a tty driver structure, given a name *	and the condition that the tty driver is capable of polled *	operation. */struct tty_driver *tty_find_polling_driver(char *name, int *line){	struct tty_driver *p, *res = NULL;	int tty_line = 0;	int len;	char *str, *stp; 	for (str = name; *str; str++)		if ((*str >= '0' && *str <= '9') || *str == ',')			break;	if (!*str)		return NULL; 	len = str - name;	tty_line = simple_strtoul(str, &str, 10); 	mutex_lock(&tty_mutex);	/* Search through the tty devices to look for a match */	list_for_each_entry(p, &tty_drivers, tty_drivers) {		if (strncmp(name, p->name, len) != 0)			continue;		stp = str;		if (*stp == ',')			stp++;		if (*stp == '\0')			stp = NULL; 		if (tty_line >= 0 && tty_line < p->num && p->ops &&		    p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {			res = tty_driver_kref_get(p);			*line = tty_line;			break;		}	}	mutex_unlock(&tty_mutex); 	return res;}EXPORT_SYMBOL_GPL(tty_find_polling_driver);#endif static ssize_t hung_up_tty_read(struct file *file, char __user *buf,				size_t count, loff_t *ppos){	return 0;} static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,				 size_t count, loff_t *ppos){	return -EIO;} /* No kernel lock held - none needed ;) */static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait){	return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;} static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,		unsigned long arg){	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;} static long hung_up_tty_compat_ioctl(struct file *file,				     unsigned int cmd, unsigned long arg){	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;} static int hung_up_tty_fasync(int fd, struct file *file, int on){	return -ENOTTY;} static const struct file_operations tty_fops = {	.llseek		= no_llseek,	.read		= tty_read,	.write		= tty_write,	.poll		= tty_poll,	.unlocked_ioctl	= tty_ioctl,	.compat_ioctl	= tty_compat_ioctl,	.open		= tty_open,	.release	= tty_release,	.fasync		= tty_fasync,}; static const struct file_operations console_fops = {	.llseek		= no_llseek,	.read		= tty_read,	.write		= redirected_tty_write,	.poll		= tty_poll,	.unlocked_ioctl	= tty_ioctl,	.compat_ioctl	= tty_compat_ioctl,	.open		= tty_open,	.release	= tty_release,	.fasync		= tty_fasync,}; static const struct file_operations hung_up_tty_fops = {	.llseek		= no_llseek,	.read		= hung_up_tty_read,	.write		= hung_up_tty_write,	.poll		= hung_up_tty_poll,	.unlocked_ioctl	= hung_up_tty_ioctl,	.compat_ioctl	= hung_up_tty_compat_ioctl,	.release	= tty_release,	.fasync		= hung_up_tty_fasync,}; static DEFINE_SPINLOCK(redirect_lock);

Lines 1–500 of 3224.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t