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 20 BaseJob::BaseJob(const char* name) 21 : 22 BJob(name), 23 fCondition(NULL), 24 fEvent(NULL) 25 { 26 } 27 28 29 BaseJob::~BaseJob() 30 { 31 delete fCondition; 32 } 33 34 35 const char* 36 BaseJob::Name() const 37 { 38 return Title().String(); 39 } 40 41 42 const ::Condition* 43 BaseJob::Condition() const 44 { 45 return fCondition; 46 } 47 48 49 ::Condition* 50 BaseJob::Condition() 51 { 52 return fCondition; 53 } 54 55 56 void 57 BaseJob::SetCondition(::Condition* condition) 58 { 59 fCondition = condition; 60 } 61 62 63 bool 64 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* 74 BaseJob::Event() const 75 { 76 return fEvent; 77 } 78 79 80 ::Event* 81 BaseJob::Event() 82 { 83 return fEvent; 84 } 85 86 87 void 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 102 BaseJob::EventHasTriggered() const 103 { 104 return Event() == NULL || Event()->Triggered(); 105 } 106 107 108 const BStringList& 109 BaseJob::Environment() const 110 { 111 return fEnvironment; 112 } 113 114 115 BStringList& 116 BaseJob::Environment() 117 { 118 return fEnvironment; 119 } 120 121 122 const BStringList& 123 BaseJob::EnvironmentSourceFiles() const 124 { 125 return fSourceFiles; 126 } 127 128 129 BStringList& 130 BaseJob::EnvironmentSourceFiles() 131 { 132 return fSourceFiles; 133 } 134 135 136 void 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 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 185 BaseJob::ResolveSourceFiles() 186 { 187 if (fSourceFiles.IsEmpty()) 188 return; 189 190 GetSourceFilesEnvironment(fEnvironment); 191 fSourceFiles.MakeEmpty(); 192 } 193 194 195 void 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 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