select returns 在 fdset 中使用标准输入和管道时的 EBADF
select returns EBADF when using stdin and pipes in the fdset
在这个程序中,我试图设置一些管道来 dup2 子进程的“stdin、stdout、stderr”,而不是通过父进程管理的管道发送和接收数据;但是,我的设置似乎有问题,因为 select 返回 -1,错误号为 9(EBADF,正确吗?)。我不确定这是怎么回事,除非我以某种方式关闭了太多/没有在子端或父端关闭正确的 fds。跟我把管道放到全局范围有关系吗?
/* GLOBALS */
int mode; // i for input mode, c for command mode, i/o for input/output mode
int cpid; // child's process id
int fderr[2]; // stderr pipe
int fdsin[2]; // stdin pipe
int fdout[2]; // stdout pipe
int main(int argc, char *argv[]){
// pipe 3
pipe(fderr);
pipe(fdsin);
pipe(fdout);
// fork
if ((cpid = fork()) == 0) {
// dupe 3 for the child
dup2(fderr[1], 2);
dup2(fdout[1], 1);
dup2(fdsin[0], 0);
// close the 6 pipes
close(fderr[0]);
close(fderr[1]);
close(fdout[0]);
close(fdout[1]);
close(fdsin[0]);
close(fdsin[1]);
// execute
execvp(argv[1], argv + 1);
exit(0);
}
else {
// close unused pipes
close(fderr[1]);
close(fdout[1]);
close(fdsin[0]);
// setup fdset and mode
mode = 'c';
fd_set set;
// setup capturing of child process termination
int code;
int status;
// handle pipe reads and writes
while (1) {
switch ( mode ) {
// clear previous fdset
FD_ZERO(&set);
// always add stderr
FD_SET(fderr[0], &set);
// input and command only care about stdin
case 'i':
case 'c':
FD_SET(0, &set);
break;
// input / output cares about stdin and stdout
case 'o':
FD_SET(fdout[0], &set);
FD_SET(0, &set);
break;
}
// select
if (select(FD_SETSIZE, &set, NULL, NULL, NULL) < 0)
{
int err = errno;
fprintf(stderr, "%d\n", err);
exit(EXIT_FAILURE);
}
// Rest of code currently unreachable...
原代码中的switch语句在不可达的地方调用了FD_ZERO和FD_SET。对 FD_ZERO 和 FD_SET 的调用应放在 switch 语句之前。
// clear previous fdset
FD_ZERO(&set);
// always add stderr
FD_SET(fderr[0], &set);
switch ( mode ) {
// input and command only care about stdin
case 'i':
case 'c':
FD_SET(0, &set);
break;
// input / output cares about stdin and stdout
case 'o':
FD_SET(fdout[0], &set);
FD_SET(0, &set);
break;
}
在这个程序中,我试图设置一些管道来 dup2 子进程的“stdin、stdout、stderr”,而不是通过父进程管理的管道发送和接收数据;但是,我的设置似乎有问题,因为 select 返回 -1,错误号为 9(EBADF,正确吗?)。我不确定这是怎么回事,除非我以某种方式关闭了太多/没有在子端或父端关闭正确的 fds。跟我把管道放到全局范围有关系吗?
/* GLOBALS */
int mode; // i for input mode, c for command mode, i/o for input/output mode
int cpid; // child's process id
int fderr[2]; // stderr pipe
int fdsin[2]; // stdin pipe
int fdout[2]; // stdout pipe
int main(int argc, char *argv[]){
// pipe 3
pipe(fderr);
pipe(fdsin);
pipe(fdout);
// fork
if ((cpid = fork()) == 0) {
// dupe 3 for the child
dup2(fderr[1], 2);
dup2(fdout[1], 1);
dup2(fdsin[0], 0);
// close the 6 pipes
close(fderr[0]);
close(fderr[1]);
close(fdout[0]);
close(fdout[1]);
close(fdsin[0]);
close(fdsin[1]);
// execute
execvp(argv[1], argv + 1);
exit(0);
}
else {
// close unused pipes
close(fderr[1]);
close(fdout[1]);
close(fdsin[0]);
// setup fdset and mode
mode = 'c';
fd_set set;
// setup capturing of child process termination
int code;
int status;
// handle pipe reads and writes
while (1) {
switch ( mode ) {
// clear previous fdset
FD_ZERO(&set);
// always add stderr
FD_SET(fderr[0], &set);
// input and command only care about stdin
case 'i':
case 'c':
FD_SET(0, &set);
break;
// input / output cares about stdin and stdout
case 'o':
FD_SET(fdout[0], &set);
FD_SET(0, &set);
break;
}
// select
if (select(FD_SETSIZE, &set, NULL, NULL, NULL) < 0)
{
int err = errno;
fprintf(stderr, "%d\n", err);
exit(EXIT_FAILURE);
}
// Rest of code currently unreachable...
原代码中的switch语句在不可达的地方调用了FD_ZERO和FD_SET。对 FD_ZERO 和 FD_SET 的调用应放在 switch 语句之前。
// clear previous fdset
FD_ZERO(&set);
// always add stderr
FD_SET(fderr[0], &set);
switch ( mode ) {
// input and command only care about stdin
case 'i':
case 'c':
FD_SET(0, &set);
break;
// input / output cares about stdin and stdout
case 'o':
FD_SET(fdout[0], &set);
FD_SET(0, &set);
break;
}