打开伪终端设备pts


p align="JUSTIFY">19.3 打开伪终端设备

  在SVR4和4.3+BSD系统中打开伪终端设备的方法有所不同。我们提供两个函数来处理所有细节:ptym_open用来打开下一个有效的伪终端主设备,ptys_open用来打开相应的从设备。

#include ourhdr.h
int ptym_open(char *pts_name);

  返回:如果操作成功,返回伪终端主设备文件述符;否则返回-1

int ptys_open(int fdm, char *pts_name);

  返回:如果操作成功,返回伪终端从设备文件述符;否则返回-1

  通常我们不直接调用这两个函数--函数pty_fork(19.4节)调用它们并fork出一个子进程。ptym_open决定下一个有效的伪终端主设备并打开该设备。这个调用必须分配一个数组来存放主设备或从设备的名称,并且如果调用成功,相应的主设备或从设备的名称会通过pts_name返回。这个名称和ptym_open返回的文件描述符将传给ptys_open,该函数用来打开一个从设备。

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

19.3.1 系统V的版本4

  所有在SVR4系统下的伪终端的流实现细节在ATT[1990d]的第十二章中有所说明。三个函数在下列手册页中描述:grantpt(3),unlockpt(3),和ptsname(3)。伪终端主设备是/dev/ptmx。这是一个流的增殖设备。这意味着当我们打开该增殖设备,其open例程自动决定第一个未被使用的伪终端主设备并打开这个设备。(在下一节我们将看到在Berkeley系统中,我们必须自己找到第一个未被使用的伪终端主设备。)

________________________________________________________
#include
#include
#include
#include
#include
#include ourhdr.h
extern char *ptsname(int); /* prototype not in any system header */
int > ptym_open(char *pts_name)
{
char *ptr;
int fdm;
strcpy(pts_name, /dev/ptmx); /* in case open fails */
if ( (fdm = open(pts_name, O_RDWR)) 0)return(-1);
if (grantpt(fdm) 0) { /* grant access to slave */
close(fdm);
return(-2);
}
if (unlockpt(fdm) 0) { /* clear slaves lock flag */
close(fdm);
return(-3);
}
if ( (ptr = ptsname(fdm)) == NULL) { /* get slaves name */
close(fdm);
return(-4);
}
strcpy(pts_name, ptr); /* return name of slave */
return(fdm); /* return fd of master */
}
int
ptys_open(int fdm, char *pts_name)
{
int fds;
/* following should allocate controlling terminal */
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);
}
_______________________________________________________________
程序19.1 SVR4的伪终端打开函数

  我们首先打开设备/dev/ptmx并得到伪终端主设备的文件描述符。打开这个主设备自动锁定了对应的从设备。

  我们然后调用grantpt来改变从设备的权限。执行如下操作:(a)将从设备的所有权改为有效用户ID;(b)将组所有权改为组tty;(c)将权限改为只允许user-read,user-write和group-write。将组所有权设置为tty并允许group-write权限是因为程序wall(1)和write(1)的组标识符被设置为组tty。调用函数grantpt执行/user/lib/pt_chmod。该程序的用户被设置为root因此它能够修改从设备的所有者和权限。

  函数unlockpt用来清除从设备的内部锁。在打开从设备前我们必须做这件事情。并且我们必须调用ptsname来得到从设备的名称。这个名称的格式是/dev/pts/NNN。文件中接下来的函数是ptys_open,该函数真正被用来打开一个从设备。在SVR4系统中,如果调用者是一个还没有控制终端的会话,open就会分配一个从设备作为控制终端。如果我们不希望函数自动做这件事,可以在调用时指明O_NOCTTY标志。

  在打开从设备后,我们将三个流模块放在从设备的流上。Ptem是伪终端虚拟模块,ldterm是终端行规程模块。这两个模块合在一起象一个真正的终端模块一样工作。ttcompat提供了向老系统如V7、4BSD和Xenix的ioctl调用的兼容性。这是一个可选的模块,但是因为它自动尝试控制台登录和网络登录(见程序12.10的输出),我们将其加到从设备的流中。

  调用这两个函数的结果是得到:伪终端主设备的文件描述符和从设备的文件描述符。19.3.2 4.3+BSD在4.3+BSD系统中我们必须自己来确定第一个可用的伪终端主设备。为达到这个目的,我们从/dev/ptyp0开始并不断尝试直到成功打开一个可用的伪终端主设备或试完所有设备。在打开设备的时候,我们会看到两种可能的错误:EIO指设备已经被使用;ENOENT表示设备不存在。在后一种情况,我们可以停止搜索,因为所有的伪终端设备都在被使用中。一旦我们成功打开一个例如名为/dev/ptyMN的伪终端主设备,那么对应的从设备的名称为/dev/ttyMN。

  程序19.2中的函数ptys_open打开该从设备。我们在该函数中调用chown和chmod,必须意识到调用这两个函数的进程必须有超级用户的权限。如果必须改变权限标志,那么这两个函数必须放在一个set_user_ID的root用户的可执行程序中,这类似于4.3+BSD系统下的grantpt函数。

  在4.3+BSD系统之下打开pty从设备不具有象分配作为控制终端的设备那样的副作用。我们将在下一节探讨如何在4.3+BSD系统下分配控制终端。这个函数尝试16个不同的伪终端主设备:从/dev/ptyp0到/dev/ptyTf。具体有效的pty设备号取决于两个因素:(a)在内核中配置的号码;(b)在/dev目录下的特殊文件号。对于任何程序来说,有效的号码是(a)和(b)中较小的一个。并且,即使(a)和(b)中小的值大于64,许多现有的BSD应用(telnetd,rlogind,等等)会搜索程序19.2中第一个for循环中的pqrs。

______________________________________________________
#include
#include
#include
#include
#include
#include ourhdr.h

  使用ENOENT表示设备不存在。在后一种情况,我们可以停止搜索,因为所有的伪终端设备都在被使用中。一旦我们成功打开一个例如名为/dev/ptyMN的伪终端主设备,那么对应的从设备的名称为/dev/ttyMN。

  程序19.2中的函数ptys_open打开该从设备。我们在该函数中调用chown和chmod,必须意识到调用这两个函数的进程必须有超级用户的权限。如果必须改变权限标志,那么这两个函数必须放在一个set_user_ID的root用户的可执行程序中,这类似于4.3+BSD系统下的grantpt函数。

  在4.3+BSD系统之下打开pty从设备不具有象分配作为控制终端的设备那样的副作用。我们将在下一节探讨如何在4.3+BSD系统下分配控制终端。

  这个函数尝试16个不同的伪终端主设备:从/dev/ptyp0到/dev/ptyTf。具体有效的pty设备号取决于两个因素:(a)在内核中配置的号码;(b)在/dev目录下的特殊文件号。对于任何程序来说,有效的号码是(a)和(b)中较小的一个。并且,即使(a)和(b)中小的值大于64,许多现有的BSD应用(telnetd,rlogind,等等)会搜索程序19.2中第一个for循环中的pqrs。

_________________________________________________________
#include
#include
#include
#include
#include
#include ourhdr.h
int
ptym_open(char *pts_name)
{
int fdm;
char *ptr1, *ptr2;
strcpy(pts_name, /dev/ptyXY);
/* array index: 0123456789 (for references in following code) */
for (ptr1 = pqrstuvwxyzPQRST; *ptr1 != 0; ptr1++) {
pts_name[8] = *ptr1;
for (ptr2 = 0123456789abcdef; *ptr2 != 0; ptr2++) {
pts_name[9] = *ptr2;
/* try to open master */
if ( (fdm = open(pts_name, O_RDWR)) 0) {
if (errno == ENOENT) /* different from EIO */
return(-1); /* out opty devices */
else
continue; /* try nxt pty device */
}pts_name[5] = t;
/* change pty to tty */return(fdm);
/* got it, return fd of master */
}
}
return(-1); /* out of pty devices */
}
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; /* group tty is not in the group file */
/* following two functions dont work unless were root/
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);
}
_______________________________________________________
程序19.2 4.3+BSD系统下的伪终端open函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值