Search code examples
tty

Inner workings of TTY under Linux


I've been trying to figure out how TTY drivers works for a while now (with full understanding each kernel's implementation may be different), and came across a nice article: The TTY demystified

I notice however that it claims xterm does not have a stdin, stdout or stderr. How does xterm and other terminal emulators get the input from bash and other child processes so it can print to the window? Does the terminal emulator have a connection to a TTY driver at all?


Solution

  • I don't believe the claim that xterm(1) has no stdin, stdout, or stderr makes much sense. And, just skimming that article, I think they were left blank on the diagram because they didn't figure much into what he was describing.

    You can check your own terminals' file descriptors easily enough. The urxvt(1) terminals that I normally use look like this:

    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 0 -> /home/sarnold/.xsession-errors
    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 1 -> /home/sarnold/.xsession-errors
    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 2 -> /home/sarnold/.xsession-errors
    

    An xterm(1) I started from one of those urxvt(1) terminals looks like this:

    lrwx------ 1 sarnold sarnold 64 2011-11-15 16:45 0 -> /dev/pts/1
    lrwx------ 1 sarnold sarnold 64 2011-11-15 16:45 1 -> /dev/pts/1
    lrwx------ 1 sarnold sarnold 64 2011-11-15 16:45 2 -> /dev/pts/1
    

    And an xterm(1) I started using my window manager's dmenu(1) launcher looks like this:

    lrwx------ 1 sarnold sarnold 64 2011-11-15 16:46 0 -> /dev/null
    lrwx------ 1 sarnold sarnold 64 2011-11-15 16:46 1 -> /home/sarnold/.xsession-errors
    lrwx------ 1 sarnold sarnold 64 2011-11-15 16:46 2 -> /home/sarnold/.xsession-errors
    

    The important part to remember about stdin, stdout, and stderr is that they are completely unrelated to the graphical display that the terminal emulators offer. If your terminal program needs to write an error to stderr, say via perror(3), its output might go to the terminal where you started it or to a session error log such as ~/.xsession-errors. If you log in via ssh(1) and start your xterm(1) like this:

    DISPLAY=:1 xterm -e 'echo hello ; sleep 10`
    

    You'll see it start up and display hello. (Assuming your DISPLAY matches mine.) If you change the command to:

    DISPLAY=:1 xterm -fn fiddly -e 'echo hello ; sleep 10'
    

    You'll see that the error message about the incorrect font is sent to the terminal where you started xterm(1) -- not to its own graphical interface. (This is a bit funny, because if you change SHELL to something that doesn't exist, or attempt to execute something that doesn't exist, the error message will be printed within the graphical window instead of to the standard error.)

    A file that is also open in my terminal emulators is ptmx(4):

    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 0 -> /home/sarnold/.xsession-errors
    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 1 -> /home/sarnold/.xsession-errors
    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 2 -> /home/sarnold/.xsession-errors
    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 3 -> anon_inode:[eventpoll]
    lr-x------ 1 sarnold sarnold 64 2011-11-10 21:33 4 -> pipe:[16398]
    l-wx------ 1 sarnold sarnold 64 2011-11-10 21:33 5 -> pipe:[16398]
    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 6 -> socket:[16399]
    lrwx------ 1 sarnold sarnold 64 2011-11-10 21:33 7 -> /dev/ptmx
    

    Opening the ptmx(4) device gives the terminal emulator the pipe connections for the PTY master and slave. It is to these pipes that the terminal emulator software communicates with the clients and the kernel.

    I can't do the tty layer justice; I strongly recommend reading the pty section from Advanced Programming in the Unix Environment, 2nd edition for full details. The book (and source code include writing your own pty driver which can be used to implement script(1)-like functionality or tricking the standard C IO streams into using line-buffering rather than block-buffering when the program doesn't provide any command line options to control this natively.