I'd use popen() (++waqas).
But sometimes you need reading and writing...
Seems like nobody does things the hard way any more.
(Assuming a Unix/Linux/Mac environment, or perhaps Windows with a POSIX compatibility layer...)
enum PIPE_FILE_DESCRIPTERS
{
READ_FD = 0,
WRITE_FD = 1
};
enum CONSTANTS
{
BUFFER_SIZE = 100
};
int
main()
{
int parentToChild[2];
int childToParent[2];
pid_t pid;
string dataReadFromChild;
char buffer[ BUFFER_SIZE + 1 ];
ssize_t readResult;
int status;
ASSERT_IS(0, pipe(parentToChild));
ASSERT_IS(0, pipe(childToParent));
switch ( pid = fork() )
{
case -1:
FAIL( "Fork failed" );
exit(-1);
case 0: /* Child */
ASSERT_NOT(-1, dup2( parentToChild[ READ_FD ], STDIN_FILENO ) );
ASSERT_NOT(-1, dup2( childToParent[ WRITE_FD ], STDOUT_FILENO ) );
ASSERT_NOT(-1, dup2( childToParent[ WRITE_FD ], STDERR_FILENO ) );
ASSERT_IS( 0, close( parentToChild [ WRITE_FD ] ) );
ASSERT_IS( 0, close( childToParent [ READ_FD ] ) );
/* file, arg0, arg1, arg2 */
execlp( "ls", "ls", "-al", "--color" );
FAIL( "This line should never be reached!!!" );
exit(-1);
default: /* Parent */
cout << "Child " << pid << " process running..." << endl;
ASSERT_IS( 0, close( parentToChild [ READ_FD ] ) );
ASSERT_IS( 0, close( childToParent [ WRITE_FD ] ) );
while ( true )
{
switch ( readResult = read( childToParent[ READ_FD ],
buffer, BUFFER_SIZE ) )
{
case 0: /* End-of-File, or non-blocking read. */
cout << "End of file reached..." << endl
<< "Data received was ("
<< dataReadFromChild.size() << "):" << endl
<< dataReadFromChild << endl;
ASSERT_IS( pid, waitpid( pid, & status, 0 ) );
cout << endl
<< "Child exit staus is: " << WEXITSTATUS(status) << endl
<< endl;
exit(0);
case -1:
if ( (errno == EINTR) || (errno == EAGAIN) )
{
errno = 0;
break;
}
else
{
FAIL( "read() failed" );
exit(-1);
}
default:
dataReadFromChild . append( buffer, readResult );
break;
}
} /* while ( true ) */
} /* switch ( pid = fork() )*/
}
You also might want to play around with select() and non-blocking reads.
fd_set readfds;
struct timeval timeout;
timeout.tv_sec = 0; /* seconds */
timeout.tv_usec = 1000; /* microseconds */
FD_ZERO(readfds);
FD_SET( childToParent[ READ_FD ] );
switch ( select ( 1 + childToParent[ READ_FD ],
readfds, (fd_set*)NULL, (fd_set*)NULL, & timeout ) )
{
case 0: /* Timeout expired */
break;
case -1:
if ( (errno == EINTR) || (errno == EAGAIN) )
{
errno = 0;
break;
}
else
{
FAIL( "Select() Failed" );
exit(-1);
}
case 1: /* We have input */
readResult = read( childToParent[ READ_FD ], buffer, BUFFER_SIZE );
// However you want to handle it...
break;
default:
FAIL( "How did we see input on more than one file descriptor?" );
exit(-1);
}