1 #ifndef CPPAD_CG_LINUX_SYSTEM_INCLUDED
2 #define CPPAD_CG_LINUX_SYSTEM_INCLUDED
19 #if CPPAD_CG_SYSTEM_LINUX
21 #include <sys/types.h>
44 inline FDHandler() : fd(0), closed(true) {
47 inline explicit FDHandler(
int fd) : fd(fd), closed(false) {
71 inline void create() {
74 throw CGException(
"Failed to create pipe");
85 #ifdef CPPAD_CG_SYSTEM_APPLE
87 const std::string SystemInfo<T>::DYNAMIC_LIB_EXTENSION =
".dylib";
90 const std::string SystemInfo<T>::DYNAMIC_LIB_EXTENSION =
".so";
94 const std::string SystemInfo<T>::STATIC_LIB_EXTENSION =
".a";
96 inline std::string getWorkingDirectory() {
99 char* ret = getcwd(buffer, 1024);
100 if (ret ==
nullptr) {
101 const char* error = strerror(errno);
102 throw CGException(
"Failed to get current working directory: ", error);
109 int ret = mkdir(folder.c_str(), 0755);
111 if (errno != EEXIST) {
112 const char* error = strerror(errno);
113 throw CGException(
"Failed to create directory '", folder +
"': ", error);
118 inline std::string
createPath(std::initializer_list<std::string> folders,
119 const std::string& file) {
122 size_t n = file.size();
123 for (
const std::string& folder: folders)
124 n += folder.size() + 1;
127 for (
const std::string& folder: folders) {
128 if (!folder.empty() && folder.back() ==
'/') {
141 inline std::string
createPath(
const std::string& folder,
142 const std::string& file) {
146 inline std::string
escapePath(
const std::string& path) {
147 return std::string(
"\"") + path +
"\"";
150 inline std::string filenameFromPath(
const std::string& path) {
151 size_t pos = path.rfind(
'/');
152 if (pos != std::string::npos) {
153 if (pos == path.size() - 1) {
156 return path.substr(pos + 1);
163 inline std::string directoryFromPath(
const std::string& path) {
164 size_t found = path.find_last_of(
'/');
165 if (found != std::string::npos) {
166 return path.substr(0, found + 1);
175 return path[0] ==
'/';
181 if (stat(path.c_str(), &info) != 0) {
183 }
else return (info.st_mode & S_IFDIR) != 0;
186 inline bool isFile(
const std::string& path) {
189 if (stat(path.c_str(), &sts) == 0 && errno == 0) {
190 return S_ISREG(sts.st_mode);
191 }
else if (errno == ENOENT) {
199 const std::vector<std::string>& args,
200 std::string* stdOutErrMessage,
201 const std::string* stdInMessage) {
202 std::string execName = filenameFromPath(executable);
207 PipeHandler pipeStdOutErr;
208 if(stdOutErrMessage !=
nullptr) {
209 pipeStdOutErr.create();
213 if (stdInMessage !=
nullptr) {
221 throw CGException(
"Failed to fork process");
228 pipeMsg.read.close();
230 if (stdInMessage !=
nullptr) {
231 pipeSrc.write.close();
234 if (dup2(pipeSrc.read.fd, STDIN_FILENO) == -1) {
235 perror(
"redirecting stdin");
240 if(stdOutErrMessage !=
nullptr) {
241 pipeStdOutErr.read.close();
244 if (dup2(pipeStdOutErr.write.fd, STDOUT_FILENO) == -1) {
245 perror(
"redirecting stdout");
250 if (dup2(pipeStdOutErr.write.fd, STDERR_FILENO) == -1) {
251 perror(
"redirecting stderr");
256 auto toCharArray = [](
const std::string & args) {
257 const size_t s = args.size() + 1;
258 char* args2 =
new char[s];
259 for (
size_t c = 0; c < s - 1; c++) {
260 args2[c] = args.at(c);
266 std::vector<char*> args2(args.size() + 2);
267 args2[0] = toCharArray(execName);
268 for (
size_t i = 0; i < args.size(); i++) {
269 args2[i + 1] = toCharArray(args[i]);
271 args2.back() = (
char *)
nullptr;
273 int eCode = execv(executable.c_str(), &args2[0]);
275 for (
size_t i = 0; i < args.size(); i++) {
279 if(stdOutErrMessage !=
nullptr) {
280 pipeStdOutErr.write.close();
285 #ifndef CPPAD_CG_SYSTEM_APPLE
286 std::string error = executable +
": " + strerror_r(errno, buf, 511);
288 std::string error = executable +
": ";
289 strerror_r(errno, buf, 511);
290 error += std::string(buf);
292 ssize_t size = error.size() + 1;
293 if (write(pipeMsg.write.fd, error.c_str(), size) != size) {
294 std::cerr <<
"Failed to send message to parent process" << std::endl;
296 std::cerr <<
"*** ERROR: exec failed" << std::endl;
306 pipeMsg.write.close();
307 if(stdOutErrMessage !=
nullptr) {
308 pipeStdOutErr.write.close();
311 auto readCErrorMsg = []() {
315 #ifndef CPPAD_CG_SYSTEM_APPLE
316 return std::string(strerror_r(error, buf, 512));
318 strerror_r(error, buf, 512);
319 return std::string(buf);
323 std::string writeError;
324 if (stdInMessage !=
nullptr) {
326 pipeSrc.read.close();
328 ssize_t writeFlag = write(pipeSrc.write.fd, stdInMessage->c_str(), stdInMessage->size());
330 writeError = readCErrorMsg() +
" ";
331 pipeSrc.write.close();
337 std::ostringstream messageErr;
338 std::ostringstream messageStdOutErr;
343 if(stdOutErrMessage !=
nullptr) {
344 while ((n = read(pipeStdOutErr.read.fd, buffer, sizeof (buffer))) > 0) {
345 messageStdOutErr.write(buffer, n);
347 if (size > 1e4)
break;
351 while ((n = read(pipeMsg.read.fd, buffer, sizeof (buffer))) > 0) {
352 messageErr.write(buffer, n);
354 if (size > 1e4)
break;
357 if (waitpid(pid, &status, 0) < 0) {
358 throw CGException(
"Waitpid failed for pid ", pid,
" [", readCErrorMsg(),
"]");
360 }
while (!WIFEXITED(status) && !WIFSIGNALED(status));
362 pipeMsg.read.close();
363 if(stdOutErrMessage !=
nullptr) {
364 pipeStdOutErr.read.close();
367 if (!writeError.empty()) {
368 std::ostringstream s;
369 s <<
"Failed to write to pipe";
370 if (size > 0) s <<
": " << messageErr.str();
371 else s <<
": " << writeError;
372 throw CGException(s.str());
375 if (WIFEXITED(status)) {
376 if (WEXITSTATUS(status) != EXIT_SUCCESS) {
377 std::ostringstream s;
378 s <<
"Executable '" << executable <<
"' (pid " << pid <<
") exited with code " << WEXITSTATUS(status);
379 if (size > 0) s <<
": " << messageErr.str();
380 throw CGException(s.str());
382 }
else if (WIFSIGNALED(status)) {
383 std::ostringstream s;
384 s <<
"Executable '" << executable <<
"' (pid " << pid <<
") terminated by signal " << WTERMSIG(status);
385 if (size > 0) s <<
": " << messageErr.str();
386 throw CGException(s.str());
389 if (stdOutErrMessage !=
nullptr) {
390 *stdOutErrMessage = messageStdOutErr.str();