/* * 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. Load more
/* * 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_COMPAT static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #else #define tty_compat_ioctl NULL #endif static 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,