子进程无法从创建的伪终端读取

问题描述:

我正在尝试编写一个应用程序,它可以通过使用伪终端以密码登录到SSH。但是,如果我将()写入主设备,那么数据不会在从设备中出现。这里有一个简单的测试用例:子进程无法从创建的伪终端读取

#include <sys/wait.h> 
#include <sys/types.h> 
#include <stdio.h> 
#include <unistd.h> 
#ifdef __linux__ 
    #include <pty.h> 
#else 
    #include <util.h> 
#endif 

int 
main() { 
    int master; 
    pid_t pid = forkpty(&master, NULL, NULL, NULL); 
    if (pid == 0) { 
     int ch; 
     read(0, &ch, 1); 
     _exit(1); 
    } else { 
     printf("Press Enter to send a byte.\n"); 
     getchar(); 
     write(master, "1", 1); 
     printf("Done. Waiting for process to exit...\n"); 
     waitpid(pid, NULL, 0); 
     return 0; 
    } 
} 

该应用程序将首先输出“按Enter键发送一个字节”。按Enter后,我期望子进程的read()返回。但是read()似乎无限地阻塞,即使master的write()成功了,所以master在waitpid()上永远等待。这是怎么回事?

+0

我不确定你在用什么,但是我会用'expect'这样的东西。它在大多数发行版上都可用。 http://expect.nist.gov/ – 2010-02-02 19:02:52

+0

我正在编写的应用程序将分发给可能没有“期望”或可能不想安装它的用户。除此之外,我还想知道如何做伪终端,以防将来需要它们用于其他任何事情。 – Hongli 2010-02-02 19:08:34

+0

试试这个:写(master,“1 \ n”,2); – sambowry 2010-02-02 19:25:36

问题是你没有修改PTY的行纪律。默认的行规则是面向行的,所以在读取换行符之前,不会有任何输入发送到从属进程。 (您可以通过发送一个“\ n”给从机而不是“1”来看到这一点)。您可以在子进程中通过调用tcgetattr,cfmakerawtcsetattr来运行PTY RAW模式,如下所示:

if (pid == 0) { 
     int ch; 
     struct termios t; 
     tcgetattr(0, &t); 
     cfmakeraw(&t); 
     tcsetattr(0, TCSANOW, &t); 
     read(0, &ch, 1); 
     _exit(1); 
    } else { 

这似乎适用于我。

this blog post的示例代码应该可能有帮助。作者给出了一个可用的spawn (char *argv[]);函数的更新(与您的原始问题非常相似)。