我需要创建一个函数,除其他外,它会生成一个子进程。 我想向该函数传递一个可选的文件描述符列表,以便根据用户需要重定向子进程输入/输出。
我见过很多人在讨论如何使用dup2
这样做:
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 );
}
好的。所有这一切都在互联网上。
我现在的问题是,如何(或最好的方式)重定向到/dev/null
?
我应该强迫用户open( /dev/null)
并将其作为fd
传递,还是有更好的方式?
编辑:
这不是我想要的那么漂亮,但我找不到更好的方法,所以我最终将一个文件名数组传递给用户想要重定向的地方,分别是STDIN,STDOUT和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 );
}
非常感谢@Zack和@gbulmer。
答案 0 :(得分:4)
您可以将其作为API的惯例,传递-1
以获取fd意味着使用/dev/null
,并执行
// ... same as you have ...
else // Child process
{
if (stdin_fd == -1)
stdin_fd = open("/dev/null", O_RDONLY);
if (stdin_fd == -1)
_exit(127);
dup2(stdin_fd, STDIN_FILENO);
close(stdin_fd);
// similarly for stdout and stderr
execvp(arglist[0], arglist);
_exit(127);
}
(诗篇:每当你在括号内放置空格时,上帝会杀死一只小猫。)
答案 1 :(得分:1)
子进程需要知道哪个fd用作dup2的oldfd和用于复制到f2的fd。
例如,为什么fd会被复制到STDIN_FILENO上?
孩子需要打开fd的信息,并且fd应该重复上传。
为了概括,为了涵盖文件名而不仅仅是fd的处理情况,你可以说“/ dev / null”,因为它是一个真正的文件名。
所以只需要一个struct { int oldfd; char* filename; int newfd; }
结构列表,并且作业是常规的,而/ dev / null不是特例。当oldfd为-1时,在newfd上打开文件名而不是dup2'ing到它上面。