No. Terminal applications read keyboard input from the device file (on Linux, something like /dev/ttyS0
or /dev/ttyUSB0
... for a serial device, /dev/pts/0
for a pseudo-terminal device) corresponding to the terminal with the keyboard you're typing on.
That device doesn't have to be the controlling terminal of the process (or any process for that matters).
You can do cat /dev/pts/x
provided you have read permission to that device file, and that would read what's being typed on the terminal (if any) at the other end.
Actually, if it is the controlling terminal of the process and the process is not in the foreground process group of the terminal, the process would typically be suspended if it attempted to read from it (and if it was in the foreground process group, it would receive a SIGINT/SIGTSTP/SIGQUIT if you sent a ^C
/^Z
/^\
regardless of whether the process is reading from the terminal device or not). Those things would not happen if the terminal device was not the controlling terminal of the process (if the process was part of a different session). That's what controlling terminal is about. That is intended for the job control mechanism as implemented by interactive shells. Beside those SIGTTIN/SIGTTOU and SIGINT/SIGTSTP/SIGQUIT signals, the controlling terminal is involved in the delivery of SIGHUP upon terminal hang hup, it's also the tty device that /dev/tty
redirects to.
In any case, that's only for terminal input: real as in a terminal device connected over a serial cable, emulated like X11 terminal emulators such as xterm
that make use of pseudo-terminal devices, or emulated by the kernel like the virtual terminals on Linux that interact with processes with /dev/tty<x>
(and support more than the standard terminal interface).
Applications like the X server typically get keyboard input from the keyboard drivers. On Linux using common input abstraction layers. The X server, in turn provides an event mechanism to communicate keyboard events to applications connecting to it. For instance, xterm
would receive X11 keyboard events which it translates to writing characters to the master side of a pseudo-terminal device, which translates to processes running "inside" xterm
reading the corresponding characters when they read from the corresponding pseudo-terminal slave device (/dev/pts/x
).
Now, there's no such thing as a terminal application. What we call terminal application above are applications that are typically used in a terminal, that are expected to be displayed in a terminal and take input from a terminal like vi
, and interactive shell or less
. But any application can be controlled by a terminal, and any application that reads or writes files or their stdin/stdout/stderr can be made to perform I/O to a terminal device.
For instance, if you run firefox
, an application that connects to the X server for user I/O, from within a shell running in an xterm
, firefox
will inherit the controlling terminal from its shell parent. ^C
in the terminal would kill it if it was started in foreground by the shell. It will also have its file descriptors 0, 1 and 2 (stdin, stdout and stderr) open on that /dev/pts/<x>
file (again as inherited from its shell parent). And firefox
may very well end up writing on the fd 2 (stderr) for some kind of errors (and if it was put in background and the terminal device was configured with stty tostop
, it would then receive a SIGTTOU and be suspended).
If instead, firefox
is started by your X session manager or Windows manager (when you click on some firefox icon on some menu), it will likely not get any controlling terminal and will have no file descriptor connected to any (you'll see that ps -fp <firefox-pid>
shows ?
as the tty
and lsof -p <firefox-pid>
shows no file descriptor on /dev/pts/*
or /dev/tty*
). If however you browsed to file:///dev/pts/<x>
, firefox
could still do some I/O to a terminal device. And if it opened that file without the O_NOCTTY
flag and if it happened to be a session leader and if that /dev/pts/<x>
didn't already have a session attached to it, that device would end up being the controlling terminal of that firefox
process.
More reading at:
Edit
After your edit clarifies a bit the question and adds some context.
The above should make it clear that a process can read input from any terminal device they like (except the controlling terminal if the process is not in its foreground process group), but that's not really what is of interest to you here.
Your question would be: for an interactive terminal application, where to get the user input from when stdin no longer points to the terminal.
Applications like tr
get their input from stdin and write on stdout. When stdin/stdout is a tty device with a terminal at the other end, they happen to be interactive in that they read and write data from/to the user.
Some terminal text editors (like ed
/ex
and even some vi
implementations) continue reading their input from stdin when stdin is no longer a terminal so they can be scriptable.
A pager though is a typical application that still needs to interact with the user even when their input is not a terminal (at least when their output still goes to the terminal). So they need another channel to the terminal device to take user input. And the question is: which terminal device should they use?
Yes, it should be the controlling terminal. As that's typically what the controlling terminal is meant to be. That's the device that would send the pager a SIGINT/SIGTSTP when you press Ctrl-C/Z, so it makes sense for the pager to read other key strokes from that same terminal.
The typical way to get a file descriptor on the controlling terminal is to open /dev/tty
that redirects there (note that it works even if the process has changed euid so that it doesn't have read permission to the original device. It's a lot better than trying to find a path to the original device (which can't be done portably anyway)).
Some pagers like less
or most
open /dev/tty
even if stdin is a tty device (after all, one could do less < /dev/ttyS0
from within a terminal emulator to see what's being sent over serial).
If opening /dev/tty
fails, that's typically because you don't have a controlling terminal. One might argue that it's because you've been explicitly detached from a terminal so shouldn't be attempting to do user interaction, but there are potential (unusual) situations where you have no controlling terminal device but your stdin/stdout is still a tty device and you'd still want to do user interaction (like an emergency shell in an initrd).
So you could fall back to get user interaction from stdin if it's a terminal.
One could argue that you'd want to check that stdout is a terminal device and that it points to the same terminal device as the controlling one (to account for things that do man -l /dev/stdin < /dev/ttyS0 > /dev/ttyS1
for instance where you don't want the pager spawned by man
to do user interaction) but that's probably not worth the bother especially considering that it's not easy to do portably. That could also potentially break other weird use cases that expect the pager to be interactive as long as stdout is a terminal device.