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;
}
Andrew Barton <[email protected]> writes:
> 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.
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
On Thu, Jul 24, 2003 at 11:28:36PM +0000, Andrew Barton wrote:
> I've got the 2.4 kernel, and I'm trying to use the forkpty() system call
forkpty is not a 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.
> 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
On Fri, 2003-07-25 at 15:27, Andries Brouwer wrote:
> On Thu, Jul 24, 2003 at 11:28:36PM +0000, Andrew Barton wrote:
>
> > I've got the 2.4 kernel, and I'm trying to use the forkpty() system call
>
> forkpty is not a 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.
>
> > 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
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:
...
> > > 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.
> >
> > > 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);
> > > }
...
> 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?
PTY file-handle is full-duplex bi-directional thing, and sometimes
it may need reading, or you get unwanted deadlocks.
> 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.
> I appreciate the help.
/Matti Aarnio
On Fri, 2003-07-25 at 18:46, Matti Aarnio wrote:
> 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.
>
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.
On Fri, Jul 25, 2003 at 10:59:04AM +0000, Andrew Barton wrote:
> On Fri, 2003-07-25 at 15:27, Andries Brouwer wrote:
> > On Thu, Jul 24, 2003 at 11:28:36PM +0000, Andrew Barton wrote:
> > > 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.
> >
> > 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 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