NORM-mirror/common/normPostProcess.cpp

166 lines
4.4 KiB
C++

#include "normPostProcess.h"
#include "protoLib.h"
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#ifdef UNIX
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif // UNIX
typedef void (*sighandler_t)(int);
NormPostProcessor::NormPostProcessor()
: process_argv(NULL)
#ifdef UNIX
,process_id(0)
#endif // UNIX
{
}
NormPostProcessor::~NormPostProcessor()
{
if (IsActive()) Kill();
SetCommand(NULL);
}
bool NormPostProcessor::SetCommand(const char* cmd)
{
// 1) Delete old command resources
if (process_argv)
{
const char** arg = process_argv;
while (*arg)
{
delete *arg;
arg++;
}
delete process_argv;
process_argv = NULL;
process_argc = 0;
}
// 2) Count the number of tokens
if (!cmd) return true; // post processing disabled
if (!strcmp(cmd, "none")) return SetCommand(NULL);
const char* ptr = cmd;
unsigned int argCount = 0;
while (isspace(*ptr) && ('\0' != *ptr)) ptr++;
while ('\0' != *ptr)
{
argCount++;
while (!isspace(*ptr) && ('\0' != *ptr)) ptr++;
}
if (!argCount) return true; // post processing disabled
// 3) Allocate new process_argv array (2 extra slots, one for "target",
// and one for terminating NULL pointer.
if (!(process_argv = new const char*[argCount+2]))
{
DMSG(0, "NormPostProcessor::SetCommand new(process_argv) error: %s\n",
strerror(errno));
return false;
}
memset((void*)process_argv, 0, (argCount+2)*sizeof(char**));
process_argc = argCount;
// 4) Fill in process_argv[] array with individual args
ptr = cmd;
while (isspace(*ptr) && ('\0' != *ptr)) ptr++;
unsigned int index = 0;
while ('\0' != *ptr)
{
const char* argStart = ptr;
while (!isspace(*ptr) && ('\0' != *ptr)) ptr++;
unsigned int argLength = ptr - argStart;
char* arg;
if (!(arg = new char[argLength+1]))
{
SetCommand(NULL);
DMSG(0, "NormPostProcessor::SetCommand new(process_arg) error: %s\n",
strerror(errno));
return false;
}
strncpy(arg, argStart, argLength);
arg[argLength] = '\0';
process_argv[index] = arg;
}
return true;
} // end NormPostProcessor::SetCommand()
bool NormPostProcessor::ProcessFile(const char* path)
{
if (IsActive()) Kill();
#ifdef UNIX
// 1) temporarily disable signal handling
sighandler_t sigtermHandler = signal(SIGTERM, SIG_DFL);
sighandler_t sigintHandler = signal(SIGINT, SIG_DFL);
sighandler_t sigchldHandler = signal(SIGCHLD, SIG_DFL);
process_argv[process_argc] = path;
switch((process_id = fork()))
{
case -1: // error
DMSG(0, "NormPostProcessor::ProcessFile fork() error: %s\n", strerror(errno));
process_id = 0;
process_argv[process_argc] = NULL;
return false;
case 0: // child
if (execvp((char*)process_argv[0], (char**)process_argv) < 0)
{
DMSG(0, "NormPostProcessor::ProcessFile execvp() error: %s\n", strerror(errno));
exit(-1);
}
break;
default: // parent
process_argv[process_argc] = NULL;
// Restore signal handlers for parent
signal(SIGTERM, sigtermHandler);
signal(SIGINT, sigintHandler);
signal(SIGCHLD, sigchldHandler);
break;
}
#endif // UNIX
return true;
} // end NormPostProcessor::ProcessFile()
void NormPostProcessor::Kill()
{
if (!IsActive()) return;
#ifdef UNIX
int count = 0;
while((kill(process_id, SIGTERM) != 0) && count < 10)
{
if (errno == ESRCH) break;
count++;
DMSG(0, "NormPostProcessor::Kill kill() error: %s\n", strerror(errno));
}
count = 0;
int status;
while((waitpid(process_id, &status, 0) != process_id) && count < 10)
{
if (errno == ECHILD) break;
count++;
DMSG(0, "NormPostProcessor::Kill waitpid() error: %s\n", strerror(errno));
}
process_id = 0;
#endif // UNIX
} // end NormPostProcessor::Kill()
void NormPostProcessor::HandleSIGCHLD()
{
// See if processor exited itself
int status;
if (wait(&status) == process_id) process_id = 0;
} // end NormPostProcessor::HandleSIGCHLD()