[C] stdout and stdin replace by pipes and execve the child
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
[C] stdout and stdin replace by pipes and execve the child
I've managed to create pipe between two processes. I can make parent's stout child's stdin but I cannot send EOF to child.
Here is the code
Edit: looks like rafb.net have forgotten about my code, so I've used wklej.org (but tabs are gone) http://wklej.org/id/ca1f2b983b
My target is to make progress bar for tar application without knowing what is inside the archive file. I only know its name and size. The solution is to read tar archive byte after byte and send read values as stdin to tar. In simply way it can be done by that way:
cat archive.tar | tar xz
By replacing cat with application that writes down how much bytes was read (writing to tar stdin actually blocks until tar unpacks sent data) I can make a progress bar. The reason why I'm not doing it using bash is that I'm writing library that shouldn't depend on shell or create and execute unnecessary script files.
Last edited by chudzielec; 01-26-2008 at 04:09 PM.
not sure if this helps, but this is from man execve (which is the 'back-end' to exec*):
Quote:
...
execve() does not return on success, and the text, data, bss, and stack
of the calling process are overwritten by that of the program loaded.
The program invoked inherits the calling process's PID, and any open
file descriptors that are not set to close on exec. ...
maybe when you exec, it uses actually stdin and not the file descriptor you used dup2 with?
have you tried using named pipes (see man fifo)? the advantage of FIFOs is that any programs on the same host can communicate, that is, without needing a parent-child relationship. i would guess that a call to exec* is destroying this link.
I don’t know why, but your hyperlink is broken, and we can’t see the code.
Usually, to send the child an EOF, you would close the “write-end” of the pipe (and the next time the child tries to read from it, it will get EOF). If you close the “read-end” of the pipe first, then the parent is send SIGPIPE.
Also, the write() function should only block when the pipe is full (on linux a full pipe means 64kB pending for the “read-end”).
Btw nadroj, the exec function should keep the file descriptor open (that is the point).
@nadjor: I'm pretty sure that file descriptor are kept (at least the ones that describes stdin, stdout and stderr). Try to execute my code without exec line or try to replace exec with /bin/echo ( `echo "hello" | echo` prints nothing ). cat application displays what it gets so it looks good. I will check named pipes and report any progress. Thanks for advice.
if( pid == 0 ) {
// I am child
close(fd[1]);
// connect pipe output to stdin
dup2( fd[0], 0 );
close(fd[0]);
// loading image of cat application
execl("/bin/cat", "cat", NULL);
// because of exec* will never gets here and below
// so this is the end of child code
} else {
The line in red must be inserted for your problem to go away. The reason is that the right before the exec, the child has these file descriptors open:
Code:
0 — a copy of the read end of the pipe
1 — the terminal (normal stdout)
2 — stderr (probably also the terminal)
3* — read end of the pipe
4* — write end of the pipe
*I base this on the fact that fd[0] should be 3 and fd[1] should be 4
So when you do the exec, the stdin and stdout work as expected. But when you close the write end of the pipe in the parent, you forget that there is a copy of it still open in the child. So when the child does a read(), then call will block, waiting for the child to write to the pipe (which is never going to happen). So the correct thing to do is to close the write end of the pipe as soon as you get into the child process. Basically, the reading the read end of a pipe will return EOF when and only when all copies of the write end of the pipe are closed. In your case, you had left one copy open.
As for the line in blue, it is not strictly necessary, but it is good style to close a file descriptor you don’t need. You can also insert a similar line after the other call to dup2 (on line 33). In a real-world situation, you would check that the return values of each of those system calls (including pipe(), fork(), and dup2()) is not -1 before continuing.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.