From 634aefe4fdaa245ad977dd7e8eff1744f380a02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 8 Jul 2015 21:31:34 +0200 Subject: [PATCH] launch_daemon: Now supports getting the env from a script. * Scripts from targets are evaluated once on first target launch, scripts from jobs are evaluated on each start. * The "desktop" target now sources SetupEnvironment as usual. --- data/launch/user | 2 + src/servers/launch/BaseJob.cpp | 129 +++++++++++++++++++++++++- src/servers/launch/BaseJob.h | 12 +++ src/servers/launch/Job.cpp | 6 +- src/servers/launch/LaunchDaemon.cpp | 3 + src/servers/launch/SettingsParser.cpp | 2 +- 6 files changed, 151 insertions(+), 3 deletions(-) diff --git a/data/launch/user b/data/launch/user index 66308e920d..b552fd5f98 100644 --- a/data/launch/user +++ b/data/launch/user @@ -1,4 +1,6 @@ target desktop { + env /system/boot/SetupEnvironment + service x-vnd.Be-TRAK { launch /system/Tracker legacy diff --git a/src/servers/launch/BaseJob.cpp b/src/servers/launch/BaseJob.cpp index e1c3ffc00a..a98ba07e46 100644 --- a/src/servers/launch/BaseJob.cpp +++ b/src/servers/launch/BaseJob.cpp @@ -6,6 +6,9 @@ #include "BaseJob.h" +#include +#include + #include #include "Conditions.h" @@ -70,6 +73,13 @@ BaseJob::Environment() const } +BStringList& +BaseJob::Environment() +{ + return fEnvironment; +} + + const BStringList& BaseJob::EnvironmentSourceFiles() const { @@ -77,6 +87,13 @@ BaseJob::EnvironmentSourceFiles() const } +BStringList& +BaseJob::EnvironmentSourceFiles() +{ + return fSourceFiles; +} + + void BaseJob::SetEnvironment(const BMessage& message) { @@ -85,7 +102,7 @@ BaseJob::SetEnvironment(const BMessage& message) int32 count; for (int32 index = 0; message.GetInfo(B_STRING_TYPE, index, &name, &type, &count) == B_OK; index++) { - if (strcmp(name, "from_file") == 0) { + if (strcmp(name, "from_script") == 0) { const char* fromFile; for (int32 fileIndex = 0; message.FindString(name, fileIndex, &fromFile) == B_OK; fileIndex++) { @@ -109,3 +126,113 @@ BaseJob::SetEnvironment(const BMessage& message) fEnvironment.Add(variable); } } + + +void +BaseJob::GetSourceFilesEnvironment(BStringList& environment) +{ + int32 count = fSourceFiles.CountStrings(); + for (int32 index = 0; index < count; index++) { + _GetSourceFileEnvironment(fSourceFiles.StringAt(index), fEnvironment); + } +} + + +/*! Gets the environment by evaluating the source files, and move that + environment to the static environment. + + When this method returns, the source files list will be empty. +*/ +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) { + // TODO: log error + return; + } + + pid_t child = fork(); + if (child < 0) { + // TODO: log error + } else if (child == 0) { + // We're the child, redirect stdout + close(STDOUT_FILENO); + close(STDERR_FILENO); + dup2(pipes[1], STDOUT_FILENO); + dup2(pipes[1], STDERR_FILENO); + + for (int32 i = 0; i < 2; i++) + close(pipes[i]); + + BString command; + command.SetToFormat(". \"%s\"; export -p", script); + execl("/bin/sh", "/bin/sh", "-c", command.String(), NULL); + exit(1); + } else { + // Retrieve environment from child + + close(pipes[1]); + + BString line; + char buffer[4096]; + while (true) { + ssize_t bytesRead = read(pipes[0], buffer, sizeof(buffer) - 1); + if (bytesRead <= 0) + break; + + // Make sure the buffer is null terminated + 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); +} diff --git a/src/servers/launch/BaseJob.h b/src/servers/launch/BaseJob.h index 4c014f3373..6ebd1dbd8b 100644 --- a/src/servers/launch/BaseJob.h +++ b/src/servers/launch/BaseJob.h @@ -30,9 +30,21 @@ public: bool CheckCondition(ConditionContext& context) const; const BStringList& Environment() const; + BStringList& Environment(); const BStringList& EnvironmentSourceFiles() const; + BStringList& EnvironmentSourceFiles(); void SetEnvironment(const BMessage& message); + void GetSourceFilesEnvironment( + BStringList& environment); + void ResolveSourceFiles(); + +private: + void _GetSourceFileEnvironment(const char* script, + BStringList& environment); + void _ParseExportVariable(BStringList& environment, + const BString& line); + protected: ::Condition* fCondition; BStringList fEnvironment; diff --git a/src/servers/launch/Job.cpp b/src/servers/launch/Job.cpp index 9e7606271c..1092ae9cd4 100644 --- a/src/servers/launch/Job.cpp +++ b/src/servers/launch/Job.cpp @@ -306,7 +306,6 @@ Job::Launch() { // Build environment - // TODO: resolve environment source files std::vector environment; for (const char** variable = (const char**)environ; variable[0] != NULL; variable++) { @@ -317,6 +316,11 @@ Job::Launch() _AddStringList(environment, Target()->Environment()); _AddStringList(environment, Environment()); + // Resolve source files + BStringList sourceFilesEnvironment; + GetSourceFilesEnvironment(sourceFilesEnvironment); + _AddStringList(environment, sourceFilesEnvironment); + environment.push_back(NULL); if (fArguments.IsEmpty()) { diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index 084ecbf760..6143b2820a 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -684,6 +684,9 @@ LaunchDaemon::_LaunchJobs(Target* target) void LaunchDaemon::_AddLaunchJob(Job* job) { + if (job->Target() != NULL) + job->Target()->ResolveSourceFiles(); + if (!job->IsLaunched() && job->CheckCondition(*this)) fJobQueue.AddJob(job); } diff --git a/src/servers/launch/SettingsParser.cpp b/src/servers/launch/SettingsParser.cpp index 1da79e881b..8c81edf39d 100644 --- a/src/servers/launch/SettingsParser.cpp +++ b/src/servers/launch/SettingsParser.cpp @@ -111,7 +111,7 @@ const static settings_template kPortTemplate[] = { }; const static settings_template kEnvTemplate[] = { - {B_STRING_TYPE, "from_file", NULL, true}, + {B_STRING_TYPE, "from_script", NULL, true}, {B_STRING_TYPE, NULL, NULL}, };