All of the processes in a session may have a (single) controlling terminal. Upon creation, a session has no controlling terminal; the controlling terminal is established when the session leader first opens a terminal that is not already the controlling terminal for a session, unless the O_NOCTTY
flag is specified when calling open(). A terminal may be the controlling terminal for at most one session.
SUSv3 specifies the function tcgetsid(int fd) (prototyped in <termios.h>
), which returns the ID of the session associated with the controlling terminal specified by fd. This function is provided in glibc (where it is implemented using the ioctl() TIOCGSID
operation).
The controlling terminal is inherited by the child of a fork() and preserved across an exec().
When a session leader opens a controlling terminal, it simultaneously becomes the controlling process for the terminal. If a terminal disconnect subsequently occurs, the kernel sends the controlling process a SIGHUP
signal to inform it of this event. We go into further detail on this point in SIGHUP and Termination of the Controlling Process.
If a process has a controlling terminal, opening the special file /dev/tty
obtains a file descriptor for that terminal. This is useful if standard input and output are redirected, and a program wants to ensure that it is communicating with the controlling terminal. For example, the getpass() function described in Password Encryption and User Authentication opens /dev/tty
for this purpose. If the process doesn’t have a controlling terminal, opening /dev/tty
fails with the error ENXIO
.
The ioctl(fd, TIOCNOTTY) operation can be used to remove a process’s association with its controlling terminal, specified via the file descriptor fd. After this call, attempts to open /dev/tty
will fail. (Although not specified in SUSv3, the TIOCNOTTY
operation is supported on most UNIX implementations.)
If the calling process is the controlling process for the terminal, then as for the termination of the controlling process (SIGHUP and Termination of the Controlling Process), the following steps occur:
All processes in the session lose their association with the controlling terminal.
The controlling terminal loses its association with the session, and can therefore be acquired as the controlling process by another session leader.
The kernel sends a SIGHUP
signal (and a SIGCONT
signal) to all members of the foreground process group, to inform them of the loss of the controlling terminal.
SUSv3 leaves the manner in which a session acquires a controlling terminal unspecified, merely stating that specifying the O_NOCTTY
flag when opening a terminal guarantees that the terminal won’t become a controlling terminal for the session. The Linux semantics that we have described above derive from System V.
On BSD systems, opening a terminal in the session leader never causes the terminal to become a controlling terminal, regardless of whether the O_NOCTTY
flag is specified. Instead, the session leader uses the ioctl() TIOCSCTTY
operation to explicitly establish the terminal referred to by the file descriptor fd as the controlling terminal:
if (ioctl(fd, TIOCSCTTY) == -1) errExit("ioctl");
This operation can be performed only if the session doesn’t already have a controlling terminal.
The TIOCSCTTY
operation is also available on Linux, but it is not widespread on other (non-BSD) implementations.
The ctermid() function returns a pathname referring to the controlling terminal.
#include <stdio.h> /* Defines L_ctermid constant */
char *ctermid
(char *ttyname);
Returns pointer to string containing pathname of controlling terminal, or NULL
if pathname could not be determined
The ctermid() function returns the controlling terminal’s pathname in two different ways: via the function result and via the buffer pointed to by ttyname.
If ttyname is not NULL
, then it should be a buffer of at least L_ctermid
bytes, and the pathname is copied into this array. In this case, the function return value is also a pointer to this buffer. If ttyname is NULL
, ctermid() returns a pointer to a statically allocated buffer containing the pathname. When ttyname is NULL
, ctermid() is not reentrant.
On Linux and other UNIX implementations, ctermid() typically yields the string /dev/tty
. The purpose of this function is to ease portability to non-UNIX systems.