我做常规的事情:
如果execvp因找不到cmd而失败,如何在父进程中注意到此错误?
著名的自管技巧可以适用于这一目的。
#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 孩子的execvp:没有此类文件或目录 $(sleep 1 && killall -QUIT sleep&); 外出睡眠60 等待孩子... 被3杀死的孩子 $ ./a.out true 等待孩子... 孩子以0退出
工作原理:
创建一个管道,并创建write端点CLOEXEC:exec成功执行an时,它将自动关闭。
CLOEXEC
exec
在孩子中,尝试exec。如果成功,我们将不再具有控制权,但管道已关闭。如果失败,则将失败代码写入管道并退出。
在父级中,尝试从另一个管道端点读取。如果read返回零,则说明管道已关闭并且子级必须exec成功。如果read返回数据,那是我们孩子编写的失败代码。
read