Home » What are the responsibilities of each Pseudo-Terminal (PTY) component (software, master side, slave side)?

What are the responsibilities of each Pseudo-Terminal (PTY) component (software, master side, slave side)?


Terminal emulators

The master side replaces the line (the pair of TX/RX wires) that goes to the terminal.

The terminal displays the characters that it receives on one of the wires (some of those are control characters and make it do things like move the cursor, change colour…) and sends on another wire the characters corresponding to the keys you type.

Terminal emulators like xterm are not different except that instead of sending and receiving characters on wires, they read and write characters on their file descriptor to the master side. Once they’ve spawned the slave terminal, and started your shell on that, they no longer touch that. In addition to emulating the pair of wire, xterm can also change some of the line discipline properties via that file descriptor to the master side. For instance, they can update the size attributes so a SIGWINCH be sent to the applications that interact with the slave pty to notify them of a changed size.

Other than that, there is little intelligence in the terminal/terminal emulator.

What you write to a terminal device (like the pty slave) is what you mean to be displayed there, what you read from it is what you have typed there, so it does not make sense for the terminal emulator to read or write to that. They are the ones at the other end.

The tty line discipline

A lot of the intelligence is in the tty line discipline. The line discipline is a software module (residing in the driver, in the kernel) pushed on top of a serial/pty device that sits between that device and the line/wire (the master side for a pty).

A serial line can have a terminal at the other end, but also a mouse or another computer for networking. You can attach a SLIP line discipline for instance to get a network interface on top of a serial device (or pty device), or you can have a tty line discipline. The tty line discipline is the default line discipline at least on Linux for serial and pty devices. On Linux, you can change the line discipline with ldattach.

You can see the effect of disabling the tty line discipline by issuing stty raw -echo (note that the bash prompt or other interactive applications like vi set the terminal in the exact mode they need, so you want to use a dumb application like cat to experience with that).
Then, everything that is written to the slave terminal device makes it immediately to the master side for xterm to read, and every character written by xterm to the master side is immediately available for reading from the slave device.

The line discipline is where the terminal device internal line editor is implemented. For instance with stty icanon echo (as is the default), when you type a, xterm writes a to the master, then the line discipline echoes it back (makes a a available for reading by xterm for display), but does not make anything available for reading on the slave side. Then if you type backspace, xterm sends a ^? or ^H character, the line discipline (as that ^? or ^H corresponds to the erase line discipline setting) sends back on the master a ^H, space and ^H for xterm to erase the a you’ve just typed on its screen and still doesn’t send anything to the application reading from the slave side, it just updates its internal line editor buffer to remove that a you’ve typed before.

Then when you press Enter, xterm sends ^M (CR), which the line discipline converts on input to a ^J (LF), and sends what you’ve entered so far for reading on the slave side (an application reading on /dev/pts/x will receive what you’ve typed including the LF, but not the a since you’ve deleted it), while on the master side, it sends a CR and LF to move the cursor to the next line and the start of the screen.

The line discipline is also responsible for sending the SIGINT signal to the foreground process group of the terminal when it receives a ^C character on the master side etc.

Many interactive terminal applications disable most of the features of that line discipline to implement it themselves. But in any case, beware that the terminal (xterm) has little involvement in that (except displaying what it’s told to display).

And there can be only one session per process and per terminal device. A session can have a controlling terminal attached to it but does not have to (all sessions start without a terminal until they open one). xterm, in the process that it forks to execute your shell will typically create a new session (and therefore detach from the terminal where you launched xterm from if any), open the new /dev/pts/x it has spawned, by that attaching that terminal device to the new session. It will then execute your shell in that process, so your shell will become the session leader. Your shell or any interactive shell in that session will typically juggle with process groups and tcsetpgrp(), to set the foreground and background jobs for that terminal.

As to what informations are stored by a terminal device with a tty discipline (serial or pty), that’s typically what the stty command displays and modifies. All the discipline configuration: terminal screen size, local, input output flags, settings for special characters (like ^C, ^Z…), input and output speed (not relevant for ptys). That corresponds to the tcgetattr()/tcsetattr() functions which on Linux map to the TCGETS/TCSETS ioctls, and TIOCGWINSZ/TIOCSWINSZ for the screen size. You may argue that the current foreground process group is another information stored in the terminal device (tcsetpgrp()/tcgetpgrp(), TIOC{G,S}PGRP ioctls), or the current input or output buffer.

Note that that screen size information stored in the terminal device may not reflect the reality. The terminal emulator will typically set it (via the same ioctl on the master size) when its window is resized, but it can get out of sync if an application calls the ioctl on the slave side or when the resize is not transmitted (in case of an ssh connection which implies another pty spawned by sshd if ssh ignores the SIGWINCH for instance). Some terminals can also be queried their size via escape sequences, so an application can query it that way, and update the line discipline with that information.

For more details, you can have a look at the termios and tty_ioctl man pages on Debian for instance.

To play with other line disciplines:

  1. Emulate a mouse with a pseudo-terminal:

    socat pty,link=mouse fifo:fifo
    sudo inputattach -msc mouse # sets the MOUSE line discipline and specifies protocol
    xinput list # see the new mouse there
    exec 3<> fifo
    printf '20712' >&3 # moves the cursor 10 pixels to the right

    Above, the master side of the pty is terminated by socat onto a named pipe (fifo). We connect that fifo to a process (the shell) that writes 0x87 0x0a 0x00 which in the mouse systems protocol means no button pressed, delta(x,y) = (10,0). Here, we (the shell) are not emulating a terminal, but a mouse, the 3 bytes we send are not to be read (potentially transformed) by an application from the terminal device (mouse above which is a symlink made by socat to some /dev/pts/x device), but are to be interpreted as a mouse input event.

  2. Create a SLIP interface:

    # on hostA
    socat tcp-listen:12345,reuseaddr pty,link=interface
    # after connection from hostB:
    sudo ldattach SLIP interface
    ifconfig -a # see the new interface there
    sudo ifconfig sl0
    # on hostB
    socat -v -x pty,link=interface tcp:hostA:12345
    sudo ldattach SLIP interface
    sudo ifconfig sl0
    ping # see the packets on socat output

    Above, the serial wire is emulated by socat as a TCP socket in-between hostA and hostB. The SLIP line discipline interprets those bytes exchanged over that virtual line as SLIP encapsulated IP packets for delivery on the sl0 interface.

Edit: Since this answer, I wrote a dedicated article on my blog, for people who would be interested on more details.

After a lot of reading, this is what I understood.

  • Has ptmx any purpose besides allocating the slave part? Does it provide some kind of “intelligence”, or the emulated terminal (xterm for instance) has all the intelligence of behaving like a terminal?

    /dev/ptmx doesn’t allocate the slave part: it allocates the “pseudo terminal master part”. /dev/ptmx is not the master pseudo terminal: it is a pseudo terminal master multiplexer. It has been created with the Unix98 PTY standard to avoid race conditions when allocating master pseudo terminal (source).

    The master part (ptm) of the pseudo terminal is not represented on the file system. It is represented by a file descriptor.

    The slave part (pts) is represented by a file in /dev/pts/N where N is a number.

    The pts is obtained from the ptm through the successive call of grandpt,unlockpt,ptsname.(Source)

    The ptm replace the AUR driver dedicated to communicate with the device, and the line edition. So it doesn’t emulate in any way a terminal but provide the feature of line edition, and provide a way to visualize and communicate with pts. (Source)

    Here is a graph of what was a TTY connected to a hardware device
    TTY communication with AUR

    And here is a graph of an tty connected to a ptm
    TTY communication with PTM

    The ptm file handles different Ioctl arguments (ISPTM, UNLKPT, TIOCREMOTE, TIOCSIGNAL) than the pts.

  • Why does xterm has to interact with the master part, as it only forwards the stdout and stdin of the slave part? Why can’t it directly write and read from the pts file?

    Processes interacts with devices through actions done to a virtual file (read, write, ioctl..). The file itself doesn’t exists and the driver use the file to trigger actions when read or write methods are called. (See Annexe for information about drivers)

    A TTY defines a precise way to interact with it. Processes write and read from the device and expect the same behavior regardless of what kind of TTY is implemented.

    • read function is used by processes to read entries from the terminal
    • write function is used by processes to send output to the terminal

    The pts behave like a TTY driver. Its read and write method are used to implements the TTY Driver behaviour.
    As there is no real device to send the data, a stream pair is created and the ptm implements a read function to read the data that are sent by pts to the stream, and a write function to send data to the stream that will be available when the pts will read it.

    Remember, the file representing a device is not a classic file, and if xterm wants to see what have been write to the file, it cannot just simply called open and read it, as these functions have a completely different behavior here.

  • Has a session ID always attached to one pts file and vice versa? Could I type a ps command and found 2 sessionId for the same /dev/pts/X?

    I don’t think so, the session Id is defined by the first process that attach the pts (bash generally), and I don’t see a way to create another session and attach it to the same pts. Maybe a tool like socat could do this?

  • What other information does the pts store? Does Xterm update all fields by himself, or does the ptm add some “intelligence” on it?

    The pts store 2 categories of information regarding the terminal it is communicating with: the Terminfo and the Termcap.
    Usually, many terminal emulator are based on library that manage termcap informations for them (that will provide all capabilities values to emulate a VTX100 for instance). An exemple of such a library is libvte. Edit (seeStephane Chazelas comment): The terminal capabilities are not stored by the pts.


  • A complete book about character drivers, with last chapter dedicated to TTY:
    Linux Device Driver 3rd edition
  • A detail explanation of implementation of character device: The linux kernel, Character device
  • A quick implementation of Character device: Brief tutorial from freesoftware magazine
  • A great article explaining terminals: the TTY demystified
  • Man page of ptm and pts from Oracle
  • Man page for ptm from HP

Here is a scheme I made some time ago about how sshd works. It doesn’t concern the operation of line discipline and stuff, but it adds a real-life illustration of who interacts with what:

enter image description here

Related Solutions

Joining bash arguments into single string with spaces

[*] I believe that this does what you want. It will put all the arguments in one string, separated by spaces, with single quotes around all: str="'$*'" $* produces all the scripts arguments separated by the first character of $IFS which, by default, is a space....

AddTransient, AddScoped and AddSingleton Services Differences

TL;DR Transient objects are always different; a new instance is provided to every controller and every service. Scoped objects are the same within a request, but different across different requests. Singleton objects are the same for every object and every...

How to download package not install it with apt-get command?

Use --download-only: sudo apt-get install --download-only pppoe This will download pppoe and any dependencies you need, and place them in /var/cache/apt/archives. That way a subsequent apt-get install pppoe will be able to complete without any extra downloads....

What defines the maximum size for a command single argument?

Answers Definitely not a bug. The parameter which defines the maximum size for one argument is MAX_ARG_STRLEN. There is no documentation for this parameter other than the comments in binfmts.h: /* * These are the maximum length and maximum number of strings...

Bulk rename, change prefix

I'd say the simplest it to just use the rename command which is common on many Linux distributions. There are two common versions of this command so check its man page to find which one you have: ## rename from Perl (common in Debian systems -- Ubuntu, Mint,...

Output from ls has newlines but displays on a single line. Why?

When you pipe the output, ls acts differently. This fact is hidden away in the info documentation: If standard output is a terminal, the output is in columns (sorted vertically) and control characters are output as question marks; otherwise, the output is...

mv: Move file only if destination does not exist

mv -vn file1 file2. This command will do what you want. You can skip -v if you want. -v makes it verbose - mv will tell you that it moved file if it moves it(useful, since there is possibility that file will not be moved) -n moves only if file2 does not exist....

Is it possible to store and query JSON in SQLite?

SQLite 3.9 introduced a new extension (JSON1) that allows you to easily work with JSON data . Also, it introduced support for indexes on expressions, which (in my understanding) should allow you to define indexes on your JSON data as well. PostgreSQL has some...

Combining tail && journalctl

You could use: journalctl -u service-name -f -f, --follow Show only the most recent journal entries, and continuously print new entries as they are appended to the journal. Here I've added "service-name" to distinguish this answer from others; you substitute...

how can shellshock be exploited over SSH?

One example where this can be exploited is on servers with an authorized_keys forced command. When adding an entry to ~/.ssh/authorized_keys, you can prefix the line with command="foo" to force foo to be run any time that ssh public key is used. With this...

Why doesn’t the tilde (~) expand inside double quotes?

The reason, because inside double quotes, tilde ~ has no special meaning, it's treated as literal. POSIX defines Double-Quotes as: Enclosing characters in double-quotes ( "" ) shall preserve the literal value of all characters within the double-quotes, with the...

What is GNU Info for?

GNU Info was designed to offer documentation that was comprehensive, hyperlinked, and possible to output to multiple formats. Man pages were available, and they were great at providing printed output. However, they were designed such that each man page had a...

Set systemd service to execute after fstab mount

a CIFS network location is mounted via /etc/fstab to /mnt/ on boot-up. No, it is not. Get this right, and the rest falls into place naturally. The mount is handled by a (generated) systemd mount unit that will be named something like mnt-wibble.mount. You can...

Merge two video clips into one, placing them next to each other

To be honest, using the accepted answer resulted in a lot of dropped frames for me. However, using the hstack filter_complex produced perfectly fluid output: ffmpeg -i left.mp4 -i right.mp4 -filter_complex hstack output.mp4 ffmpeg -i input1.mp4 -i input2.mp4...

How portable are /dev/stdin, /dev/stdout and /dev/stderr?

It's been available on Linux back into its prehistory. It is not POSIX, although many actual shells (including AT&T ksh and bash) will simulate it if it's not present in the OS; note that this simulation only works at the shell level (i.e. redirection or...

How can I increase the number of inodes in an ext4 filesystem?

It seems that you have a lot more files than normal expectation. I don't know whether there is a solution to change the inode table size dynamically. I'm afraid that you need to back-up your data, and create new filesystem, and restore your data. To create new...

Why doesn’t cp have a progress bar like wget?

The tradition in unix tools is to display messages only if something goes wrong. I think this is both for design and practical reasons. The design is intended to make it obvious when something goes wrong: you get an error message, and it's not drowned in...