3593 lines · 88.8 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.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 #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}; 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. This is shared with   vt.c for deeply disgusting hack reasons */DEFINE_MUTEX(tty_mutex);EXPORT_SYMBOL(tty_mutex); /* Spinlock to protect the tty->tty_files list */DEFINE_SPINLOCK(tty_files_lock); 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);static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); /** *	alloc_tty_struct	-	allocate a tty object * *	Return a new empty tty structure. The data fields have not *	been initialized in any way but has been zeroed * *	Locking: none */ struct tty_struct *alloc_tty_struct(void){	return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);} /** *	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 */ void free_tty_struct(struct tty_struct *tty){	if (!tty)		return;	if (tty->dev)		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; 	spin_lock(&tty_files_lock);	list_del(&priv->list);	spin_unlock(&tty_files_lock);	tty_free_file(file);}  #define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) /** *	tty_name	-	return tty naming *	@tty: tty structure *	@buf: buffer for output * *	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 */ char *tty_name(struct tty_struct *tty, char *buf){	if (!tty) /* Hmm.  NULL pointer.  That's fun. */		strcpy(buf, "NULL tty");	else		strcpy(buf, tty->name);	return buf;} EXPORT_SYMBOL(tty_name); int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,			      const char *routine){#ifdef TTY_PARANOIA_CHECK	if (!tty) {		printk(KERN_WARNING			"null TTY for (%d:%d) in %s\n",			imajor(inode), iminor(inode), routine);		return 1;	}	if (tty->magic != TTY_MAGIC) {		printk(KERN_WARNING			"bad magic number for tty struct (%d:%d) in %s\n",			imajor(inode), iminor(inode), routine);		return 1;	}#endif	return 0;} 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) {		printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "				    "!= #fd's(%d) in %s\n",		       tty->name, tty->count, count, routine);		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;} #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 /** *	tty_check_change	-	check for POSIX terminal changes *	@tty: tty to check * *	If we try to write to, or set the state of, a terminal and we're *	not in the foreground, send a SIGTTOU.  If the signal is blocked or *	ignored, go ahead and perform the operation.  (POSIX 7.2) * *	Locking: ctrl_lock */ int tty_check_change(struct tty_struct *tty){	unsigned long flags;	int ret = 0; 	if (current->signal->tty != tty)		return 0; 	spin_lock_irqsave(&tty->ctrl_lock, flags); 	if (!tty->pgrp) {		printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");		goto out_unlock;	}	if (task_pgrp(current) == tty->pgrp)		goto out_unlock;	spin_unlock_irqrestore(&tty->ctrl_lock, flags);	if (is_ignored(SIGTTOU))		goto out;	if (is_current_pgrp_orphaned()) {		ret = -EIO;		goto out;	}	kill_pgrp(task_pgrp(current), SIGTTOU, 1);	set_thread_flag(TIF_SIGPENDING);	ret = -ERESTARTSYS;out:	return ret;out_unlock:	spin_unlock_irqrestore(&tty->ctrl_lock, flags);	return ret;} EXPORT_SYMBOL(tty_check_change); 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 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,

Lines 1–500 of 3593.