我们知道在Linux的/dev目录下有一些特殊的文件,比如:/dev/tty, /dev/tty0, /dev/tty1 ...还有/dev/pts/0, /dev/pts/1, /dev/pts/2 ... 等。对于它们我们一般感觉比较理解。本文从编程的角度对其进行一些分析。
首先我们搞清楚几个缩写:
tty是Teletype或者Teletypewriter的缩写。是早期的一种终端设备--电传打字机。通过串行线连接打印机键盘阅读和发送信息的东西,后来被键盘与显示器取代,所以现在一般叫做“终端”。
pty即Pseudo-TTY 伪终端或者叫做虚拟终端。是成对的逻辑终端设备(即master和slave设备, 对master的操作会反映到slave上)。
pts是Pseudo Terminal Slave的缩写。是pty的实现方法,与
ptmx(pseudo-terminal master)配合使用实现pty。当我们telnet到主机,或者直接使用xterm,或者程序需要交互时,我们就需要一个终端。因为只有通过终端我们才能实现人与计算机的交互。只要是人与计算机的交互,就一定是使用的虚拟终端pty(pseudo-tty)
下面我们看一下Linux命令行输出的情况:
digdeep:~$ ls -l /dev/tty*
crw-rw-rw- 1 root tty 5, 0 2011-06-22 11:08 /dev/tty
crw--w---- 1 root root 4, 0 2011-06-22 11:08 /dev/tty0
crw------- 1 root root 4, 1 2011-06-22 11:08 /dev/tty1
crw--w---- 1 root tty 4, 10 2011-06-22 11:08 /dev/tty10
crw--w---- 1 root tty 4, 11 2011-06-22 11:08 /dev/tty11
crw--w---- 1 root tty 4, 12 2011-06-22 11:08 /dev/tty12
crw--w---- 1 root tty 4, 13 2011-06-22 11:08 /dev/tty13
crw--w---- 1 root tty 4, 14 2011-06-22 11:08 /dev/tty14
crw--w---- 1 root tty 4, 15 2011-06-22 11:08 /dev/tty15
crw--w---- 1 root tty 4, 16 2011-06-22 11:08 /dev/tty16
crw--w---- 1 root tty 4, 17 2011-06-22 11:08 /dev/tty17
crw--w---- 1 root tty 4, 18 2011-06-22 11:08 /dev/tty18
crw--w---- 1 root tty 4, 19 2011-06-22 11:08 /dev/tty19
crw------- 1 root root 4, 2 2011-06-22 11:08 /dev/tty2
crw--w---- 1 root tty 4, 20 2011-06-22 11:08 /dev/tty20
crw--w---- 1 root tty 4, 21 2011-06-22 11:08 /dev/tty21
crw--w---- 1 root tty 4, 22 2011-06-22 11:08 /dev/tty22
crw--w---- 1 root tty 4, 23 2011-06-22 11:08 /dev/tty23
crw--w---- 1 root tty 4, 24 2011-06-22 11:08 /dev/tty24
crw--w---- 1 root tty 4, 25 2011-06-22 11:08 /dev/tty25
crw--w---- 1 root tty 4, 26 2011-06-22 11:08 /dev/tty26
crw--w---- 1 root tty 4, 27 2011-06-22 11:08 /dev/tty27
crw--w---- 1 root tty 4, 28 2011-06-22 11:08 /dev/tty28
crw--w---- 1 root tty 4, 29 2011-06-22 11:08 /dev/tty29
crw------- 1 root root 4, 3 2011-06-22 11:08 /dev/tty3
crw--w---- 1 root tty 4, 30 2011-06-22 11:08 /dev/tty30
crw--w---- 1 root tty 4, 31 2011-06-22 11:08 /dev/tty31
crw--w---- 1 root tty 4, 32 2011-06-22 11:08 /dev/tty32
crw--w---- 1 root tty 4, 33 2011-06-22 11:08 /dev/tty33
crw--w---- 1 root tty 4, 34 2011-06-22 11:08 /dev/tty34
crw--w---- 1 root tty 4, 35 2011-06-22 11:08 /dev/tty35
crw--w---- 1 root tty 4, 36 2011-06-22 11:08 /dev/tty36
crw--w---- 1 root tty 4, 37 2011-06-22 11:08 /dev/tty37
crw--w---- 1 root tty 4, 38 2011-06-22 11:08 /dev/tty38
crw--w---- 1 root tty 4, 39 2011-06-22 11:08 /dev/tty39
crw------- 1 root root 4, 4 2011-06-22 11:08 /dev/tty4
crw--w---- 1 root tty 4, 40 2011-06-22 11:08 /dev/tty40
crw--w---- 1 root tty 4, 41 2011-06-22 11:08 /dev/tty41
crw--w---- 1 root tty 4, 42 2011-06-22 11:08 /dev/tty42
crw--w---- 1 root tty 4, 43 2011-06-22 11:08 /dev/tty43
crw--w---- 1 root tty 4, 44 2011-06-22 11:08 /dev/tty44
crw--w---- 1 root tty 4, 45 2011-06-22 11:08 /dev/tty45
crw--w---- 1 root tty 4, 46 2011-06-22 11:08 /dev/tty46
crw--w---- 1 root tty 4, 47 2011-06-22 11:08 /dev/tty47
crw--w---- 1 root tty 4, 48 2011-06-22 11:08 /dev/tty48
crw--w---- 1 root tty 4, 49 2011-06-22 11:08 /dev/tty49
crw------- 1 root root 4, 5 2011-06-22 11:08 /dev/tty5
crw--w---- 1 root tty 4, 50 2011-06-22 11:08 /dev/tty50
crw--w---- 1 root tty 4, 51 2011-06-22 11:08 /dev/tty51
crw--w---- 1 root tty 4, 52 2011-06-22 11:08 /dev/tty52
crw--w---- 1 root tty 4, 53 2011-06-22 11:08 /dev/tty53
crw--w---- 1 root tty 4, 54 2011-06-22 11:08 /dev/tty54
crw--w---- 1 root tty 4, 55 2011-06-22 11:08 /dev/tty55
crw--w---- 1 root tty 4, 56 2011-06-22 11:08 /dev/tty56
crw--w---- 1 root tty 4, 57 2011-06-22 11:08 /dev/tty57
crw--w---- 1 root tty 4, 58 2011-06-22 11:08 /dev/tty58
crw--w---- 1 root tty 4, 59 2011-06-22 11:08 /dev/tty59
crw------- 1 root root 4, 6 2011-06-22 11:08 /dev/tty6
crw--w---- 1 root tty 4, 60 2011-06-22 11:08 /dev/tty60
crw--w---- 1 root tty 4, 61 2011-06-22 11:08 /dev/tty61
crw--w---- 1 root tty 4, 62 2011-06-22 11:08 /dev/tty62
crw--w---- 1 root tty 4, 63 2011-06-22 11:08 /dev/tty63
crw--w---- 1 root root 4, 7 2011-06-22 11:08 /dev/tty7
crw--w---- 1 root tty 4, 8 2011-06-22 11:08 /dev/tty8
crw--w---- 1 root tty 4, 9 2011-06-22 11:08 /dev/tty9
crw-rw---- 1 root dialout 4, 64 2011-06-22 11:08 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 2011-06-22 11:08 /dev/ttyS1
crw-rw---- 1 root dialout 4, 66 2011-06-22 11:08 /dev/ttyS2
crw-rw---- 1 root dialout 4, 67 2011-06-22 11:08 /dev/ttyS3
digdeep:~$
digdeep:~$ ls -l /dev/pts/*
crw--w---- 1 digdeep tty 136, 0 2011-06-22 12:09 /dev/pts/0
crw--w---- 1 digdeep tty 136, 1 2011-06-22 12:14 /dev/pts/1
crw--w---- 1 digdeep tty 136, 2 2011-06-22 12:16 /dev/pts/2
c--------- 1 root root 5, 2 2011-06-22 11:08 /dev/pts/ptmx
digdeep:~$ ps ax
......
820 tty7 Rs+ 0:09 /usr/bin/X :0 -nr -verbose -auth /var/run/gdm/auth-fo
864 tty4 Ss+ 0:00 /sbin/getty -8 38400 tty4
868 tty5 Ss+ 0:00 /sbin/getty -8 38400 tty5
875 tty2 Ss+ 0:00 /sbin/getty -8 38400 tty2
876 tty3 Ss+ 0:00 /sbin/getty -8 38400 tty3
879 tty6 Ss+ 0:00 /sbin/getty -8 38400 tty6
......
1277 tty1 Ss+ 0:00 /sbin/getty -8 38400 tty1
......
1613 pts/0 Ss 0:00 bash
digdeep:~$ tty
/dev/pts/0很显然我们是通过tty1登陆进来的。tty2到tty6已经启动等待其它用户的登陆。tty7用户权限的验证。
/dev/tty1对应的虚拟终端是/dev/pts/0 。
但是从:crw------- 1 root root 4, 1 2011-06-22 11:08 /dev/tty1
我们可以知道,我们根本无权访问/dev/tty1
然而从:crw-rw-rw- 1 root tty 5, 0 2011-06-22 11:08 /dev/tty
我们可以知道,
任何用户对/dev/tty都有读写的权限。
这样安排的原因是:
实际上/dev/tty只是一个相当于“符号链接”,它实际的终端是某个它对应的
/dev/pts/n 。但是我们不知道这里的n到底是等于多少。实际上我们也不需要知道,需要访问终端时我们直接打开文件/dev/tty即可打开对应的/dev/pts/n .
/dev/tty文件的存在,有一个特殊的用法:
当标准输入stdin和标准输出stdout被重定向时,我们仍然可以通过/dev/tty文件而实现对键盘的读取和对显示器的输出!
下面的实例摘录自<
>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #define PAGELEN 24
- #define LINELEN 512
- void do_more(FILE *);
- int see_more(FILE *);
- int main(int argc, char *argv[])
- {
- FILE *fp;
- if(argc == 1)
- do_more(stdin);
- else{
- while(--argc){
- if((fp = fopen(*++argv, "r")) != NULL){
- do_more(fp);
- fclose(fp);
- }else
- exit(1);
- }
- }
- return 0;
- }
- /*
- * read PAGELEN lines, then call see_more() for further instructions.
- */
- void do_more(FILE *fp)
- {
- char line[LINELEN];
- int num_of_lines = 0;
- int see_more(), reply;
- FILE *fp_tty;
- fp_tty = fopen("/dev/tty", "r"); /* NEW: cmd stream */
- if(fp_tty == NULL)
- exit(1);
- while(fgets(line, LINELEN, fp)){ /* more input */
- if(num_of_lines == PAGELEN){ /* full screen ? */
- reply = see_more(fp_tty); /* y: ask user */
- if(reply == 0) /* n: done *? */
- break;
- num_of_lines -= reply; /* reset count */
- }
- if(fputs(line, stdout) == EOF) /* show line */
- exit(1); /* or die */
- num_of_lines++; /* count it */
- }
- }
- /*
- * print message, wait for response, return # of lines to advance
- * a means no, space means yes, CR means one line.
- */
- int see_more(FILE *cmd) /* NEW: accepts arg */
- {
- int c;
- printf("\033[7m more? \033[m"); /* reverse on a vt100 */
- while((c = getc(cmd)) != EOF){ /* get response */
- if(c == 'q') /* q -> N */
- return 0;
- if(c == ' ') /* ' ' -> next page */
- return PAGELEN; /* how many to show */
- if(c == '\n') /* Enter key -> 1 line */
- return 1;
- }
- return 0;
- }
编译:gcc -Wall -o more02 more02.c
执行:./more02 < more02.c
上面的执行我们对输入进行了重定向,但是我们还是可以通过/dev/tty来进行对键盘输入的读取!