/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * SystemCommandJob.cpp * * Created on: Feb 5, 2012 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include #include #include "CodePatterns/MemDebug.hpp" // include headers that implement a archive in simple text format // otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect #include #include #include "SystemCommandJob.hpp" #include #include #include #include #include #include #include #include "CodePatterns/Info.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/toString.hpp" /** Constructor for class SystemCommandJob. * */ SystemCommandJob::SystemCommandJob() : FragmentJob(JobId::IllegalJob) {} /** Constructor for class SystemCommandJob. * * \param _command command to execute * \param _outputfile configuration file for solver * \param _JobId unique id of this job */ SystemCommandJob::SystemCommandJob(const std::string &_command, const std::string &_outputfile, const JobId_t _JobId) : FragmentJob(_JobId), command(_command), outputfile(_outputfile) {} /** Destructor for class SystemCommandJob. * */ SystemCommandJob::~SystemCommandJob() {} /** Work routine of this SystemCommandJob. * * This function encapsulates all the work that has to be done to generate * a FragmentResult. Hence, the FragmentWorker does not need to know anything * about the operation: it just receives it and executes this function. * * We obtain FragmentResult::exitflag from std::system's return value and * FragmentResult::result from the contents of the piped output file. * * \return result of this job */ FragmentResult::ptr SystemCommandJob::Work() { Info info((std::string(__FUNCTION__)+std::string(", id #")+toString(getId())).c_str()); // the following is taken from http://stackoverflow.com/questions/2746168/how-to-construct-a-c-fstream-from-a-posix-file-descriptor char tmpTemplate[24]; strncpy(tmpTemplate, "/tmp/XXXXXX_", 14); const std::string idstring(toString(getId())); const size_t idlength = idstring.length(); ASSERT(idlength <= 8, "SystemCommandJob::Work() - the id contains more than 8 digits."); strcat(tmpTemplate, toString(getId()).c_str()); mkstemps(tmpTemplate, idlength+1); // write outputfile to temporary file LOG(2, "DEBUG: Temporary file is " << tmpTemplate << "."); std::ofstream output(tmpTemplate); ASSERT(output.is_open(), "SystemCommandJob::Work() - the temporary file could not be opened."); output << outputfile << std::endl; // fork into subprocess and launch command std::string command_args = command+std::string(" ")+tmpTemplate; LOG(1, "INFO: Executing '" << command_args << "'."); FILE *stdoutstream = popen(command_args.c_str(), "r"); FragmentResult::ptr s; { boost::iostreams::stream stdoutfile(fileno(stdoutstream), boost::iostreams::never_close_handle); stdoutfile.set_auto_close(false); // https://svn.boost.org/trac/boost/ticket/3517 std::istreambuf_iterator beginiter = (std::istreambuf_iterator(stdoutfile)); std::string resultstring( beginiter, std::istreambuf_iterator()); // construct result LOG(2, "DEBUG: First 50 characters of output: " << resultstring.substr(0,50)); s = extractResult(resultstring); } const int exitflag = pclose(stdoutstream); if (exitflag != 0) ELOG(1, "Job " << getId() << " failed on executing: " << command_args); s->exitflag = exitflag; // close temporary file and remove it output.close(); boost::filesystem::path tmpPath(tmpTemplate); if (boost::filesystem::exists(boost::filesystem::status(tmpPath))) { LOG(2, "DEBUG: Removing " << tmpPath.string()); boost::filesystem::remove(tmpPath); } // return result return s; } /** Default function for result extraction is just copy. * * @param resultstring output of system command * @return copy of \a resultstring */ FragmentResult::ptr SystemCommandJob::extractResult(const std::string &resultstring) { return FragmentResult::ptr (new FragmentResult(getId(), resultstring) ); } /** Comparator for class SystemCommandJob. * \param other instance to compare to * \return every member variable is the same, else - is not */ bool SystemCommandJob::operator==(const SystemCommandJob &other) const { if (command != other.command) { LOG(1, "INFO: command's of two SystemCommandJobs differ: " << command << " != " << other.command << "."); return false; } if (outputfile != other.outputfile) { LOG(1, "INFO: outputfile's of two SystemCommandJobs differ: " << outputfile << " != " << other.outputfile << "."); return false; } return (dynamic_cast(*this) == dynamic_cast(other)); } // we need to explicitly instantiate the serialization functions as // its is only serialized through its base class FragmentJob BOOST_CLASS_EXPORT_IMPLEMENT(SystemCommandJob)