簡體   English   中英

waitpid / wexitstatus返回0而不是正確的返回碼

[英]waitpid/wexitstatus returning 0 instead of correct return code

我有下面的幫助函數,用於執行命令並在posix系統上獲取返回值。 我曾經使用過popen ,但是如果它運行並且在popen / pclose有機會完成其工作之前退出,則無法獲得具有popen的應用程序的返回代碼。

以下輔助函數創建進程fork,使用execvp運行所需的外部進程,然后父進程使用waitpid獲取返回代碼。 我看到奇怪的情況,它拒絕運行。

當使用wait = true調用時,無論如何, waitpid都應該返回應用程序的退出代碼。 但是,我看到stdout輸出指定返回代碼應該是非零,但返回代碼為零。 在常規shell中測試外部進程,然后echo $? 返回非零,因此外部進程沒有返回正確的代碼也不是問題。 如果有任何幫助,正在運行的外部進程是mount(8) (是的,我知道我可以使用mount(2)但是除了這一點之外)。

我提前為代碼轉儲道歉。 大多數是調試/日志記錄:

inline int ForkAndRun(const std::string &command, const std::vector<std::string> &args, bool wait = false, std::string *output = NULL)
{
    std::string debug;

    std::vector<char*> argv;
    for(size_t i = 0; i < args.size(); ++i)
    {
        argv.push_back(const_cast<char*>(args[i].c_str()));
        debug += "\"";
        debug += args[i];
        debug += "\" ";
    }
    argv.push_back((char*)NULL);

    neosmart::logger.Debug("Executing %s", debug.c_str());

    int pipefd[2];

    if (pipe(pipefd) != 0)
    {
        neosmart::logger.Error("Failed to create pipe descriptor when trying to launch %s", debug.c_str());
        return EXIT_FAILURE;
    }

    pid_t pid = fork();

    if (pid == 0)
    {
        close(pipefd[STDIN_FILENO]); //child isn't going to be reading
        dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
        close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
        dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);

        if (execvp(command.c_str(), &argv[0]) != 0)
        {
            exit(EXIT_FAILURE);
        }
        return 0;
    }
    else if (pid < 0)
    {
        neosmart::logger.Error("Failed to fork when trying to launch %s", debug.c_str());
        return EXIT_FAILURE;
    }
    else
    {
        close(pipefd[STDOUT_FILENO]);

        int exitCode = 0;

        if (wait)
        {
            waitpid(pid, &exitCode, wait ? __WALL : (WNOHANG | WUNTRACED));

            std::string result;
            char buffer[128];
            ssize_t bytesRead;
            while ((bytesRead = read(pipefd[STDIN_FILENO], buffer, sizeof(buffer)-1)) != 0)
            {
                buffer[bytesRead] = '\0';
                result += buffer;
            }

            if (wait)
            {
                if ((WIFEXITED(exitCode)) == 0)
                {
                    neosmart::logger.Error("Failed to run command %s", debug.c_str());
                    neosmart::logger.Info("Output:\n%s", result.c_str());
                }
                else
                {
                    neosmart::logger.Debug("Output:\n%s", result.c_str());
                    exitCode = WEXITSTATUS(exitCode);
                    if (exitCode != 0)
                    {
                        neosmart::logger.Info("Return code %d", (exitCode));
                    }
                }
            }

            if (output)
            {
                result.swap(*output);
            }
        }

        close(pipefd[STDIN_FILENO]);

        return exitCode;
    }
}

請注意,使用正確的參數運行命令,函數繼續運行沒有任何問題, WIFEXITED返回TRUE 但是, WEXITSTATUS返回0,應該返回其他內容。

可能不是你的主要問題,但我認為我看到一個小問題。 在你的孩子過程中,你有......

dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO); //but wait, this pipe is closed!

但我認為你想要的是:

dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd for both, can close

我對Linux中的分支和管道沒有多少經驗,但我最近寫了一個類似的功能。 如果您願意,可以查看要比較的代碼。 我知道我的功能有效。

execAndRedirect.cpp

我使用的貓鼬圖書館和grepping我的代碼SIGCHLD透露,使用mg_start在制定從貓鼬結果SIGCHLDSIG_IGN

waitpid手冊頁中 ,在Linux ,設置為SIG_IGNSIGCHLD不會創建僵屍進程,因此如果進程已成功運行並退出,則waitpid將失敗 - 但如果尚未運行則將運行OK。 這是我的代碼零星失敗的原因。

在將mg_start調用為無效函數后,只需重新設置SIGCHLD完成任何操作,足以防止僵屍記錄被立即刪除。

根據@ Geoff_Montee的建議 ,我的STDERR重定向中存在一個錯誤,但這不是問題的原因,因為execvp不會將返回值存儲在STDERR甚至STDOUT ,而是存儲在與父進程關聯的內核對象中(僵屍記錄)。

@jilles關於C ++中vector非連續性的警告不適用於C ++ 03及更高版本(僅對C ++ 98有效,但在實踐中,大多數C ++ 98編譯器確實使用了連續存儲),並且與此問題無關。 但是,在阻塞和檢查waitpid的輸出之前從管道讀取的建議是正確的。

我發現pclose不會阻塞並等待進程結束,這與文檔相反(這是在CentOS 6上)。 我發現我需要調用pclose然后調用waitpid(pid,&status,0); 獲得真正的回報價值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM