#include "BaseJob.h"
#include <errno.h>
#include <spawn.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <AutoDeleter.h>
#include <Message.h>
#include "Conditions.h"
#include "Events.h"
BaseJob::BaseJob(const char* name)
:
BJob(name),
fCondition(NULL),
fEvent(NULL)
{
}
BaseJob::~BaseJob()
{
delete fCondition;
}
const char*
BaseJob::Name() const
{
return Title().String();
}
const ::Condition*
BaseJob::Condition() const
{
return fCondition;
}
::Condition*
BaseJob::Condition()
{
return fCondition;
}
void
BaseJob::SetCondition(::Condition* condition)
{
fCondition = condition;
}
bool
BaseJob::CheckCondition(ConditionContext& context) const
{
if (fCondition != NULL)
return fCondition->Test(context);
return true;
}
const ::Event*
BaseJob::Event() const
{
return fEvent;
}
::Event*
BaseJob::Event()
{
return fEvent;
}
void
BaseJob::SetEvent(::Event* event)
{
fEvent = event;
if (event != NULL)
event->SetOwner(this);
}
bool
BaseJob::EventHasTriggered() const
{
return Event() == NULL || Event()->Triggered();
}
const BStringList&
BaseJob::Environment() const
{
return fEnvironment;
}
BStringList&
BaseJob::Environment()
{
return fEnvironment;
}
const BStringList&
BaseJob::EnvironmentSourceFiles() const
{
return fSourceFiles;
}
BStringList&
BaseJob::EnvironmentSourceFiles()
{
return fSourceFiles;
}
void
BaseJob::SetEnvironment(const BMessage& message)
{
char* name;
type_code type;
int32 count;
for (int32 index = 0; message.GetInfo(B_STRING_TYPE, index, &name, &type,
&count) == B_OK; index++) {
if (strcmp(name, "from_script") == 0) {
const char* fromScript;
for (int32 scriptIndex = 0; message.FindString(name, scriptIndex,
&fromScript) == B_OK; scriptIndex++) {
fSourceFiles.Add(fromScript);
}
continue;
}
BString variable = name;
variable << "=";
const char* argument;
for (int32 argumentIndex = 0; message.FindString(name, argumentIndex,
&argument) == B_OK; argumentIndex++) {
if (argumentIndex > 0)
variable << " ";
variable += argument;
}
fEnvironment.Add(variable);
}
}
void
BaseJob::GetSourceFilesEnvironment(BStringList& environment)
{
int32 count = fSourceFiles.CountStrings();
for (int32 index = 0; index < count; index++) {
_GetSourceFileEnvironment(fSourceFiles.StringAt(index), environment);
}
}
void
BaseJob::ResolveSourceFiles()
{
if (fSourceFiles.IsEmpty())
return;
GetSourceFilesEnvironment(fEnvironment);
fSourceFiles.MakeEmpty();
}
void
BaseJob::_GetSourceFileEnvironment(const char* script, BStringList& environment)
{
int pipes[2];
if (pipe(&pipes[0]) != 0) {
return;
}
posix_spawn_file_actions_t fileActions;
int status = posix_spawn_file_actions_init(&fileActions);
if (status != 0) {
return;
}
CObjectDeleter<posix_spawn_file_actions_t, int, posix_spawn_file_actions_destroy>
actionsDeleter(&fileActions);
posix_spawn_file_actions_addclose(&fileActions, STDOUT_FILENO);
posix_spawn_file_actions_addclose(&fileActions, STDERR_FILENO);
posix_spawn_file_actions_adddup2(&fileActions, pipes[1], STDOUT_FILENO);
posix_spawn_file_actions_adddup2(&fileActions, pipes[1], STDERR_FILENO);
for (int32 i = 0; i < 2; i++)
posix_spawn_file_actions_addclose(&fileActions, pipes[i]);
BString command;
command.SetToFormat(". \"%s\"; export -p", script);
const char* argv[] = {"/bin/sh", "-c", command.String(), NULL};
pid_t child;
status = posix_spawn(&child, argv[0], &fileActions, NULL, (char**)argv, NULL);
if (status != 0) {
debug_printf("could not fork: %s\n", strerror(errno));
return;
}
close(pipes[1]);
BString line;
char buffer[4096];
while (true) {
ssize_t bytesRead = read(pipes[0], buffer, sizeof(buffer) - 1);
if (bytesRead <= 0)
break;
buffer[bytesRead] = 0;
const char* chunk = buffer;
while (true) {
const char* separator = strchr(chunk, '\n');
if (separator == NULL) {
line.Append(chunk, bytesRead);
break;
}
line.Append(chunk, separator - chunk);
chunk = separator + 1;
_ParseExportVariable(environment, line);
line.Truncate(0);
}
}
if (!line.IsEmpty())
_ParseExportVariable(environment, line);
close(pipes[0]);
}
void
BaseJob::_ParseExportVariable(BStringList& environment, const BString& line)
{
if (!line.StartsWith("export "))
return;
int separator = line.FindFirst("=\"");
if (separator < 0)
return;
BString variable;
line.CopyInto(variable, 7, separator - 7);
BString value;
line.CopyInto(value, separator + 2, line.Length() - separator - 3);
variable << "=" << value;
environment.Add(variable);
}