ptg10805159
Section 19.6 Using theptyProgram 739
When we run thetelnetprogram interactively, we wait for the remote host to
prompt for a passwordbefore we type it, but theptyprogram doesn’t know to do this.
This is why it takes a moresophisticated program thanpty,such asexpect, to drive
an interactive program from a script file.
Even runningptyfrom the program in Figure15.18, as we showed earlier,doesn’t
help, because the program in Figure15.18 assumes that each line it writes to the pipe
generates exactly one line on the other pipe. With an interactive program, one line of
input may generate many lines of output. Furthermore, the program in Figure15.18
always sent a line to the coprocess beforereading from it. This strategy won’t work
when we want to read from the coprocess beforesending it anything.
Thereare a few ways to proceed from here to be able to drive an interactive
program from a script.We could add a command language and interpreter topty,but
areasonable command language would probably be ten times larger than thepty
program. Another option is to take a command language and use thepty_fork
function to invoke interactive programs. This is what theexpectprogram does.
We’ll take a different path hereand just provide an option (-d) to allowptyto be
connected to a driver process for its input and output. The standardoutput of the
driver ispty’s standardinput, and vice versa. This is similar to a coprocess, but on ‘‘the
other side’’of pty.The resulting arrangement of processes is almost identical to
Figure19.15, but in the current scenario,ptydoes theforkandexecof the driver
process. Also, instead of two half-duplex pipes, we’ll use a single bidirectional pipe
betweenptyand the driver process.
Figure19.16 shows the source for thedo_driverfunction, which is called by the
mainfunction ofpty(Figure19.11) when the-doption is specified.
#include "apue.h"
void
do_driver(char *driver)
{
pid_t child;
int pipe[2];
/*
*Create a full-duplex pipe to communicate with the driver.
*/
if (fd_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)