execv 和 fork:通知父子进程执行文件失败

execv and fork: inform parent that child failed to execute the file

主进程如何知道子进程执行文件失败(例如没有那个文件或目录)?例如,在下面的代码中,我们如何让 运行() 变成 return 不是 0 的值?谢谢!

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

enum ErrorType { noError, immediateFailure, returnFailure, forkFailure };

using namespace std;

int run(void)
{
    int error = noError;
    //char proc[] = "/bin/uname";
    char proc[] = "/usr/bin/Idontexist";
    char *const params[] = {proc, NULL};

    pid_t pid = fork();

    printf("pid = %d\n",pid);

    if (pid == 0)
    {
        if ( execv(proc,params)==-1 )
        {
            error = immediateFailure;
        }
        printf("child: error = %d\n",error);
    }
    else if (pid > 0)
    {
        /*  This is the parent process
         *  incase you want to do something
         *  like wait for the child process to finish
         */
        int waitError;
        waitpid(pid, &waitError, 0);

        if ( waitError )
            error = returnFailure;

        printf("parent: error = %d, waitError = %d\n",error,waitError);
    }
    else
    {
        error = forkFailure;
    }

    return error;
}

int main(void)
{
    printf("run() = %d\n",run());

    return 0;
}

输出:

pid = 4286
pid = 0
child: error = 1
run() = 1
parent: error = 0, waitError = 0
run() = 0

问题是execv失败后的错误处理。 child 将 error 设置为 immediateFailure,将 return 设置为 main。然后 main 打印错误号,然后 returns 0。但是0表示成功,所以parent进程认为child成功了。

解决方法是return来自main的错误号,或者在child代码中调用exit,例如

if (pid == 0)
{
    execv(proc,params);
    error = immediateFailure;
    printf("child: error = %d\n",error);
    exit( error );
}

请注意,您不需要检查 execv 的 return 值,因为 execv 如果成功则不会 return。它只会 return 如果失败,并且总是 return -1.

您需要 return 来自 main 的错误代码,或 exit() 的值。现在,在所有情况下,您都从 main returning 0,这将是父级从 waitpid.[=26= 收到的子级的退出代码]

最好的解决方法是在子进程中添加_exit(error)

printf("child: error = %d\n",error);
_exit(error);

在任何情况下都使用整数常量而不是随机枚举常量枚举。 1 和 2 是来自许多 unix 命令的常见 return 值,其中 1 表示命令不成功(例如 grep 未找到任何匹配项),2+ 表示命令确实失败(错误的论点等)`.

bashzsh 和其他 shell 使用 127 作为退出代码来表示 command not found / not 运行nable;因此建议这样做:

#define COMMAND_NOT_RUNNABLE 127

/* ... */

execv(proc, params);  // exec never returns if successful.
perror(proc);
_exit(COMMAND_NOT_RUNNABLE);

在子进程中使用 _exit 的原因是它不会刷新 stdio 缓冲区(它也存在于父进程中)并且它不会 运行 atexit 个钩子。 (感谢Andrew Henle

除了提议的 exit(error); 之外,您还应该为 waitpid 提供具体选项。在我将调用更改为 waitpid(pid, &waitError, WUNTRACED | WCONTINUED);

之前,您的代码对我不起作用

在我的例子中 exit(EXIT_FAILURE) 不会导致子进程的 return 到 waitpid() EXIT_FAILURE 状态,总是 0。我的解决方案是abort()子进程如果execv()/execve()执行失败