2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
|
|
*
|
|
|
|
* Added support for a Unix98-style ptmx device.
|
|
|
|
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2008-10-13 09:43:38 +00:00
|
|
|
#include <linux/module.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/tty.h>
|
|
|
|
#include <linux/tty_flip.h>
|
|
|
|
#include <linux/fcntl.h>
|
2009-10-07 13:09:06 +00:00
|
|
|
#include <linux/sched.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/major.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/init.h>
|
2008-10-13 09:41:42 +00:00
|
|
|
#include <linux/device.h>
|
2008-10-13 09:43:38 +00:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/devpts_fs.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2012-05-03 21:22:09 +00:00
|
|
|
#include <linux/mutex.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-10-13 09:43:38 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
2009-01-08 02:09:15 +00:00
|
|
|
static struct tty_driver *ptm_driver;
|
2005-04-16 22:20:36 +00:00
|
|
|
static struct tty_driver *pts_driver;
|
2012-05-03 21:22:09 +00:00
|
|
|
static DEFINE_MUTEX(devpts_mutex);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
|
2008-10-13 09:43:38 +00:00
|
|
|
static void pty_close(struct tty_struct *tty, struct file *filp)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2008-10-13 09:43:38 +00:00
|
|
|
BUG_ON(!tty);
|
|
|
|
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
|
|
|
WARN_ON(tty->count > 1);
|
|
|
|
else {
|
2005-04-16 22:20:36 +00:00
|
|
|
if (tty->count > 2)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
wake_up_interruptible(&tty->read_wait);
|
|
|
|
wake_up_interruptible(&tty->write_wait);
|
|
|
|
tty->packet = 0;
|
2012-08-08 15:30:13 +00:00
|
|
|
/* Review - krefs on tty_link ?? */
|
2005-04-16 22:20:36 +00:00
|
|
|
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);
|
2012-02-24 21:56:36 +00:00
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
2012-05-03 21:22:09 +00:00
|
|
|
if (tty->driver == ptm_driver) {
|
2013-01-12 04:01:22 +00:00
|
|
|
mutex_lock(&devpts_mutex);
|
2012-10-18 20:26:29 +00:00
|
|
|
devpts_pty_kill(tty->link->driver_data);
|
2013-01-12 04:01:22 +00:00
|
|
|
mutex_unlock(&devpts_mutex);
|
2012-05-03 21:22:09 +00:00
|
|
|
}
|
2012-02-24 21:56:36 +00:00
|
|
|
#endif
|
2012-08-08 15:30:13 +00:00
|
|
|
tty_unlock(tty);
|
2010-06-18 12:58:07 +00:00
|
|
|
tty_vhangup(tty->link);
|
2012-08-08 15:30:13 +00:00
|
|
|
tty_lock(tty);
|
2005-04-16 22:20:36 +00: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
|
2008-10-13 09:43:38 +00:00
|
|
|
* unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
|
2005-04-16 22:20:36 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2008-10-13 09:43:38 +00:00
|
|
|
static void pty_unthrottle(struct tty_struct *tty)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2009-07-07 15:39:41 +00:00
|
|
|
tty_wakeup(tty->link);
|
2005-04-16 22:20:36 +00:00
|
|
|
set_bit(TTY_THROTTLED, &tty->flags);
|
|
|
|
}
|
|
|
|
|
2009-07-07 15:39:41 +00:00
|
|
|
/**
|
|
|
|
* pty_space - report space left for writing
|
|
|
|
* @to: tty we are writing into
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2009-07-07 15:39:41 +00:00
|
|
|
* The tty buffers allow 64K but we sneak a peak and clip at 8K this
|
|
|
|
* allows a lot of overspill room for echo and other fun messes to
|
|
|
|
* be handled properly
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int pty_space(struct tty_struct *to)
|
|
|
|
{
|
2012-10-18 20:26:47 +00:00
|
|
|
int n = 8192 - to->port->buf.memory_used;
|
2009-07-07 15:39:41 +00:00
|
|
|
if (n < 0)
|
|
|
|
return 0;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* pty_write - write to a pty
|
|
|
|
* @tty: the tty we write from
|
|
|
|
* @buf: kernel buffer of data
|
|
|
|
* @count: bytes to write
|
2009-06-16 16:01:13 +00:00
|
|
|
*
|
2009-07-07 15:39:41 +00:00
|
|
|
* 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.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-07-07 15:39:41 +00:00
|
|
|
|
2009-09-05 20:27:10 +00:00
|
|
|
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct tty_struct *to = tty->link;
|
|
|
|
|
2009-07-07 15:39:41 +00:00
|
|
|
if (tty->stopped)
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
2009-07-07 15:39:41 +00:00
|
|
|
|
|
|
|
if (c > 0) {
|
|
|
|
/* Stuff the data into the input queue of the other end */
|
2013-01-03 14:53:04 +00:00
|
|
|
c = tty_insert_flip_string(to->port, buf, c);
|
2009-07-07 15:39:41 +00:00
|
|
|
/* And shovel */
|
2009-09-18 14:05:58 +00:00
|
|
|
if (c) {
|
2013-01-03 14:53:06 +00:00
|
|
|
tty_flip_buffer_push(to->port);
|
2009-09-18 14:05:58 +00:00
|
|
|
tty_wakeup(tty);
|
|
|
|
}
|
2009-06-16 16:01:13 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2009-07-07 15:39:41 +00: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.
|
|
|
|
*/
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static int pty_write_room(struct tty_struct *tty)
|
|
|
|
{
|
2009-08-10 20:21:19 +00:00
|
|
|
if (tty->stopped)
|
|
|
|
return 0;
|
2009-07-07 15:39:41 +00:00
|
|
|
return pty_space(tty->link);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2009-07-07 15:39:41 +00:00
|
|
|
/**
|
|
|
|
* pty_chars_in_buffer - characters currently in our tx queue
|
|
|
|
* @tty: our tty
|
2008-10-13 09:43:38 +00:00
|
|
|
*
|
2009-07-07 15:39:41 +00:00
|
|
|
* Report how much we have in the transmit queue. As everything is
|
|
|
|
* instantly at the other end this is easy to implement.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-07-07 15:39:41 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static int pty_chars_in_buffer(struct tty_struct *tty)
|
|
|
|
{
|
2009-07-07 15:39:41 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the lock flag on a pty */
|
2008-10-13 09:43:38 +00:00
|
|
|
static int pty_set_lock(struct tty_struct *tty, int __user *arg)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int val;
|
2008-10-13 09:43:38 +00:00
|
|
|
if (get_user(val, arg))
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EFAULT;
|
|
|
|
if (val)
|
|
|
|
set_bit(TTY_PTY_LOCK, &tty->flags);
|
|
|
|
else
|
|
|
|
clear_bit(TTY_PTY_LOCK, &tty->flags);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-24 19:43:22 +00: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);
|
|
|
|
}
|
|
|
|
|
2012-10-24 19:43:20 +00:00
|
|
|
/* Set the packet mode on a pty */
|
|
|
|
static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
int pktmode;
|
|
|
|
|
|
|
|
if (get_user(pktmode, arg))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
|
|
|
if (pktmode) {
|
|
|
|
if (!tty->packet) {
|
|
|
|
tty->packet = 1;
|
|
|
|
tty->link->ctrl_status = 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
tty->packet = 0;
|
|
|
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-24 19:43:22 +00: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);
|
|
|
|
}
|
|
|
|
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-22 17:14:49 +00:00
|
|
|
/* Send a signal to the slave */
|
|
|
|
static int pty_signal(struct tty_struct *tty, int sig)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
struct pid *pgrp;
|
|
|
|
|
|
|
|
if (tty->link) {
|
|
|
|
spin_lock_irqsave(&tty->link->ctrl_lock, flags);
|
|
|
|
pgrp = get_pid(tty->link->pgrp);
|
|
|
|
spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
|
|
|
|
|
|
|
|
kill_pgrp(pgrp, sig, 1);
|
|
|
|
put_pid(pgrp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static void pty_flush_buffer(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
struct tty_struct *to = tty->link;
|
2008-04-30 07:53:29 +00:00
|
|
|
unsigned long flags;
|
2008-10-13 09:43:38 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (!to)
|
|
|
|
return;
|
2009-07-07 15:39:41 +00:00
|
|
|
/* tty_buffer_flush(to); FIXME */
|
2005-04-16 22:20:36 +00:00
|
|
|
if (to->packet) {
|
2008-04-30 07:53:29 +00:00
|
|
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
|
|
|
|
wake_up_interruptible(&to->read_wait);
|
2008-04-30 07:53:29 +00:00
|
|
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-13 09:43:38 +00:00
|
|
|
static int pty_open(struct tty_struct *tty, struct file *filp)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int retval = -ENODEV;
|
|
|
|
|
|
|
|
if (!tty || !tty->link)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
retval = -EIO;
|
|
|
|
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
|
|
|
|
goto out;
|
|
|
|
if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
|
|
|
|
goto out;
|
|
|
|
if (tty->link->count != 1)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
|
|
|
set_bit(TTY_THROTTLED, &tty->flags);
|
|
|
|
retval = 0;
|
|
|
|
out:
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2008-10-13 09:43:38 +00:00
|
|
|
static void pty_set_termios(struct tty_struct *tty,
|
|
|
|
struct ktermios *old_termios)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2012-07-14 14:31:47 +00:00
|
|
|
tty->termios.c_cflag &= ~(CSIZE | PARENB);
|
|
|
|
tty->termios.c_cflag |= (CS8 | CREAD);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2009-01-02 13:43:17 +00:00
|
|
|
/**
|
|
|
|
* pty_do_resize - resize event
|
|
|
|
* @tty: tty being resized
|
2009-01-11 19:46:49 +00:00
|
|
|
* @ws: window size being set.
|
2009-01-02 13:43:17 +00:00
|
|
|
*
|
tree-wide: Assorted spelling fixes
In particular, several occurances of funny versions of 'success',
'unknown', 'therefore', 'acknowledge', 'argument', 'achieve', 'address',
'beginning', 'desirable', 'separate' and 'necessary' are fixed.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Cc: Joe Perches <joe@perches.com>
Cc: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2010-02-03 00:01:28 +00:00
|
|
|
* Update the termios variables and send the necessary signals to
|
2009-01-02 13:43:17 +00:00
|
|
|
* peform a terminal resize correctly
|
|
|
|
*/
|
|
|
|
|
2012-11-19 05:27:40 +00:00
|
|
|
static int pty_resize(struct tty_struct *tty, struct winsize *ws)
|
2009-01-02 13:43:17 +00:00
|
|
|
{
|
|
|
|
struct pid *pgrp, *rpgrp;
|
|
|
|
unsigned long flags;
|
|
|
|
struct tty_struct *pty = tty->link;
|
|
|
|
|
|
|
|
/* For a PTY we need to lock the tty side */
|
|
|
|
mutex_lock(&tty->termios_mutex);
|
|
|
|
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Get the PID values and reference them so we can
|
|
|
|
avoid holding the tty ctrl lock while sending signals.
|
|
|
|
We need to lock these individually however. */
|
|
|
|
|
|
|
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
|
|
|
pgrp = get_pid(tty->pgrp);
|
|
|
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
|
|
|
|
|
|
|
spin_lock_irqsave(&pty->ctrl_lock, flags);
|
|
|
|
rpgrp = get_pid(pty->pgrp);
|
|
|
|
spin_unlock_irqrestore(&pty->ctrl_lock, flags);
|
|
|
|
|
|
|
|
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->termios_mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-27 17:02:54 +00:00
|
|
|
/**
|
|
|
|
* pty_common_install - set up the pty pair
|
|
|
|
* @driver: the pty driver
|
|
|
|
* @tty: the tty being instantiated
|
|
|
|
* @bool: 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
|
|
|
|
*/
|
2012-06-04 11:35:29 +00:00
|
|
|
static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
|
|
|
bool legacy)
|
2008-10-13 09:42:39 +00:00
|
|
|
{
|
|
|
|
struct tty_struct *o_tty;
|
2012-06-04 11:35:30 +00:00
|
|
|
struct tty_port *ports[2];
|
2008-10-13 09:42:39 +00:00
|
|
|
int idx = tty->index;
|
2012-06-04 11:35:29 +00:00
|
|
|
int retval = -ENOMEM;
|
2008-10-13 09:42:39 +00:00
|
|
|
|
|
|
|
o_tty = alloc_tty_struct();
|
2012-08-07 19:47:26 +00:00
|
|
|
if (!o_tty)
|
|
|
|
goto err;
|
2012-06-04 11:35:30 +00:00
|
|
|
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
|
|
|
|
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
|
2012-08-07 19:47:26 +00:00
|
|
|
if (!ports[0] || !ports[1])
|
2012-06-04 11:35:30 +00:00
|
|
|
goto err_free_tty;
|
2008-10-13 09:42:39 +00:00
|
|
|
if (!try_module_get(driver->other->owner)) {
|
|
|
|
/* This cannot in fact currently happen */
|
2011-03-23 09:48:33 +00:00
|
|
|
goto err_free_tty;
|
2008-10-13 09:42:39 +00:00
|
|
|
}
|
|
|
|
initialize_tty_struct(o_tty, driver->other, idx);
|
|
|
|
|
2012-06-04 11:35:29 +00:00
|
|
|
if (legacy) {
|
|
|
|
/* We always use new tty termios data so we can do this
|
|
|
|
the easy way .. */
|
|
|
|
retval = tty_init_termios(tty);
|
|
|
|
if (retval)
|
|
|
|
goto err_deinit_tty;
|
|
|
|
|
|
|
|
retval = tty_init_termios(o_tty);
|
|
|
|
if (retval)
|
|
|
|
goto err_free_termios;
|
|
|
|
|
|
|
|
driver->other->ttys[idx] = o_tty;
|
|
|
|
driver->ttys[idx] = tty;
|
|
|
|
} else {
|
2012-07-14 14:31:47 +00:00
|
|
|
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;
|
2012-06-04 11:35:29 +00:00
|
|
|
}
|
2008-10-13 09:43:38 +00:00
|
|
|
|
2008-10-13 09:42:39 +00:00
|
|
|
/*
|
|
|
|
* Everything allocated ... set up the o_tty structure.
|
|
|
|
*/
|
|
|
|
tty_driver_kref_get(driver->other);
|
|
|
|
if (driver->subtype == PTY_TYPE_MASTER)
|
|
|
|
o_tty->count++;
|
|
|
|
/* Establish the links in both directions */
|
|
|
|
tty->link = o_tty;
|
|
|
|
o_tty->link = tty;
|
2012-06-04 11:35:30 +00:00
|
|
|
tty_port_init(ports[0]);
|
|
|
|
tty_port_init(ports[1]);
|
|
|
|
o_tty->port = ports[0];
|
|
|
|
tty->port = ports[1];
|
2012-10-18 20:26:46 +00:00
|
|
|
o_tty->port->itty = o_tty;
|
2008-10-13 09:42:39 +00:00
|
|
|
|
|
|
|
tty_driver_kref_get(driver);
|
|
|
|
tty->count++;
|
|
|
|
return 0;
|
2011-03-23 09:48:33 +00:00
|
|
|
err_free_termios:
|
2012-06-04 11:35:29 +00:00
|
|
|
if (legacy)
|
|
|
|
tty_free_termios(tty);
|
2011-03-23 09:48:36 +00:00
|
|
|
err_deinit_tty:
|
|
|
|
deinitialize_tty_struct(o_tty);
|
2008-10-13 09:42:39 +00:00
|
|
|
module_put(o_tty->driver->owner);
|
2011-03-23 09:48:33 +00:00
|
|
|
err_free_tty:
|
2012-06-04 11:35:30 +00:00
|
|
|
kfree(ports[0]);
|
|
|
|
kfree(ports[1]);
|
2008-10-13 09:42:39 +00:00
|
|
|
free_tty_struct(o_tty);
|
2012-08-07 19:47:26 +00:00
|
|
|
err:
|
2011-03-23 09:48:33 +00:00
|
|
|
return retval;
|
2008-10-13 09:42:39 +00:00
|
|
|
}
|
|
|
|
|
2012-10-18 20:26:31 +00:00
|
|
|
/* this is called once with whichever end is closed last */
|
|
|
|
static void pty_unix98_shutdown(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
devpts_kill_index(tty->driver_data, tty->index);
|
|
|
|
}
|
|
|
|
|
2012-06-04 11:35:30 +00:00
|
|
|
static void pty_cleanup(struct tty_struct *tty)
|
|
|
|
{
|
2012-10-18 20:26:46 +00:00
|
|
|
tty->port->itty = NULL;
|
2012-11-15 08:49:49 +00:00
|
|
|
tty_port_put(tty->port);
|
2012-06-04 11:35:30 +00:00
|
|
|
}
|
|
|
|
|
2012-06-04 11:35:29 +00: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);
|
|
|
|
}
|
|
|
|
|
2012-07-27 17:02:54 +00: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;
|
|
|
|
}
|
|
|
|
|
2011-02-14 16:27:22 +00:00
|
|
|
static int pty_bsd_ioctl(struct tty_struct *tty,
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
|
|
|
|
return pty_set_lock(tty, (int __user *) arg);
|
2012-10-24 19:43:22 +00:00
|
|
|
case TIOCGPTLCK: /* Get PT Lock status */
|
|
|
|
return pty_get_lock(tty, (int __user *)arg);
|
2012-10-24 19:43:20 +00:00
|
|
|
case TIOCPKT: /* Set PT packet mode */
|
|
|
|
return pty_set_pktmode(tty, (int __user *)arg);
|
2012-10-24 19:43:22 +00:00
|
|
|
case TIOCGPKT: /* Get PT packet mode */
|
|
|
|
return pty_get_pktmode(tty, (int __user *)arg);
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-22 17:14:49 +00:00
|
|
|
case TIOCSIG: /* Send signal to other side of pty */
|
|
|
|
return pty_signal(tty, (int) arg);
|
2013-01-11 11:06:27 +00:00
|
|
|
case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */
|
|
|
|
return -EINVAL;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
2007-08-15 10:25:38 +00:00
|
|
|
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
|
|
|
|
module_param(legacy_count, int, 0);
|
|
|
|
|
2009-09-30 14:49:40 +00:00
|
|
|
/*
|
|
|
|
* 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,
|
2008-04-30 07:54:10 +00:00
|
|
|
.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,
|
|
|
|
.ioctl = pty_bsd_ioctl,
|
2012-06-04 11:35:30 +00:00
|
|
|
.cleanup = pty_cleanup,
|
2012-07-27 17:02:54 +00:00
|
|
|
.resize = pty_resize,
|
|
|
|
.remove = pty_remove
|
2008-04-30 07:54:10 +00:00
|
|
|
};
|
|
|
|
|
2009-09-30 14:49:40 +00:00
|
|
|
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,
|
2012-06-04 11:35:30 +00:00
|
|
|
.cleanup = pty_cleanup,
|
2012-07-27 17:02:54 +00:00
|
|
|
.resize = pty_resize,
|
|
|
|
.remove = pty_remove
|
2009-09-30 14:49:40 +00:00
|
|
|
};
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static void __init legacy_pty_init(void)
|
|
|
|
{
|
2009-09-30 14:49:40 +00:00
|
|
|
struct tty_driver *pty_driver, *pty_slave_driver;
|
|
|
|
|
2007-08-15 10:25:38 +00:00
|
|
|
if (legacy_count <= 0)
|
|
|
|
return;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2012-08-08 20:26:41 +00:00
|
|
|
pty_driver = tty_alloc_driver(legacy_count,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 13:16:56 +00:00
|
|
|
if (IS_ERR(pty_driver))
|
2005-04-16 22:20:36 +00:00
|
|
|
panic("Couldn't allocate pty driver");
|
|
|
|
|
2012-08-08 20:26:41 +00:00
|
|
|
pty_slave_driver = tty_alloc_driver(legacy_count,
|
|
|
|
TTY_DRIVER_RESET_TERMIOS |
|
|
|
|
TTY_DRIVER_REAL_RAW |
|
|
|
|
TTY_DRIVER_DYNAMIC_ALLOC);
|
2012-08-16 13:16:56 +00:00
|
|
|
if (IS_ERR(pty_slave_driver))
|
2005-04-16 22:20:36 +00:00
|
|
|
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;
|
2006-12-08 10:38:45 +00:00
|
|
|
pty_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pty_driver->init_termios.c_ospeed = 38400;
|
2005-04-16 22:20:36 +00:00
|
|
|
pty_driver->other = pty_slave_driver;
|
2009-09-30 14:49:40 +00:00
|
|
|
tty_set_operations(pty_driver, &master_pty_ops_bsd);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
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;
|
2006-12-08 10:38:45 +00:00
|
|
|
pty_slave_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pty_slave_driver->init_termios.c_ospeed = 38400;
|
2005-04-16 22:20:36 +00:00
|
|
|
pty_slave_driver->other = pty_driver;
|
2009-09-30 14:49:40 +00:00
|
|
|
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void legacy_pty_init(void) { }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Unix98 devices */
|
|
|
|
#ifdef CONFIG_UNIX98_PTYS
|
|
|
|
|
2008-10-13 09:41:42 +00:00
|
|
|
static struct cdev ptmx_cdev;
|
|
|
|
|
2011-02-14 16:27:22 +00:00
|
|
|
static int pty_unix98_ioctl(struct tty_struct *tty,
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
|
|
|
|
return pty_set_lock(tty, (int __user *)arg);
|
2012-10-24 19:43:22 +00:00
|
|
|
case TIOCGPTLCK: /* Get PT Lock status */
|
|
|
|
return pty_get_lock(tty, (int __user *)arg);
|
2012-10-24 19:43:20 +00:00
|
|
|
case TIOCPKT: /* Set PT packet mode */
|
|
|
|
return pty_set_pktmode(tty, (int __user *)arg);
|
2012-10-24 19:43:22 +00:00
|
|
|
case TIOCGPKT: /* Get PT packet mode */
|
|
|
|
return pty_get_pktmode(tty, (int __user *)arg);
|
2005-04-16 22:20:36 +00:00
|
|
|
case TIOCGPTN: /* Get PT Number */
|
|
|
|
return put_user(tty->index, (unsigned int __user *)arg);
|
tty: Add EXTPROC support for LINEMODE
This patch is against the 2.6.34 source.
Paraphrased from the 1989 BSD patch by David Borman @ cray.com:
These are the changes needed for the kernel to support
LINEMODE in the server.
There is a new bit in the termios local flag word, EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and mapping
of signals are all disabled. This allows the telnetd to turn
off these functions when in linemode, but still keep track of
what state the user wants the terminal to be in.
New ioctl:
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the EXTPROC bit
is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set. This allows the process on the server side of the pty
to know when the state of the terminal has changed; it can then
issue the appropriate ioctl to retrieve the new state.
Since the original BSD patches accompanied the source code for telnet
I've left that reference here, but obviously the feature is useful for
any remote terminal protocol, including ssh.
The corresponding feature has existed in the BSD tty driver since 1989.
For historical reference, a good copy of the relevant files can be found
here:
http://anonsvn.mit.edu/viewvc/krb5/trunk/src/appl/telnet/?pathrev=17741
Signed-off-by: Howard Chu <hyc@symas.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-06-22 17:14:49 +00:00
|
|
|
case TIOCSIG: /* Send signal to other side of pty */
|
|
|
|
return pty_signal(tty, (int) arg);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
2008-10-13 09:42:00 +00: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.
|
|
|
|
*/
|
|
|
|
|
2008-10-13 09:42:59 +00:00
|
|
|
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
|
|
|
|
struct inode *ptm_inode, int idx)
|
2008-10-13 09:42:00 +00:00
|
|
|
{
|
2012-01-05 09:04:21 +00:00
|
|
|
/* Master must be open via /dev/ptmx */
|
|
|
|
return ERR_PTR(-EIO);
|
2008-10-13 09:42:00 +00: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.
|
2012-05-03 21:22:09 +00:00
|
|
|
* This provides our locking for the tty pointer.
|
2008-10-13 09:42:00 +00:00
|
|
|
*/
|
|
|
|
|
2008-10-13 09:42:59 +00:00
|
|
|
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
|
|
|
|
struct inode *pts_inode, int idx)
|
2008-10-13 09:42:00 +00:00
|
|
|
{
|
2012-05-03 21:22:09 +00:00
|
|
|
struct tty_struct *tty;
|
|
|
|
|
|
|
|
mutex_lock(&devpts_mutex);
|
2012-10-18 20:26:27 +00:00
|
|
|
tty = devpts_get_priv(pts_inode);
|
2012-05-03 21:22:09 +00:00
|
|
|
mutex_unlock(&devpts_mutex);
|
2008-10-13 09:42:00 +00:00
|
|
|
/* Master must be open before slave */
|
|
|
|
if (!tty)
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
return tty;
|
|
|
|
}
|
|
|
|
|
2008-10-13 09:42:19 +00:00
|
|
|
/* We have no need to install and remove our tty objects as devpts does all
|
|
|
|
the work for us */
|
|
|
|
|
2008-10-13 09:42:39 +00:00
|
|
|
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
|
2008-10-13 09:42:19 +00:00
|
|
|
{
|
2012-06-04 11:35:29 +00:00
|
|
|
return pty_common_install(driver, tty, false);
|
2008-10-13 09:42:19 +00:00
|
|
|
}
|
|
|
|
|
2012-06-04 11:35:28 +00:00
|
|
|
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
2008-10-13 09:42:19 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-10-13 09:41:30 +00:00
|
|
|
static const struct tty_operations ptm_unix98_ops = {
|
2008-10-13 09:42:00 +00:00
|
|
|
.lookup = ptm_unix98_lookup,
|
2008-10-13 09:42:39 +00:00
|
|
|
.install = pty_unix98_install,
|
2012-06-04 11:35:28 +00:00
|
|
|
.remove = pty_unix98_remove,
|
2008-04-30 07:54:10 +00:00
|
|
|
.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,
|
2008-10-13 09:41:30 +00:00
|
|
|
.ioctl = pty_unix98_ioctl,
|
2012-07-17 16:06:57 +00:00
|
|
|
.resize = pty_resize,
|
2012-10-18 20:26:31 +00:00
|
|
|
.shutdown = pty_unix98_shutdown,
|
2012-07-17 16:06:57 +00:00
|
|
|
.cleanup = pty_cleanup
|
2008-04-30 07:54:10 +00:00
|
|
|
};
|
|
|
|
|
2008-10-13 09:42:00 +00:00
|
|
|
static const struct tty_operations pty_unix98_ops = {
|
|
|
|
.lookup = pts_unix98_lookup,
|
2008-10-13 09:42:39 +00:00
|
|
|
.install = pty_unix98_install,
|
2012-06-04 11:35:28 +00:00
|
|
|
.remove = pty_unix98_remove,
|
2008-10-13 09:42:00 +00:00
|
|
|
.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,
|
2012-10-18 20:26:31 +00:00
|
|
|
.shutdown = pty_unix98_shutdown,
|
2012-06-04 11:35:30 +00:00
|
|
|
.cleanup = pty_cleanup,
|
2008-10-13 09:42:00 +00:00
|
|
|
};
|
2008-10-13 09:41:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2013-01-12 04:01:22 +00:00
|
|
|
* protect the rest.
|
2008-10-13 09:41:42 +00:00
|
|
|
* allocated_ptys_lock handles the list of free pty numbers
|
|
|
|
*/
|
|
|
|
|
2010-06-01 20:53:02 +00:00
|
|
|
static int ptmx_open(struct inode *inode, struct file *filp)
|
2008-10-13 09:41:42 +00:00
|
|
|
{
|
|
|
|
struct tty_struct *tty;
|
2012-10-18 20:26:28 +00:00
|
|
|
struct inode *slave_inode;
|
2008-10-13 09:41:42 +00:00
|
|
|
int retval;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
nonseekable_open(inode, filp);
|
|
|
|
|
2011-10-12 09:32:43 +00:00
|
|
|
retval = tty_alloc_file(filp);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
2008-10-13 09:41:42 +00:00
|
|
|
/* find a device that is not in use. */
|
2012-08-08 15:30:13 +00:00
|
|
|
mutex_lock(&devpts_mutex);
|
2008-10-13 09:42:59 +00:00
|
|
|
index = devpts_new_index(inode);
|
2011-10-12 09:32:43 +00:00
|
|
|
if (index < 0) {
|
|
|
|
retval = index;
|
2012-09-19 14:34:47 +00:00
|
|
|
mutex_unlock(&devpts_mutex);
|
2011-10-12 09:32:43 +00:00
|
|
|
goto err_file;
|
|
|
|
}
|
2008-10-13 09:41:42 +00:00
|
|
|
|
2012-08-08 15:30:13 +00:00
|
|
|
mutex_unlock(&devpts_mutex);
|
|
|
|
|
2008-10-13 09:41:42 +00:00
|
|
|
mutex_lock(&tty_mutex);
|
2012-01-05 09:04:21 +00:00
|
|
|
tty = tty_init_dev(ptm_driver, index);
|
2008-10-13 09:41:42 +00:00
|
|
|
|
2008-10-13 09:42:29 +00:00
|
|
|
if (IS_ERR(tty)) {
|
|
|
|
retval = PTR_ERR(tty);
|
2008-10-13 09:41:42 +00:00
|
|
|
goto out;
|
2008-10-13 09:42:29 +00:00
|
|
|
}
|
2008-10-13 09:41:42 +00:00
|
|
|
|
2012-08-08 15:30:13 +00:00
|
|
|
/* The tty returned here is locked so we can safely
|
|
|
|
drop the mutex */
|
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
|
|
2008-10-13 09:41:42 +00:00
|
|
|
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
|
2010-08-17 18:37:35 +00:00
|
|
|
|
2011-10-12 09:32:43 +00:00
|
|
|
tty_add_file(tty, filp);
|
2008-10-13 09:41:42 +00:00
|
|
|
|
2012-10-18 20:26:29 +00:00
|
|
|
slave_inode = devpts_pty_new(inode,
|
|
|
|
MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
|
|
|
|
tty->link);
|
2012-10-18 20:26:28 +00:00
|
|
|
if (IS_ERR(slave_inode)) {
|
|
|
|
retval = PTR_ERR(slave_inode);
|
2011-10-12 09:32:44 +00:00
|
|
|
goto err_release;
|
2012-10-18 20:26:28 +00:00
|
|
|
}
|
2008-10-13 09:41:42 +00:00
|
|
|
|
|
|
|
retval = ptm_driver->ops->open(tty, filp);
|
2010-06-01 20:53:02 +00:00
|
|
|
if (retval)
|
2011-10-12 09:32:44 +00:00
|
|
|
goto err_release;
|
|
|
|
|
2012-08-08 15:30:13 +00:00
|
|
|
tty_unlock(tty);
|
2012-10-18 20:26:31 +00:00
|
|
|
tty->driver_data = inode;
|
2012-10-18 20:26:29 +00:00
|
|
|
tty->link->driver_data = slave_inode;
|
2011-10-12 09:32:44 +00:00
|
|
|
return 0;
|
|
|
|
err_release:
|
2012-08-08 15:30:13 +00:00
|
|
|
tty_unlock(tty);
|
2009-11-30 13:18:29 +00:00
|
|
|
tty_release(inode, filp);
|
2008-10-13 09:41:42 +00:00
|
|
|
return retval;
|
|
|
|
out:
|
2012-08-08 15:30:13 +00:00
|
|
|
mutex_unlock(&tty_mutex);
|
2012-01-30 20:14:32 +00:00
|
|
|
devpts_kill_index(inode, index);
|
2011-10-12 09:32:43 +00:00
|
|
|
err_file:
|
|
|
|
tty_free_file(filp);
|
2010-06-01 20:53:02 +00:00
|
|
|
return retval;
|
2008-10-13 09:41:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_operations ptmx_fops;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
static void __init unix98_pty_init(void)
|
|
|
|
{
|
2012-08-08 20:26:41 +00:00
|
|
|
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);
|
2012-08-16 13:16:56 +00:00
|
|
|
if (IS_ERR(ptm_driver))
|
2005-04-16 22:20:36 +00:00
|
|
|
panic("Couldn't allocate Unix98 ptm driver");
|
2012-08-08 20:26:41 +00:00
|
|
|
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);
|
2012-08-16 13:16:56 +00:00
|
|
|
if (IS_ERR(pts_driver))
|
2005-04-16 22:20:36 +00:00
|
|
|
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;
|
2006-12-08 10:38:45 +00:00
|
|
|
ptm_driver->init_termios.c_ispeed = 38400;
|
|
|
|
ptm_driver->init_termios.c_ospeed = 38400;
|
2005-04-16 22:20:36 +00:00
|
|
|
ptm_driver->other = pts_driver;
|
2008-10-13 09:41:30 +00:00
|
|
|
tty_set_operations(ptm_driver, &ptm_unix98_ops);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
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;
|
2006-12-08 10:38:45 +00:00
|
|
|
pts_driver->init_termios.c_ispeed = 38400;
|
|
|
|
pts_driver->init_termios.c_ospeed = 38400;
|
2005-04-16 22:20:36 +00:00
|
|
|
pts_driver->other = ptm_driver;
|
2008-10-13 09:42:00 +00:00
|
|
|
tty_set_operations(pts_driver, &pty_unix98_ops);
|
2008-10-13 09:43:38 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
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");
|
|
|
|
|
2008-10-13 09:41:42 +00:00
|
|
|
/* 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)
|
2013-01-12 04:01:21 +00:00
|
|
|
panic("Couldn't register /dev/ptmx driver");
|
2008-10-13 09:41:42 +00:00
|
|
|
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2008-10-13 09:41:42 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#else
|
|
|
|
static inline void unix98_pty_init(void) { }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int __init pty_init(void)
|
|
|
|
{
|
|
|
|
legacy_pty_init();
|
|
|
|
unix98_pty_init();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
module_init(pty_init);
|