views:

74

answers:

1

Hello,

I am creating a child-parent fork() to be able to communicate with a shell(/bin/sh) from the parent through a pipe.

The problem is: In a parent I set a select() on a child output, but it unblocks only when the process is finished! So when I run say ps it's okay. but when I run /bin/sh it does not output until shell exits. But I want to read it's output!

for(;;) {
select(PARENT_READ+1,&sh,NULL,NULL,NULL); // This unblocks only when shell exits!
if (FD_ISSET(PARENT_READ,&sh)) {
   while (n = read (PARENT_READ, &buf,30)) {
       buf[30]='\0';
       printf("C: %s\n",buf);
   };
};
}

The answer is somewhere in the field of disabling buffering of pipes?

+4  A: 

A lot of programs change their behavior depending on whether or not they think they're talking to a terminal (tty), and the shell definitely does this this. Also, the default C streams stdout and stderr are probably unbuffered if stdout is a tty, and fully buffered otherwise - that means that they don't flush until the internal buffer is full, the program explicitly flushes them, or the program ends.

To work around this problem, you have to make your program pretend to be a terminal. To do this, you can use your system's pseudo-terminal APIs (try man 7 pty). The end result is a pair of file descriptors that sort-of work like a pipe.

Also, as an aside, when select unblocks, you should read exactly once from the triggered file descriptor. If you read more than once, which is possible with the loop you've got there, you risk blocking again on subsequent reads, unless you've got your FD in non-blocking mode.

However, I have to ask: why do you need to interact with the shell in this way? Is it possible to, say, just run a shell script, or use "/bin/sh -c your_command_here" instead? There are relatively few programs that actually need a real terminal to work correctly - the main ones are programs that prompt for a password, like ssh, su or sudo.

Doug
1) I tried filling up the buffer by cat'ing big files, but nothing happens! 2) I am developing a rsh-like remote shell though a special hardware, but so I am not able to use sockets(its a complicated situation, I know). 3) Don't worry about the loop -- I need to read at least something!
JAmes
Ah, OK, if you're doing something like rsh, then you should use the pseudo-terminal approach - that's how rsh and ssh work internally.
Doug