In most UNIX systems, the control terminal name is/dev/tty. POSIX.1, which provides a runtime function that can be used to determine the name of the control terminal.
# Include <stdio. h>
Char * ctermid (char * ptr );
Return Value: If successful, the pointer to the control terminal name is returned. If an error occurs, the pointer to a null string is returned.
If ptr is not empty, it is considered a pointer pointing to an array of at least L_ctermid bytes. The control terminal name of the process is stored in this array. The constant L_ctermid is defined in <stdio. h>. If ptr is a null pointer, this function allocates space for arrays (usually static variables. Similarly, the control terminal name of the process is stored in this array.
In both cases, the starting address of the array is returned as a function value. Because most UNIX systems use/dev/tty as the control terminal name, this function is mainly used to improve portability to other operating systems.
Instance: ctermid Function
Program list 18-3 POSIX.1 ctermid function implementation
# Include <stdio. h>
# Include <string. h>
Static char ctermid_name [L_ctermid];
Char *
Ctermid (char * str)
{
If (str = NULL)
Str = ctermid_name;
Return (strcpy (str, "/dev/tty");/* strcpy () returns str */
}
Note: because we cannot determine the size of the caller's buffer, we cannot prevent excessive use of the buffer.
The other two functions related to the terminal identity are isatty and ttyname. The former returns true when the file descriptor references a terminal device, while the latter returns the path name of the terminal device opened on the file descriptor.
# Include <unisd. h>
Int isatty (int filedes );
Return Value: if it is a terminal device, 1 (true) is returned, and 0 (false) is returned)
Char * ttyname (int filedes );
Return Value: pointer to the terminal path name. If an error occurs, NULL is returned.
Instance: isatty Function
Implementation of the isatty function in listing 18-4 POSIX.1
# Include <termios. h>
Int
Isatty (int fd)
{
Struct termios ts;
Return (tcgetattr (fd, & ts )! =-1);/* true if no error (is a tty )*/
}
Program list 18-5 test isatty Function
# Include "apue. h"
Int
Main (void)
{
Printf ("fd 0: % s \ n", isatty (0 )? "Tty": "not a tty ");
Printf ("fd 1: % s \ n", isatty (1 )? "Tty": "not a tty ");
Printf ("fd 2: % s \ n", isatty (2 )? "Tty": "not a tty ");
Exit (0 );
}
When running the program in the program list 18-5, we can get the following results:
Instance: ttyname Function
Implementation of the POSIX.1 ttyname function in the program list 18-6
# Include <sys/stat. h>
# Include <dirent. h>
# Include <limits. h>
# Include <string. h>
# Include <termios. h>
# Include <unistd. h>
# Include <stdlib. h>
Struct devdir {
Struct devdir * d_next;
Char * d_name;
};
Static struct devdir * head;
Static struct devdir * tail;
Static char pathname [_ POSIX_PATH_MAX + 1];
Static void
Add (char * dirname)
{
Struct devdir * ddp;
Int len;
Len = strlen (dirname );
/*
* Skip..., and/dev/fd.
*/
If (dirname [len-1] = '.') & (dirname [len-2] = '/' |
(Dirname [len-2] = '.' & dirname [len-3] = '/')))
Return;
If (strcmp (dirname, "dev/fd") = 0)
Return;
Ddp = malloc (sizeof (struct devdir ));
If (ddp = NULL)
Return;
Ddp-> d_name = strdup (dirname );
If (ddp-> d_name = NULL)
{
Free (ddp );
Return;
}
Ddp-> d_next = NULL;
If (tail = NULL)
{
Head = ddp;
Tail = ddp;
}
Else
{
Tail-> d_next = ddp;
Tail = ddp;
}
}
Static void
Cleanup (void)
{
Struct devdir * ddp, * nddp;
Ddp = head;
While (ddp! = NULL)
{
Nddp = ddp-> d_next;
Free (ddp-> d_name );
Free (ddp );
Ddp = nddp;
}
Head = NULL;
Tail = NULL;
}
Static char *
Searchdir (char * dirname, struct stat * fdstatp)
{
Struct stat devstat;
DIR * dp;
Int devlen;
Struct dirent * dirp;
Strcpy (pathname, dirname );
If (dp = opendir (dirname) = NULL)
Return (NULL );
Strcat (pathname ,"/");
Devlen = strlen (pathname );
While (dirp = readdir (dp ))! = NULL)
{
Strncpy (pathname + devlen, dirp-> d_name,
_ POSIX_PATH_MAX-devlen );
/*
* Skip aliases.
*/
If (strcmp (pathname, "/dev/stdin") = 0 |
Strcmp (pathname, "/dev/stdout") = 0 |
Strcmp (pathname, "/dev/stderr") = 0)
Continue;
If (stat (pathname, & devstat) <0)
Continue;
If (S_ISDIR (devstat. st_mode ))
{
Add (pathname );
Continue;
}
If (devstat. st_ino = fdstatp-> st_ino &&
Devstat. st_dev = fdstatp-> st_dev)/* found a match */
{
Closedir (dp );
Return (pathname );
}
}
Closedir (dp );
Return (NULL );
}
Char *
Ttyname (int fd)
{
Struct stat fdstat;
Struct devdir * ddp;
Char * rval;
If (isatty (fd) = 0)
Return (NULL );
If (fstat (fd, & fdstat) <0)
Return (NULL );
If (S_ISCHR (fdstat. st_mode) = 0)
Return (NULL );
Rval = searchdir ("/dev", & fdstat );
If (rval = NULL)
{
For (ddp = head; ddp! = NULL; ddp = ddp-> d_next)
If (rval = searchdir (ddp-> d_name, & fdstat ))! = NULL)
Break;
}
Cleanup ();
Return (rval );
}
Here, you can use the Read/dev directory to find table items with the same device number and I node number. Each file system has a unique device number (st_dev field http://www.cnblogs.com/nufangrensheng/p/3501385.html In the stat structure), and each directory item in the file system has a unique I node number (st_ino field in the stat structure ). In this function, it is assumed that the desired directory item is found when a Matched Device number and a matched I-node number are found.
The terminal name may be in the/dev subdirectory. Therefore, you need to search for the entire file system subtree under/dev. We skipped many directories that generate incorrect or strange results. They are/dev/.,/dev/.. And/dev/fd. I skipped some aliases, namely/dev/stdin,/dev/stdout, And/dev/stderr. They are symbolic links to files in the/dev/fd directory.
Procedure List 18-7 test the ttyname Function
# Include "apue. h"
Int
Main (void)
{
Char * name;
If (isatty (0 ))
{
Name = ttyname (0 );
If (name = NULL)
Name = "undefined ";
}
Else
{
Name = "not a tty ";
}
Printf ("fd 0: % s \ n", name );
If (isatty (1 ))
{
Name = ttyname (1 );
If (name = NULL)
Name = "undefined ";
}
Else
{
Name = "not a tty ";
}
Printf ("fd 1: % s \ n", name );
If (isatty (2 ))
{
Name = ttyname (2 );
If (name = NULL)
Name = "undefined ";
}
Else
{
Name = "not a tty ";
}
Printf ("fd 2: % s \ n", name );
Exit (0 );
}
Run the program to obtain:
File descriptors 0, 1, and 2 all point to the same terminal/dev/tty1.