1 /*
2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "BaseJob.h"
8
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include <Message.h>
15
16 #include "Conditions.h"
17 #include "Events.h"
18
19
BaseJob(const char * name)20 BaseJob::BaseJob(const char* name)
21 :
22 BJob(name),
23 fCondition(NULL),
24 fEvent(NULL)
25 {
26 }
27
28
~BaseJob()29 BaseJob::~BaseJob()
30 {
31 delete fCondition;
32 }
33
34
35 const char*
Name() const36 BaseJob::Name() const
37 {
38 return Title().String();
39 }
40
41
42 const ::Condition*
Condition() const43 BaseJob::Condition() const
44 {
45 return fCondition;
46 }
47
48
49 ::Condition*
Condition()50 BaseJob::Condition()
51 {
52 return fCondition;
53 }
54
55
56 void
SetCondition(::Condition * condition)57 BaseJob::SetCondition(::Condition* condition)
58 {
59 fCondition = condition;
60 }
61
62
63 bool
CheckCondition(ConditionContext & context) const64 BaseJob::CheckCondition(ConditionContext& context) const
65 {
66 if (fCondition != NULL)
67 return fCondition->Test(context);
68
69 return true;
70 }
71
72
73 const ::Event*
Event() const74 BaseJob::Event() const
75 {
76 return fEvent;
77 }
78
79
80 ::Event*
Event()81 BaseJob::Event()
82 {
83 return fEvent;
84 }
85
86
87 void
SetEvent(::Event * event)88 BaseJob::SetEvent(::Event* event)
89 {
90 fEvent = event;
91 if (event != NULL)
92 event->SetOwner(this);
93 }
94
95
96 /*! Determines whether the events of this job has been triggered
97 already or not.
98 Note, if this job does not have any events, this method returns
99 \c true.
100 */
101 bool
EventHasTriggered() const102 BaseJob::EventHasTriggered() const
103 {
104 return Event() == NULL || Event()->Triggered();
105 }
106
107
108 const BStringList&
Environment() const109 BaseJob::Environment() const
110 {
111 return fEnvironment;
112 }
113
114
115 BStringList&
Environment()116 BaseJob::Environment()
117 {
118 return fEnvironment;
119 }
120
121
122 const BStringList&
EnvironmentSourceFiles() const123 BaseJob::EnvironmentSourceFiles() const
124 {
125 return fSourceFiles;
126 }
127
128
129 BStringList&
EnvironmentSourceFiles()130 BaseJob::EnvironmentSourceFiles()
131 {
132 return fSourceFiles;
133 }
134
135
136 void
SetEnvironment(const BMessage & message)137 BaseJob::SetEnvironment(const BMessage& message)
138 {
139 char* name;
140 type_code type;
141 int32 count;
142 for (int32 index = 0; message.GetInfo(B_STRING_TYPE, index, &name, &type,
143 &count) == B_OK; index++) {
144 if (strcmp(name, "from_script") == 0) {
145 const char* fromScript;
146 for (int32 scriptIndex = 0; message.FindString(name, scriptIndex,
147 &fromScript) == B_OK; scriptIndex++) {
148 fSourceFiles.Add(fromScript);
149 }
150 continue;
151 }
152
153 BString variable = name;
154 variable << "=";
155
156 const char* argument;
157 for (int32 argumentIndex = 0; message.FindString(name, argumentIndex,
158 &argument) == B_OK; argumentIndex++) {
159 if (argumentIndex > 0)
160 variable << " ";
161 variable += argument;
162 }
163
164 fEnvironment.Add(variable);
165 }
166 }
167
168
169 void
GetSourceFilesEnvironment(BStringList & environment)170 BaseJob::GetSourceFilesEnvironment(BStringList& environment)
171 {
172 int32 count = fSourceFiles.CountStrings();
173 for (int32 index = 0; index < count; index++) {
174 _GetSourceFileEnvironment(fSourceFiles.StringAt(index), environment);
175 }
176 }
177
178
179 /*! Gets the environment by evaluating the source files, and move that
180 environment to the static environment.
181
182 When this method returns, the source files list will be empty.
183 */
184 void
ResolveSourceFiles()185 BaseJob::ResolveSourceFiles()
186 {
187 if (fSourceFiles.IsEmpty())
188 return;
189
190 GetSourceFilesEnvironment(fEnvironment);
191 fSourceFiles.MakeEmpty();
192 }
193
194
195 void
_GetSourceFileEnvironment(const char * script,BStringList & environment)196 BaseJob::_GetSourceFileEnvironment(const char* script, BStringList& environment)
197 {
198 int pipes[2];
199 if (pipe(&pipes[0]) != 0) {
200 // TODO: log error
201 return;
202 }
203
204 pid_t child = fork();
205 if (child < 0) {
206 // TODO: log error
207 debug_printf("could not fork: %s\n", strerror(errno));
208 } else if (child == 0) {
209 // We're the child, redirect stdout
210 close(STDOUT_FILENO);
211 close(STDERR_FILENO);
212 dup2(pipes[1], STDOUT_FILENO);
213 dup2(pipes[1], STDERR_FILENO);
214
215 for (int32 i = 0; i < 2; i++)
216 close(pipes[i]);
217
218 BString command;
219 command.SetToFormat(". \"%s\"; export -p", script);
220 execl("/bin/sh", "/bin/sh", "-c", command.String(), NULL);
221 exit(1);
222 } else {
223 // Retrieve environment from child
224
225 close(pipes[1]);
226
227 BString line;
228 char buffer[4096];
229 while (true) {
230 ssize_t bytesRead = read(pipes[0], buffer, sizeof(buffer) - 1);
231 if (bytesRead <= 0)
232 break;
233
234 // Make sure the buffer is null terminated
235 buffer[bytesRead] = 0;
236
237 const char* chunk = buffer;
238 while (true) {
239 const char* separator = strchr(chunk, '\n');
240 if (separator == NULL) {
241 line.Append(chunk, bytesRead);
242 break;
243 }
244 line.Append(chunk, separator - chunk);
245 chunk = separator + 1;
246
247 _ParseExportVariable(environment, line);
248 line.Truncate(0);
249 }
250 }
251 if (!line.IsEmpty())
252 _ParseExportVariable(environment, line);
253
254 close(pipes[0]);
255 }
256 }
257
258
259 void
_ParseExportVariable(BStringList & environment,const BString & line)260 BaseJob::_ParseExportVariable(BStringList& environment, const BString& line)
261 {
262 if (!line.StartsWith("export "))
263 return;
264
265 int separator = line.FindFirst("=\"");
266 if (separator < 0)
267 return;
268
269 BString variable;
270 line.CopyInto(variable, 7, separator - 7);
271
272 BString value;
273 line.CopyInto(value, separator + 2, line.Length() - separator - 3);
274
275 variable << "=" << value;
276 environment.Add(variable);
277 }
278