Perl, how do I create a pipe to my exec'd child?

c, perl, pipe, unix

Solution

Your pipe file descriptors are set FD_CLOEXEC, and so are closed upon exec().

Perl's `$^F` controls this behavior. Try something like this, before you call IO::Pipe->new:

$^F = 10;  # Assumes we don't already have a zillion FDs open

Alternatively, you can with Fcntl clear the FD_CLOEXEC flag yourself after creating the pipe.

Problem

I am trying to pass data from my perl script to my c program using a pipe (uni-directional). I need to find a way to to do this without messing with the child programs STDIN or STDOUT, so I try creating a new handle and passing the fd. I create 2 IO::Handles and create a pipe. I write to one end of the pipe and attempt to pass the File descriptor of the other end of the pipe to my child program that is being execed. I pass the file descriptor by setting an ENV variable. Why does this not work? (It does not print out 'hello world'). As far as I know, file descriptors and pipes are inherited by the child when exec'd. Perl script: ``` #!/opt/local/bin/perl use IO::Pipe; use IO::Handle; my $reader = IO::Handle->new(); my $writer = IO::Handle->new(); $reader->autoflush(1); $writer->autoflush(1); my $pipe = IO::Pipe->new($reader, $writer); print $writer "hello world"; my $fh = $reader->fileno; $ENV{'MY_FD'} = $fh; exec('./child') or print "error opening app\n"; # No more code after this since exec replaces the current process ``` C Program, app.c (Compiled with `gcc app.c -o child`): ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char ** argv) { int fd = atoi(getenv("MY_FD")); char buf[12]; read(fd, buf, 11); buf[11] = '\0'; printf("fd: %d\n", fd); printf("message: %s\n", buf); } ``` Output: ``` fd: 3 message: ``` The message is never passed through the pipe to the C program. Any suggestions?

Original source

Related problems