Bugfixes for the Process class.

This commit is contained in:
Gunnar Beutner 2013-02-10 12:45:39 +01:00
parent dd93206113
commit 0e7a3c67ec
5 changed files with 78 additions and 101 deletions

View File

@ -26,9 +26,10 @@ boost::mutex Process::m_Mutex;
deque<Process::Ptr> Process::m_Tasks;
int Process::m_TaskFd;
Process::Process(const String& command, const Dictionary::Ptr& environment)
: AsyncTask<Process, ProcessResult>(), m_Command(command),
m_Environment(environment), m_FP(NULL)
extern char **environ;
Process::Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment)
: AsyncTask<Process, ProcessResult>(), m_FP(NULL)
{
assert(Application::IsMainThread());
@ -45,6 +46,49 @@ Process::Process(const String& command, const Dictionary::Ptr& environment)
m_ThreadCreated = true;
}
// build argv
m_Arguments = new char *[arguments.size() + 1];
for (int i = 0; i < arguments.size(); i++)
m_Arguments[i] = strdup(arguments[i].CStr());
m_Arguments[arguments.size()] = NULL;
// build envp
int envc = 0;
/* count existing environment variables */
while (environ[envc] != NULL)
envc++;
m_Environment = new char *[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0) + 1];
for (int i = 0; i < envc; i++)
m_Environment[i] = strdup(environ[i]);
if (extraEnvironment) {
String key;
Value value;
int index = envc;
BOOST_FOREACH(tie(key, value), extraEnvironment) {
String kv = key + "=" + Convert::ToString(value);
m_Environment[index] = strdup(kv.CStr());
index++;
}
}
m_Environment[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0)] = NULL;
}
vector<String> Process::ParseCommand(const String& command)
{
// TODO: implement
vector<String> args;
args.push_back("sh");
args.push_back("-c");
args.push_back(command);
return args;
}
void Process::Run(void)
@ -117,7 +161,7 @@ void Process::WorkerThreadProc(int taskFd)
try {
task->InitTask();
int fd = task->GetFD();
int fd = fileno(task->m_FP);
if (fd >= 0)
tasks[fd] = task;
} catch (...) {
@ -150,18 +194,10 @@ void Process::WorkerThreadProc(int taskFd)
}
}
void Process::Spawn(const String& command, const Dictionary::Ptr& env)
void Process::InitTask(void)
{
vector<String> args;
args.push_back("sh");
args.push_back("-c");
args.push_back(command);
m_Result.ExecutionStart = Utility::GetTime();
return Spawn(args, env);
}
void Process::Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv)
{
assert(m_FP == NULL);
#ifdef _MSC_VER
@ -172,37 +208,6 @@ void Process::Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv)
if (pipe(fds) < 0)
BOOST_THROW_EXCEPTION(PosixException("pipe() failed.", errno));
char **argv = new char *[args.size() + 1];
for (int i = 0; i < args.size(); i++)
argv[i] = strdup(args[i].CStr());
argv[args.size()] = NULL;
int envc = 0;
/* count existing environment variables */
while (environ[envc] != NULL)
envc++;
char **envp = new char *[envc + (extraEnv ? extraEnv->GetLength() : 0) + 1];
for (int i = 0; i < envc; i++)
envp[i] = environ[i];
if (extraEnv) {
String key;
Value value;
int index = envc;
BOOST_FOREACH(tie(key, value), extraEnv) {
String kv = key + "=" + Convert::ToString(value);
envp[index] = strdup(kv.CStr());
index++;
}
}
envp[envc + (extraEnv ? extraEnv->GetLength() : 0)] = NULL;
#ifdef HAVE_VFORK
m_Pid = vfork();
#else /* HAVE_VFORK */
@ -213,7 +218,8 @@ void Process::Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv)
BOOST_THROW_EXCEPTION(PosixException("fork() failed.", errno));
if (m_Pid == 0) {
/* child */
// child process
if (dup2(fds[1], STDOUT_FILENO) < 0 || dup2(fds[1], STDERR_FILENO) < 0) {
perror("dup2() failed.");
_exit(128);
@ -221,26 +227,27 @@ void Process::Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv)
(void) close(fds[1]);
if (execvpe(argv[0], argv, envp) < 0) {
if (execvpe(m_Arguments[0], m_Arguments, m_Environment) < 0) {
perror("execvpe() failed.");
_exit(128);
}
_exit(128);
} else {
for (int i = 0; i < args.size(); i++)
free(argv[i]);
// parent process
delete [] argv;
// free arguments
for (int i = 0; m_Arguments[i] != NULL; i++)
free(m_Arguments[i]);
if (extraEnv) {
for (int i = envc; i < envc + extraEnv->GetLength(); i++)
free(envp[i]);
}
delete [] m_Arguments;
delete [] envp;
// free environment
for (int i = 0; m_Environment[i] != NULL; i++)
free(m_Environment[i]);
delete [] m_Environment;
/* parent */
(void) close(fds[1]);
m_FP = fdopen(fds[0], "r");
@ -251,28 +258,6 @@ void Process::Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv)
#endif /* _MSC_VER */
}
int Process::WaitPid(void)
{
#ifdef _MSC_VER
return _pclose(m_FP);
#else /* _MSC_VER */
fclose(m_FP);
int status;
if (waitpid(m_Pid, &status, 0) != m_Pid)
BOOST_THROW_EXCEPTION(PosixException("waitpid() failed.", errno));
return status;
#endif /* _MSC_VER */
}
void Process::InitTask(void)
{
m_Result.ExecutionStart = Utility::GetTime();
Spawn(m_Command, m_Environment);
}
bool Process::RunTask(void)
{
char buffer[512];
@ -288,7 +273,14 @@ bool Process::RunTask(void)
int status, exitcode;
status = WaitPid();
#ifdef _MSC_VER
status = _pclose(m_FP);
#else /* _MSC_VER */
fclose(m_FP);
if (waitpid(m_Pid, &status, 0) != m_Pid)
BOOST_THROW_EXCEPTION(PosixException("waitpid() failed.", errno));
#endif /* _MSC_VER */
#ifndef _MSC_VER
if (WIFEXITED(status)) {
@ -320,13 +312,3 @@ bool Process::RunTask(void)
return false;
}
/**
* Retrieves the stdout file descriptor for the child process.
*
* @returns The stdout file descriptor.
*/
int Process::GetFD(void) const
{
return fileno(m_FP);
}

View File

@ -50,13 +50,14 @@ public:
static const deque<Process::Ptr>::size_type MaxTasksPerThread = 512;
Process(const String& command, const Dictionary::Ptr& environment = Dictionary::Ptr());
Process(const vector<String>& arguments, const Dictionary::Ptr& extraEnvironment = Dictionary::Ptr());
static vector<String> ParseCommand(const String& command);
private:
static bool m_ThreadCreated;
String m_Command;
Dictionary::Ptr m_Environment;
char **m_Arguments;
char **m_Environment;
#ifndef _WIN32
pid_t m_Pid;
@ -77,12 +78,6 @@ private:
void InitTask(void);
bool RunTask(void);
int GetFD(void) const;
void Spawn(const String& command, const Dictionary::Ptr& extraEnv);
void Spawn(const vector<String>& args, const Dictionary::Ptr& extraEnv);
int WaitPid(void);
};
}

View File

@ -48,7 +48,7 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value
macroDicts.push_back(IcingaApplication::GetInstance()->GetMacros());
String command = MacroProcessor::ResolveMacros(checkCommand, macroDicts);
Process::Ptr process = boost::make_shared<Process>(command, MacroProcessor::MakeEnvironment(macroDicts));
Process::Ptr process = boost::make_shared<Process>(Process::ParseCommand(command), MacroProcessor::MakeEnvironment(macroDicts));
PluginCheckTask ct(task, process);

View File

@ -53,7 +53,7 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const vecto
macroDicts.push_back(IcingaApplication::GetInstance()->GetMacros());
String command = MacroProcessor::ResolveMacros(notificationCommand, macroDicts);
Process::Ptr process = boost::make_shared<Process>(command, MacroProcessor::MakeEnvironment(macroDicts));
Process::Ptr process = boost::make_shared<Process>(Process::ParseCommand(command), MacroProcessor::MakeEnvironment(macroDicts));
PluginNotificationTask ct(task, process, notification->GetService()->GetName(), command);

View File

@ -35,7 +35,7 @@ void Service::RequestNotifications(NotificationType type) const
params.SetService(GetName());
params.SetType(type);
Logger::Write(LogInformation, "icinga", "Sending notification anycast request for service '" + GetName() + "'");
Logger::Write(LogDebug, "icinga", "Sending notification anycast request for service '" + GetName() + "'");
EndpointManager::GetInstance()->SendAnycastMessage(Endpoint::Ptr(), msg);
}