(7)pty程序的do_driver函数
#include "apue.h"
void do_driver(char *driver)
{
pid_t child;
int pipe[2];
/*
* Create a stream pipe to communicate with the driver.
*/
if (s_pipe(pipe) < 0)
err_sys("can't create stream pipe");
if ((child = fork()) < 0) {
err_sys("fork error");
} else if (child == 0) { /* child */
close(pipe[1]);
/* stdin for driver */
if (dup2(pipe[0], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
/* stdout for driver */
if (dup2(pipe[0], STDOUT_FILENO) != STDOUT_FILENO)
err_sys("dup2 error to stdout");
if (pipe[0] != STDIN_FILENO && pipe[0] != STDOUT_FILENO)
close(pipe[0]);
/* leave stderr for driver alone */
execlp(driver, driver, (char *)0);
err_sys("execlp error for: %s", driver);
}
close(pipe[0]); /* parent */
if (dup2(pipe[1], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
if (dup2(pipe[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys("dup2 error to stdout");
if (pipe[1] != STDIN_FILENO && pipe[1] != STDOUT_FILENO)
close(pipe[1]);
/*
* Parent returns, but with stdin and stdout connected
* to the driver.
*/
}
通过我们自己写的被pty调用的driver程序,我们可以以任何需要的方式来驱动交互程序。即使它的标准输入和标准输出连接到pty上面,driver进程也还是可以通过读写/dev/tty来和用户进行交互。这个方案还是不如expect程序通用,但是它只通过不到50行的代码,就为pty程序添加了一个有用的选项。
译者注
原文参考
7、高级特性
伪终端还有一些额外的特性,我们这里简单对它们列出。这些特性在Sun Microsystems和BSD的pty的man手册第4节中描述了。
包模式
包模式可以让PTY master获知PTY slave的状态变化。在Solaris上面,这个模式通过向PTY master端推送pckt的STREAMS模块来实现。我们在前面第2节中的"Solaris下面伪终端的结构"图中,对其进行了展示。在FreeBSD, Linux, 和 Mac OS X中,这个模式通过ioctl的TIOCPKT命令来激活。
Solaris和其他平台的包模式细节有一些不同。Solaris下面,由于pckt模块将特定的事件转化成非数据的STREAMS消息,所以从PTY master读取的进程需要调用getmsg来获得来自stream头的消息。在其他平台下面,每次从PTY master读取都会返回一个状态字节接着一个可选的数据。
除去这些实现上面的细节,包模式的目的就是在PTY slave上面的行规则模块发生如下事件的时候,通知读取PTY master的进程:当读取队列被flushed,当写队列被flushed,当输出停止的时候(例如Control-S导致其停止),当输出重新启动的时候,当XON/XOFF流控制在被禁止之后再次被使能的时候,在XON/XOFF流控制在被使能之后又被禁止的时候。这些事件,在诸如rlogin客户和rlogind服务进程中可能会被用到。
网友评论