我做常规的事情:

  • 叉()
  • execvp(cmd, ) 在子

  • 如果 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/

    10-16 16:30