我有下面的幫助函數,用於執行命令並獲取posix系統上的返回值。我曾經使用popen
,但如果它運行並且在popen
/pclose
有機會完成其工作之前退出,則無法獲得應用程序的返回碼popen
。waitpid/wexitstatus返回0而不是正確的返回碼
以下幫助函數創建一個進程分叉,使用execvp
運行所需的外部進程,然後父代使用waitpid
獲取返回碼。我看到它拒絕運行的奇怪情況。
當用wait
= true
調用時,waitpid
應該返回應用程序的退出代碼,無論如何。但是,我看到stdout
輸出指定返回碼應該不爲零,但返回碼爲零。在一個普通的shell中測試外部進程,然後echo
ing $?
返回非零值,所以在外部進程沒有返回正確的代碼時這不成問題。如果有任何幫助,正在運行的外部進程是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],STDERR_FILENO);'會失敗,[EBADF]和'waitpid()'也可能失敗(什麼是__WALL?)。另外,如果輸出大於管道中的緩衝區,則應在等待進程前讀取輸出以避免死鎖。此外,「等待」的一些檢查是多餘的。 – jilles
你假設'std :: vector'中的元素在內存中是連續的是不正確的。而C++標準開發人員卻選擇保證'push_back'不會改變現有元素的地址。我建議創建一個'char *'數組,但可能會有更多的STL技巧。 – jilles
@jilles C++ 03和C++ 11保證'vector'的連續內存分配,不是嗎? –