I need to create a function that, among other things, spawns a child process.
I’d like to pass to this function an optional list of file discriptors so that, depending on the user needs, the child process input/output can be redirected.
I have seen dozens of people talking about how to do this using dup2 somewhat like this:
if( pid < 0 ) // error forking.
{
//...
}
else if( pid != 0 ) // Parent process.
{
ret = waitpid( pid, &status, 0 );
return WEXITSTATUS( status );
}
else // Child process.
{
dup2( fd, STDIN_FILENO ); // Clone passed file discriptor.
close( fd ); // Close the passed one, since we have already cloned.
execvp( arglist[ 0 ], arglist );
}
Alright. All of this is in the Internet.
My question now is, how (or what is the best way) to redirect to /dev/null?
Should I force the user to open( /dev/null) and pass it as fd or is there any better way?
EDIT:
This is not as pretty as I wanted, but I could not find any better way, so I ended up passing an array of file names to wherever a user could want to redirect, respectively, STDIN, STDOUT and STDERR:
static int do_exec( arglist_t arglist, const char *fio[ 3 ] )
{
DEBUG__( OSU_DEBUG_LEVEL_1, "fio = %p\n", fio );
if ( fio )
{
if ( fio[ STDIN_FILENO ] )
{
int fd = open( fio[ STDIN_FILENO ], O_RDONLY );
if ( -1 < fd )
{
dup2( fd, STDIN_FILENO );
close( fd );
}
}
if ( fio[ STDOUT_FILENO ] )
{
int fd = open( fio[ STDOUT_FILENO ], O_WRONLY | O_CREAT | O_APPEND );
if ( -1 < fd )
{
dup2( fd, STDOUT_FILENO );
close( fd );
}
}
if ( fio[ STDERR_FILENO ] )
{
int fd = open( fio[ STDERR_FILENO ], O_WRONLY | O_CREAT | O_APPEND );
if ( -1 < fd )
{
dup2( fd, STDERR_FILENO );
close( fd );
}
}
}
return execvp( arglist[ 0 ], arglist );
}
- I haven’t yet fully tested it, so it may have some bugs.
Really thanks to @Zack and @gbulmer.
You could have it as a convention of your API that passing in
-1for the fd means to use/dev/null, and do(Psst: Every time you put spaces on the inside of your parentheses, God kills a kitten.)