0

All I know is that a process has file descriptor 0/1 set to stdin/stdout by default. But how does programs such as vi know about window size, especially when I can resize the window freely in desktop environment? I can't think of how this could be sent via signals, so I guess there are some other mechanisms?.

I do not know anything about terminal emulator, which I guess might be related to the question. Any pointers will be helpful and appreciated.

QnA
  • 555
  • Duplicate of https://unix.stackexchange.com/q/93173/117549 ? – Jeff Schaller Apr 16 '20 at 02:32
  • @JeffSchaller the answers to that Q (just like almost all the info you can get via internet searches) won't tell which process(es) the SIGWINCH signal is sent to. You just have to assume that the right thing happens in the end ;-) –  Apr 16 '20 at 06:20

1 Answers1

6

The size of a terminal is kept in kernel-internal structure, and can be queried by the TIOCGWINSZ and set by TIOCSWINSZ ioctls. See the ioctl_tty(2) manpage for details.

Each time the window size is set via TIOCSWINSZ (eg. by xterm when its GUI window was resized) the kernel will send a SIGWINCH signal to the foreground process group of that terminal.

A program like vi catches that signal and updates its idea of the window size via TIOCGWINSZ.

The window size is usually set by the program driving the master end of a pseudo-tty (like xterm or sshd) but any process able to open the tty (whether in read-only or write-only mode) can do it.

A command line interface to those ioctls is via the stty program. (eg. stty cols 80 rows 40). This is useful with real serial terminals, which have no inherent size, and no standard way to pass that info through.


Though not yet standardized [1], all of this is not Linux-specific, and works similarly on other systems like BSD or Solaris. A notable difference is that a background process trying to change the size of its controlling tty with TIOCSWINSZ will get a SIGTTOU signal on BSD and Solaris, but not on Linux.

On any of those systems, a background process will NOT get a SIGWINCH signal, neither when its controlling tty is resized, nor when it becomes a foreground process. Full screen programs assume that they're either running in the foreground or stopped, and also query the terminal size upon a SIGCONT signal (together with other tty operations like switching to the alternate screen or turning the canonical mode off).

Notice that a process doesn't need to have an open handle to a tty for it to be its controlling tty, and it can have an open handle to a tty without it being its controlling tty.

There's no other way for a process to be notified of terminal size changes other than being in the tty's foreground process group. Also, there's no general way to be notified of other changes to the terminal parameters: tcsetattr(3) will not generate any signal or event that can be select(2)ed on.

[1] A standard interface is slated to be included in an upcoming version of POSIX, with the tcgetwinsize and tcsetwinsize functions, easily implementable as wrappers to ioctl(TIOC[SG]WINSZ). See here for details.

  • The interface is standardized... The Signal SIGWINCH has been added to POSIX and the functions tcgetsize() and tcsetsize() have been added to POSIX. They are part of the upcomming Issue 8 standard version that is expected to be ready to the end of this year. – schily Apr 16 '20 at 07:38
  • I've added that info. I hope I got the right link –  Apr 16 '20 at 08:07
  • Correct, the ioctl definitions have not been standardized for the same reason that caused to standardize tcgetattr() instead of the preexisting ioctls. – schily Apr 16 '20 at 08:20
  • thanks. So what is exactly a controlling tty? It seems the linux tty command merely check the file /proc/self/fd/0, does that mean fd 0 is the controlling tty? – QnA Apr 16 '20 at 20:36
  • @QnA No, the tty command does not show the name of the controlling tty, but the "file name of the terminal connected to standard input". If a process wants to read, write or performs ioctls like TIOCGWINSZ on its controlling tty, it can do it by opening the /dev/tty pseudo-device, which will relay all those operations to the real device which is the controlling tty. –  Apr 17 '20 at 02:29
  • @QnA The controlling tty is not an abstract concept -- it's part of the process structure, just like the current working directory, the pid, etc. On linux, the device number of the controlling tty is the 7th field of the /proc/<pid>/stat file (that's where ps -o tty get its info from) but that can't be reliably matched with a path, because multiple tty can have the same device number. –  Apr 17 '20 at 02:35
  • thanks again. I guess I still don't understand what you mean by 'controlling tty'. How does a process know which /dev/tty* (or /dev/pts/*) to open? Is there a special fd or some other variable to remember this information? – QnA Apr 17 '20 at 02:35
  • A process should open /dev/tty (not /dev/tty1 or /dev/pts/1 or any path returned by tty(1)) if it wants to access its controlling tty. –  Apr 17 '20 at 02:38
  • I didn't find how /dev/tty can always points to controlling tty of current process, but it seems far enough off-topic, hence posted another thread... https://unix.stackexchange.com/questions/580804/how-is-dev-tty-file-implemented-such-that-it-always-points-to-the-controlling – QnA Apr 17 '20 at 20:52
  • Note that only tcgetwinsize and tcsetwinsize are going to be added to POSIX. The ioctl calls won't as POSIX does not standardise any ioctl calls besides the STREAMS interface. That's why I devised the tcgetwinsize and tcsetwinsize functions. – FUZxxl Jun 12 '20 at 12:04
  • @FUZxxl thanks, (hopefully) clarified the wording. –  Jun 12 '20 at 16:58