linux 查看伪终端,Linux 伪终端

1、综述

伪终端对于一个应用程序而言,看上去像一个终端,但事实上伪终端并不是一个真正的终端。从内核角度看,伪终端看起来像一个双向管道,而事实上Solaris的伪终端就是用STREAMS构建的。伪终端总是成对地使用的,就好像是个管道的两端。一端的设备称为"主设备"(master),另一端的设备称为"从设备"(slave),每一对伪终端设备,例如/dev/ptys0和/dev/ttys0,就好像是通过一个管道连在一起,其"从设备"一端与普通的终端设备没有什么区别,而"主设备"一端则跟管道文件相似。

伪终端的用途:

(1)构造网络登录服务器,例如telnetd和rlogind服务器。

(2)script程序,将终端会话的所有输入和输出信息复制到一个文件中,自己置于终端和登录shell的一个新调用之间。

(3)expect程序,伪终端可以在非交互模式中驱动交互程序的运行

(4)运行协同进程

(5)观看长时间运行程序的输出

2、打开伪终端设备

各种平台打开伪终端设备的方法有所不同,posix_openpt用来打开一个可用的伪终端主设备,该函数可移植的。伪终端从设备可被使用之前,必须设置它的权限,调用grantpt函数设置权限,使得应用程序可以访问它。unlockpt函数批准读伪终端从设备的访问,从而允许应用程序打开该设备。ptsname函数找到从伪终端设备的路径名。函数原型如下:

#include

#include

int posix_openpt(int oflag);

//成功返回下一个可以用的PTY主设备的文件描述符,出错返回-1

int grantpt(int fildes); //更改从PTY设备的权限

int unlockpt(int fildes) //允许从PTY设备被打开

char *ptsname(int fildes); //成功返回指向PTY从设备名的指针,出错返回NULL

写个程序调用以上函数获取一个可用的PTY主设备描述符,然后获取该主设备的从伪终端的路径名。程序如下:

a4c26d1e5885305701be709a3d33442f.png

1 #define _XOPEN_SOURCE

2 #include

3 #include

4 #include

5 #include

6

7 int main()

8 {

9 int masterfd,slavefd;

10 char *slavedevice;

11 if((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1)

12 {

13 perror("posix_openpt() error");

14 exit(-1);

15 }

16 if(grantpt(masterfd) == -1)

17 {

18 perror("grantpt() error");

19 exit(-1);

20 }

21 if(unlockpt(masterfd) == -1)

22 {

23 perror("unlockpt() error");

24 exit(-1);

25 }

26 if((slavedevice=ptsname(masterfd)) == NULL)

27 {

28 perror("ptsname() error");

29 exit(-1);

30 }

31 printf("slave device is: %s\n", slavedevice);

32 exit(0);

33 }

a4c26d1e5885305701be709a3d33442f.png

程序执行结果如下:

a4c26d1e5885305701be709a3d33442f.png

介绍另外两个函数ptym_open和ptys_open,前者用于打开下一个可用的PTY主设备,后者打开相应的从设备。这两个函数需要自己实现,函数声明如下所示:

int ptym_open(char *pts_name,int pts_namesz);

int pyts_open(char *pts_name);

3、基于STREAMS的伪终端

基于STREAMS的PTY主克隆设备是/dev/ptmx。打开该设备,其克隆open例程自动决定第一个未被使用的PTY主设备,并打开这个设备。ptym_open和ptys_open实现如下所示:

a4c26d1e5885305701be709a3d33442f.pngView

Code

测试结果如下:

a4c26d1e5885305701be709a3d33442f.png

4、基于BSD的伪终端

需要自己确定第一个可用的PTY主设备,主设备名为/dev/ptyAX(/dev/ptys0),这里的A表示16个字母"pqrstuvwxyQPRST"中的一个,X则为16个16进制数字(0~f)之一,这样一共可以256个伪终端主设备。从/dev/ptyp0开始不断尝试,直到成功打开一个可用的PTY主设备或试完了所有设备。ptym_open和ptys_open实现如下所示:

a4c26d1e5885305701be709a3d33442f.pngView

Code

a4c26d1e5885305701be709a3d33442f.png

1 #define _XOPEN_SOURCE

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10 #include

11

12 #ifndef _HAS_OPENPT

13 int posix_openpt(int oflag)

14 {

15 int fdm;

16 char *ptr1,*ptr2;

17 char ptm_name[16];

18

19 strcpy(ptm_name,"/dev/ptyXY");

20 for(ptr1="pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++)

21 {

22 ptm_name[8] = *ptr1;

23 for(ptr2="0123456789abcdef";*ptr2 != 0;ptr2++)

24 {

25 ptm_name[9] = *ptr2;

26 //try to open the master

27 if((fdm = open(ptm_name,oflag)) < 0)

28 {

29 if(errno == ENOENT)

30 return -1;

31 else

32 continue;

33 }

34 return fdm;

35 }

36 }

37 errno = EAGAIN;

38 return -1;

39 }

40 #endif

41

42 #ifndef _HAS_PTSNAME

43 char *ptsname(int fdm)

44 {

45 static char pts_name[16];

46 char *ptm_name;

47 ptm_name = ttyname(fdm);

48 if(ptm_name == NULL)

49 return NULL;

50 strncpy(pts_name,ptm_name,sizeof(pts_name));

51 pts_name[sizeof(pts_name)-1] = '\0';

52 if(strncmp(pts_name,"/dev/pty",9) == 0)

53 pts_name[9] = 's';

54 else

55 pts_name[5] = 't';

56 return pts_name;

57 }

58 #endif

59

60 #ifndef _HAS_GRANTPT

61 int grantpt(int fdm)

62 {

63 struct group *grptr;

64 int gid;

65 char *pts_name;

66

67 pts_name = ptsname(fdm);

68 if((grptr = getgrnam("tty")) != NULL)

69 gid = grptr->gr_gid;

70 else

71 gid = -1;

72 if(chown(pts_name,getuid(),gid) < 0)

73 return -1;

74 return chmod(pts_name,S_IRUSR | S_IWUSR | S_IWGRP);

75 }

76 #endif

77

78 #ifndef _HAS_UNLOCKPT

79 int unlockput(int fdm)

80 {

81 return 0;

82 }

83 #endif

84 int ptym_open(char *pts_name,int pts_namesz)

85 {

86 char *ptr;

87 int fdm;

88 strncpy(pts_name,"/dev/ptyXX",pts_namesz);

89 pts_name[pts_namesz-1] = '\0';

90 if((fdm = posix_openpt(O_RDWR)) < 0)

91 return -1;

92 if(grantpt(fdm) < 0)

93 {

94 close(fdm);

95 return -2;

96 }

97 if(unlockput(fdm) < 0)

98 {

99 close(fdm);

100 return -3;

101 }

102 if((ptr = ptsname(fdm)) < 0)

103 {

104 close(fdm);

105 return -4;

106 }

107 strncpy(pts_name,ptr,pts_namesz);

108 pts_name[pts_namesz-1] = '\0';

109 return fdm;

110 }

111 int ptys_open(char *pts_name)

112 {

113 int fds,setup;

114 if((fds = open(pts_name,O_RDWR)) < 0)

115 return -5;

116 return fds;

117 }

a4c26d1e5885305701be709a3d33442f.png

5、基于Linux的伪终端

Linux支持访问伪终端的BSD方法,也支持使用/dev/ptmx的克隆风格的伪终端接口。在Linux中PTY从设备以为组tty所拥有,ptym_open和ptys_open实现如下所示:

a4c26d1e5885305701be709a3d33442f.pngView

Code

a4c26d1e5885305701be709a3d33442f.png

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10

11 #define TIOCGPTN _IOR('T',0x30, unsigned int)

12 #define TIOCSPTLCK _IOW('T',0x31, int)

13

14 #ifndef _HAS_OPENPT

15 int posix_openpt(int oflag)

16 {

17 int fdm;

18 fdm = open("/dev/ptmx",oflag);

19 return fdm;

20 }

21 #endif

22

23 #ifndef _HAS_PTSNAME

24 char *ptsname(int fdm)

25 {

26 static char pts_name[16];

27 int sminor;

28 if(ioctl(fdm,TIOCGPTN,&sminor) < 0)

29 return NULL;

30 snprintf(pts_name,sizeof(pts_name),"/dev/pts/%d",sminor);

31 return pts_name;

32 }

33 #endif

34

35 #ifndef _HAS_GRANTPT

36 int grantpt(int fdm)

37 {

38 char *pts_name;

39 pts_name = ptsname(fdm);

40 return chmod(pts_name,S_IRUSR | S_IWUSR | S_IWGRP);

41 }

42 #endif

43

44 #ifndef _HAS_UNLOCKPT

45 int unlockput(int fdm)

46 {

47 int lock = 0;

48 return (ioctl(fdm,TIOCSPTLCK,&lock));

49 }

50 #endif

51 int ptym_open(char *pts_name,int pts_namesz)

52 {

53 char *ptr;

54 int fdm;

55 strncpy(pts_name,"/dev/ptmx",pts_namesz);

56 pts_name[pts_namesz-1] = '\0';

57 if((fdm = posix_openpt(O_RDWR)) < 0)

58 return -1;

59 if(grantpt(fdm) < 0)

60 {

61 close(fdm);

62 return -2;

63 }

64 if(unlockput(fdm) < 0)

65 {

66 close(fdm);

67 return -3;

68 }

69 if((ptr = ptsname(fdm)) < 0)

70 {

71 close(fdm);

72 return -4;

73 }

74 strncpy(pts_name,ptr,pts_namesz);

75 pts_name[pts_namesz-1] = '\0';

76 return fdm;

77 }

78 int ptys_open(char *pts_name)

79 {

80 int fds,setup;

81 if((fds = open(pts_name,O_RDWR)) < 0)

82 return -5;

83 return fds;

84 }

85 int main()

86 {

87 int fdm,fds;

88 char slave_name[20];

89 fdm = ptym_open(slave_name,sizeof(slave_name));

90 if(fdm<0)

91 {

92 perror("ptym_open() error");

93 exit(-1);

94 }

95 printf("open master device successfully.\n");

96 printf("slave device name is:%s\n",slave_name);

97 fds = ptys_open(slave_name);

98 if(fds < 0)

99 {

100 perror("ptys_open() error");

101 exit(-1);

102 }

103 printf("open slave device successfully.\n");

104 exit(0);

105 }

a4c26d1e5885305701be709a3d33442f.png

执行结果如下所示:

a4c26d1e5885305701be709a3d33442f.png

6、pty_fork函数

函数功能:用fork调用打开主设备和从设备,创建作为会话首进程的子进程并使其具有控制终端。函数声明如下:

#include

#include

pid_t ptt_fork(int *ptrfdm,char *slave_name,int slave_names,const

struct termiosz *slave_termios,const struct winsize

*slave_winsize);

函数实现如下所示:

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.png

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include <string.h>

7 #include

8 #include

9 #include

10 #include

11 #ifndef IIOCGWINSZ12 #include

13 #endif

14 pid_t ptt_fork(int *ptrfdm,char *slave_name,intslave_namesz,15 const struct termios *slave_termios,16 const struct winsize *slave_winsize)17 {18 intfdm,fds;19 pid_t pid;20 char pts_name[20];21

22 if((fdm=ptym_open(pts_name,sizeof(pts_name))) < 0)23 {24 perror("ptym_open()error");25 exit(-1);26 }27 if(slave_name !=NULL)28 {29 strncpy(slave_name,pts_name,slave_namesz);30 slave_name[slave_namesz-1] = '\0';31 }32 if((pid = fork()) < 0)33 {34 perror("fork() error");35 exit(-1);36 }37 else if(pid == 0)38 {39 if(setsid() < 0)40 {41 perror("setsid() error");42 exit(-1);43 }44 if((fds = ptys_open(pts_name)) < 0)45 {46 perror("ptys_open() error");47 exit(-1);48 }49 close(fdm);50 #if defined (TIOCSCTTY)

51 if(ioctl(fds,TIOCSCTTY,(char *)0) < 0)52 {53 perror("TIOCSCTTY error");54 exit(-1);55 }56 #endif

57 if(slave_termios !=NULL)58 {59 if(tcsetattr(fds,TCSANOW,slave_termios) < 0)60 {61 perror("tcsetattr error on slave pty");62 exit(-1);63 }64 }65 if(slave_winsize !=NULL)66 {67 if(ioctl(fds,TIOCSWINSZ,slave_winsize) < 0)68 {69 perror("TIOCSWINSZ error on slave pty");70 exit(-1);71 }72 }73

74 if(dup2(fds,STDIN_FILENO) !=STDIN_FILENO)75 {76 perror("dups error to stdin");77 exit(-1);78 }79 if(dup2(fds,STDOUT_FILENO) !=STDOUT_FILENO)80 {81 perror("dups error to stdout");82 exit(-1);83 }84 if(dup2(fds,STDERR_FILENO) !=STDERR_FILENO)85 {86 perror("dups error to stderr");87 exit(-1);88 }89 if(fds != STDIN_FILENO && fds != STDOUT_FILENO && fds !=STDERR_FILENO)90 close(fds);91 return 0;92 }93 else

94 {95 *ptrfdm =fdm;96 returnpid;97 }98 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值