Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2086151
  • 博文数量: 414
  • 博客积分: 10312
  • 博客等级: 上将
  • 技术积分: 4921
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-31 01:49
文章分类

全部博文(414)

文章存档

2011年(1)

2010年(29)

2009年(82)

2008年(301)

2007年(1)

分类: C/C++

2008-03-10 07:22:01

19.3 打开伪终端设备

S V R 44 . 3 + B S D系统中打开伪终端设备的方法有所不同。我们提供两个函数来处理所有细节:p t y m _o p e n用来打开下一个有效的伪终端主设备, p t y s_o p e n用来打开相应的从设备。

# include "ourhdr.h"

int  ptym_open (char * pts_ name) ;

                                               -1

int ptys_open (int fdm, char * pts_name ) ;

                                               -1

通常我们不直接调用这两个函数函数p t y _ f o r k(见1 9 . 4节)调用它们并f o r k出一个子进程。

p t y m _ o p e n决定下一个有效的伪终端主设备并打开该设备。这个调用必须分配一个数组来存放主设备或从设备的名称,并且如果调用成功,相应的主设备或从设备的名称会通过p t s _ n a m e返回。这个名称和p t y m_o p e n返回的文件描述符将传给p t y s_o p e n,该函数用来打开一

个从设备。

在讲解p t y _ f o r k函数之后,使用两个函数来打开这两个设备的原因将会很明显。通常,一个进程调用ptym_open来打开一个主设备并且得到从设备的名称。该进程然后fork子进程,子进程在调用setsid 建立新的对话后调用ptys_open来打开从设备。这就是从设备如何成为子进程的控制终端的过程。

19.3.1 SVR4

S V R 4系统下所有伪终端的流实现细节在AT & T1 9 9 0 d〕第1 2章中有所说明,还描述了以下三个函数:g r a n t p t ( 3 )u n l o c k p t ( 3 ),和 p t s n a m e ( 3 )

伪终端主设备是/ d e v / p t m x。这是一个流的增殖设备(clone device)。这意味着当我们打开该增殖设备,其open例程自动决定第一个未被使用的伪终端主设备并打开这个设备。(下一节将看到在伯克利系统中,我们必须自己找到第一个未被使用的伪终端主设备。)

程序19-1 SVR4的伪终端打开函数

#include

#include

#include

#include

#include

#include "ourhdr.h"

 

extern char   *ptsname (int);  

 

int ptym_open (char  *pts_name)

{

      char *ptr;

      int fdm;

     

      strcpy(pts_name, "/dev/ptmx");

      if ((fdm = open (pts_name, O_RDWR)) < 0)

           return (-1);

     

      if (grantpt(fdm) < 0) {

           close (fdm);

           return (-2);

      }

     

      if (unlockpt (fdm) < 0) {

           close (fdm);

           return (-3);

      }

     

      if ((ptr = ptsname(fdm)) == NULL) {

           close (fdm);

           return (-4);

      }

     

      strcpy(pts_name, pty);

      return (fdm);

}

 

int ptys_open (int fdm, char  *pts_name)

{

      int  fds;

     

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

           close (fdm);

           return (-5);

      }

     

      if (ioctl(fds, I_PUSH, "ptem") < 0) {

           close (fdm);

           close (fds);

           return (-6);

      }

     

      if (ioctl(fds, I_PUSH, "ldterm") < 0) {

           close (fdm);

           close (fds);

           return (-7);

      }

     

      if (ioctl (fds, I_PUSH, "ttcompat") < 0) {

           close (fdm);

           close (fds);

           return (-8);

      }

     

      return (fds);

}

首先打开设备/ d e v / p t m x并得到伪终端主设备的文件描述符。打开这个主设备自动锁定了对应的从设备。

然后调用g r a n t p t来改变从设备的许可权。执行如下操作:(a)将从设备的所有权改为有效用户I D;(b)将组所有权改为组t t y;(c)将许可权改为只允许用户-读,用户-写和组-写。将组所有权设置为t t y并允许组-写许可权是因为程序w a l l ( 1 )w r i t e ( 1 )的设置-用户- I D为组t t y。调用函数g r a n t p t执行/ u s r / l i b / p t _ c h m o d。该程序的设置-用户- I Dr o o t,因此它能够修改从设备的所有者和许可权。

函数u n l o c k p t用来清除从设备的内部锁。在打开从设备前必须做这件事情。并且必须调用p t s n a m e来得到从设备的名称。这个名称的格式是/ d e v / p t s /N N N

文件中接下来的函数是p t y s _ o p e n,该函数真正被用来打开一个从设备。在S V R 4系统中,如果调用者是一个还没有控制终端的对话期首进程, o p e n就会分配一个从设备作为控制终端。如果不希望函数自动做这件事,可以在调用时指明O _ N O C T T Y标志。

打开从设备后,将三个流模块放在从设备的流上。p t e m是伪终端虚拟模块, l d t e r m是终端行规程模块。这两个模块合在一起像一个真正的终端模块一样工作。t t co m p a t提供了向老系统如V 74 B S DX e n i x ioctl 调用的兼容性。这是一个可选的模块,但是因为它自动尝试控制台登录和网络登录(见程序1 2 - 1 0的输出),我们将其加到从设备的流中

调用这两个函数的结果是得到:伪终端主设备的文件描述符和从设备的文件描述符。

19.3.2 4.3+BSD

4 . 3 + B S D系统中必须自己来确定第一个可用的伪终端主设备   为达到这个目的,/ d e v / p t y p 0开始并不断尝试,直到成功打开一个可用的伪终端主设备或试完所有设备。在打开设备时,将看到两种可能的错误 E I O指设备已经被使用; E N O E N T表示设备不存在。对于后一种情况,可以停止搜索因为所有的伪终端设备都在被使用中一旦成功地打开一个例如名为/ d e v / p t y M N 的伪终端主设备那么对应的从设备的名称为/ d e v / t t y M N

程序1 9 - 2中的函数p t y s _ o p e n打开该从设备。我们在该函数中调c h o w nc h m o d,必须意识到调用这两个函数的进程必须有超级用户许可权如果必须改变所有权,那么这两个函数调用必须放在一个设置-用户-IDroot用户的可执行函数中,这类似于4.3+BSD系统下的grantpt函数。

4 . 3 + B S D系统之下打开p t y从设备不具有像分配作为控制终端的设备那样的副作用。下一节将探讨如何在4 . 3 + B S D系统下分配控制终端。

这个函数尝试1 6种不同的伪终端主设备:从/ d e v / p t y p 0/ d e v / p t y T f。具体有效的

p t y设备号取决于两个因素:(a)内核中配置的号码;(b/ d e v目录下的特殊文件号。对于任何程序来说,有效的号码是( a)和( b)中较小的一个。并且,即使(a)和(b)中小的值大于6 4,许多现有的B S D应用(如t e l n e t dr l o g i n d等等)会搜索程序19-2中第一个f o r循环中的 p q r s

程序19-2   4.3+BSD的伪终端o p e n函数

#include

#include

#include

#include

#include

#include "ourhdr.h"

 

int ptym_open (char *pts_name)

{

      int fdm;

      char  *ptr1, *ptr2;

     

      strcpy(pts_name, "/dev/ptyXY");

     

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

           pts_name [8] = *ptr1;

           for (ptr2 = "0123456789adcdef"; *ptr2 != 0; ptr2 ++) {

                 pts_name [9] = *ptr2;

                

                 if ((fdm = open (pts_name, O_RDWR)) < 0){

                      if (errno = ENOENT)

                            return (-1);

                      else

                            continue;

                 }

                

                 pts_name[5] = 't';

                 return (fdm);

           }

      }

      return (-1);

}

 

int ptys_open (int fdm, char *pts_name)

{

      struct group *grptr;

      int gid,fds;

     

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

           gid = grptr->gr_gid;

      else

           gid = -1;

     

      chown (pts_name, getuid(), gid);

      chmod (pts_name, S_IRUSR |S_IWUSR |S_IWGRP);

     

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

           close (fdm);

           return (-1);

      }

     

      return (fds);

}

阅读(902) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~