forkpty with streams
I've got the 2.4 kernel, and I'm trying to use the forkpty() system call with the standard I/O stream functions. The calls to forkpty() and fdopen() and fprintf() all return successfully, but the data never seems to get to the child process. In this simplified example, I am trying to open a shell in a pseudo terminal and then send it the string "exit\n" and then wait for it to die. But the shell apparently never sees the "exit\n", and the parent waits forever.
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
int fd;
pid_t pid;
pid = forkpty (&fd, 0, 0, 0);
if (pid == 0) {
execlp ("sh", "sh", (void *)0);
_exit (1);
} else if (pid == -1) {
return 1;
} else {
FILE *F;
F = fdopen (fd, "w");
fprintf (F, "exit\n");
fflush (F);
wait (0);
}
return 0;
}Quoted 7 lines · Andrew Barton
I've got the 2.4 kernel, and I'm trying to use the
forkpty()system call with the standard I/O stream functions. The calls toforkpty()andfdopen()andfprintf()all return successfully, but the data never seems to get to the child process. In this simplified example, I am trying to open a shell in a pseudo terminal and then send it the string "exit\n" and then wait for it to die. But the shell apparently never sees the "exit\n", and the parent waits forever.
forkpty() is not a system call. This is more likely to be a glibc issue or a problem with your code. You might consider running your test under 'strace' to see what is happening under the covers.
-Doug
Quoted 1 line · Andrew Barton
I've got the 2.4 kernel, and I'm trying to use the
forkpty()system call
forkpty is not a system call
Quoted 4 lines
with the standard I/O stream functions. The calls to
forkpty()andfdopen()andfprintf()all return successfully, but the data never seems to get to the child process.
Quoted 9 lines
pid = forkpty (&fd, 0, 0, 0);
if (pid == 0) {
execlp ("sh", "sh", (void *)0);
} else {
F = fdopen (fd, "w");
fprintf (F, "exit\n");
fflush (F);
wait (0);
}Let me see. Your sh gets input from this pseudotty and sends its output there again. But you never read that filedescriptor. No doubt things will improve if you let the parent read from fd.
Andries
Quoted 20 lines · Andries Brouwer
Quoted 1 line · Andrew Barton
I've got the 2.4 kernel, and I'm trying to use the
forkpty()system callforkpty is not a system call
Quoted 4 lines
with the standard I/O stream functions. The calls to
forkpty()andfdopen()andfprintf()all return successfully, but the data never seems to get to the child process.Quoted 9 lines
pid = forkpty (&fd, 0, 0, 0); if (pid == 0) { execlp ("sh", "sh", (void *)0); } else { F = fdopen (fd, "w"); fprintf (F, "exit\n"); fflush (F); wait (0); }
Quoted 5 lines
Let me see. Your sh gets input from this pseudotty and sends its output there again. But you never read that filedescriptor. No doubt things will improve if you let the parent read from fd.
Andries
Before I tried using streams, I just used write() to communicate with the ptty, but I had the same problem. I found that if I put a read() call before and after the write(), it worked. But why? Is this some kind of I/O voodoo? How does the reading affect the writing?
You mentioned that things would improve if I let the parent read from fd. Will this work using streams? I have tried opening fd in "r+" mode, but in that case I end up reading my own data. Do I need to lay an fflush() somewhere inbetween? What is it exactly that causes the data to be sent to the parent?
I appreciate the help.
On Fri, Jul 25, 2003 at 10:59:04AM +0000, Andrew Barton wrote:
...
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
with the standard I/O stream functions. The calls to
forkpty()andfdopen()andfprintf()all return successfully, but the data never seems to get to the child process.pid = forkpty (&fd, 0, 0, 0); if (pid == 0) { execlp ("sh", "sh", (void *)0); } else { F = fdopen (fd, "w"); fprintf (F, "exit\n"); fflush (F); wait (0); }
...
Quoted 4 lines
Before I tried using streams, I just used
write()to communicate with the ptty, but I had the same problem. I found that if I put aread()call before and after thewrite(), it worked. But why? Is this some kind of I/O voodoo? How does the reading affect the writing?
PTY file-handle is full-duplex bi-directional thing, and sometimes it may need reading, or you get unwanted deadlocks.
Quoted 5 lines
You mentioned that things would improve if I let the parent read from fd. Will this work using streams? I have tried opening fd in "r+" mode, but in that case I end up reading my own data. Do I need to lay an
fflush()somewhere inbetween? What is it exactly that causes the data to be sent to the parent?
dup() helps you to have two fd:s, fdopen() for both, one with "w",
other "r". Things should not need that dup() actually.
Also fcntl() the fd's to be non-blocking.
Actually I am always nervous with stdio streams in places where I want to use non-blocking file handles, and carefull read()ing and write()ng along with select()s to handle non-stagnation of this type of communications.
Quoted 1 line
I appreciate the help.
/Matti Aarnio
Quoted 9 lines · Matti Aarnio
dup()helps you to have two fd:s,fdopen()for both, one with "w",
other "r". Things should not need thatdup()actually.
Alsofcntl()the fd's to be non-blocking.Actually I am always nervous with stdio streams in places where I want to use non-blocking file handles, and carefull read()ing and write()ng along with select()s to handle non-stagnation of this type of communications.
In my program, the standard input is filtered through a lex scanner whose output file is the pty. So it does indeed need to be a stream. Since I'm using flex, I won't have much control over the writing process. When will it be necessary to read from the pty, to prevent a deadlock? After each character the user types?
I might use SIGIO to read from the pty, but I have the 2.4 kernel that doesn't support SIGIO on pipes and FIFOs. I assume ptys have the same problem.
Quoted 19 lines · Andrew Barton
Quoted 18 lines · Andries Brouwer
Quoted 11 lines · Andrew Barton
the data never seems to get to the child process.
pid = forkpty (&fd, 0, 0, 0); if (pid == 0) { execlp ("sh", "sh", (void *)0); } else { F = fdopen (fd, "w"); fprintf (F, "exit\n"); fflush (F); wait (0); }Let me see. Your sh gets input from this pseudotty and sends its output there again. But you never read that filedescriptor. No doubt things will improve if you let the parent read from fd.
Quoted 6 lines
Quoted 1 line
Andries
Before I tried using streams, I just used
write()to communicate with the ptty, but I had the same problem. I found that if I put aread()call before and after thewrite(), it worked. But why? Is this some kind of I/O voodoo? How does the reading affect the writing?
You test with bash, which is a complicated program with many subtleties related to job control and terminal control. Things will be easier with ash instead of sh.
But to answer your concrete question: bash does
ioctl(0, TCSETSW, foo); which is the same as POSIX tcsetattr(0, TCSADRAIN, foo);
which does some setting, but first waits for the output buffer to drain. It will never drain, unless the other side of the pty does some reading.
Andries