我做常规的事情:
如果 execvp 由于未找到 cmd 而失败,我如何在父进程中注意到此错误?
最佳答案
为此,众所周知的 self-pipe trick 可以是 adapted。
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <sysexits.h>
#include <unistd.h>
int main(int argc, char **argv) {
int pipefds[2];
int count, err;
pid_t child;
if (pipe(pipefds)) {
perror("pipe");
return EX_OSERR;
}
if (fcntl(pipefds[1], F_SETFD, fcntl(pipefds[1], F_GETFD) | FD_CLOEXEC)) {
perror("fcntl");
return EX_OSERR;
}
switch (child = fork()) {
case -1:
perror("fork");
return EX_OSERR;
case 0:
close(pipefds[0]);
execvp(argv[1], argv + 1);
write(pipefds[1], &errno, sizeof(int));
_exit(0);
default:
close(pipefds[1]);
while ((count = read(pipefds[0], &err, sizeof(errno))) == -1)
if (errno != EAGAIN && errno != EINTR) break;
if (count) {
fprintf(stderr, "child's execvp: %s\n", strerror(err));
return EX_UNAVAILABLE;
}
close(pipefds[0]);
puts("waiting for child...");
while (waitpid(child, &err, 0) == -1)
if (errno != EINTR) {
perror("waitpid");
return EX_SOFTWARE;
}
if (WIFEXITED(err))
printf("child exited with %d\n", WEXITSTATUS(err));
else if (WIFSIGNALED(err))
printf("child killed by %d\n", WTERMSIG(err));
}
return err;
}
这是一个完整的程序。
$ ./a.out foo
child 的 execvp:没有那个文件或目录
$ (sleep 1 && killall -QUIT sleep &); ./a.out sleep 60
等 child ...
child 被 3 人杀害
$ ./a.out 真
等 child ...
child 以 0 退出
这是如何工作的:
创建一个管道,并使写入端点为
CLOEXEC
:当成功执行 exec
时,它会自动关闭。在 child 中,尝试
exec
。如果成功,我们将不再拥有控制权,但管道已关闭。如果失败,则将失败代码写入管道并退出。在父级中,尝试从另一个管道端点读取。如果
read
返回零,则管道已关闭并且子进程必须成功获得 exec
。如果read
返回数据,就是我们 child 写的失败代码。关于c++ - fork() 之后如何处理 execvp(...) 错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1584956/