diff --git a/src/components/utils/CMakeLists.txt b/src/components/utils/CMakeLists.txt index 9db13128441..fc79d448f86 100644 --- a/src/components/utils/CMakeLists.txt +++ b/src/components/utils/CMakeLists.txt @@ -124,7 +124,7 @@ add_dependencies("Utils" Boost) if(ENABLE_LOG) - add_dependencies("Utils" install-3rd_party_logger) + add_dependencies("Utils" install-3rd_party_logger Boost) endif() if(BUILD_TESTS) diff --git a/src/components/utils/src/system.cc b/src/components/utils/src/system.cc index 6c3cf561335..a045e063da7 100644 --- a/src/components/utils/src/system.cc +++ b/src/components/utils/src/system.cc @@ -29,34 +29,19 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -#ifdef __QNX__ -#include -#else // __QNX__ -#include -#include -#include -#include -#include -#endif // __QNX__ - -#include -#include -#include -#include +#include +#include +#include #include "utils/logger.h" #include "utils/system.h" +namespace bp = boost::process; // easier access + namespace utils { CREATE_LOGGERPTR_LOCAL(logger_, "Utils") -struct GetCString { - char* operator()(const std::string& string) { - return const_cast(string.c_str()); - } -}; - System::System(const std::string& command) : command_(command) { argv_.push_back(command); } @@ -83,94 +68,50 @@ bool System::Execute() { return Execute(false); } -#ifdef __QNX__ - bool System::Execute(bool wait) { - size_t size = argv_.size(); - char** argv = new char* [size + 1]; - std::transform(argv_.begin(), argv_.end(), argv, GetCString()); - argv[size] = NULL; - - int mode = wait ? P_WAIT : P_NOWAIT; - int ret = spawnvp(mode, command_.c_str(), argv); - delete[] argv; + // Empty command does nothing + if (command_.empty()) { + if (wait) { + // we couldn't wait for the command because it didn't exists + return false; + } else { + // we don't care if it ran, so return true + // This is to maintain compatibility with pre-boost API + return true; + } + } - if (ret == -1) { + // for some reason boost.process uses STL error codes + std::error_code ec; + // launch new process with no I/O, can optionally wait + bp::child c(command_, + argv_, + bp::std_out > bp::null, + bp::std_in bp::null, + ec); + + // Catch errors + if (ec) { LOG4CXX_ERROR(logger_, - "Can't execute command: " << command_ << " Errno is: " - << std::strerror(errno)); + "Can't execute command: " << command_ << " Error message is: " + << ec.message()); return false; } if (wait) { - return WEXITSTATUS(ret) == 0; - } - - return true; -} - -#else // __QNX__ - -bool System::Execute(bool wait) { - // Create a child process. - pid_t pid_command = fork(); - - switch (pid_command) { - case -1: { // Error - LOG4CXX_FATAL(logger_, "fork() failed!"); + c.wait(ec); // wait for the process to exit + if (ec) { + LOG4CXX_ERROR(logger_, + "Failed to wait for command: " + << command_ << " Error message is: " << ec.message()); return false; } - case 0: { // Child process - int32_t fd_dev0 = open("/dev/null", O_RDWR, S_IWRITE); - if (0 > fd_dev0) { - LOG4CXX_FATAL(logger_, "Open dev0 failed!"); - return false; - } - // close input/output file descriptors. - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - - // move input/output to /dev/null. - dup2(fd_dev0, STDIN_FILENO); - dup2(fd_dev0, STDOUT_FILENO); - dup2(fd_dev0, STDERR_FILENO); - - size_t size = argv_.size(); - char** argv = new char* [size + 1]; - std::transform(argv_.begin(), argv_.end(), argv, GetCString()); - argv[size] = NULL; - - // Execute the program. - if (execvp(command_.c_str(), argv) == -1) { - LOG4CXX_ERROR(logger_, "Can't execute command: " << command_); - _exit(EXIT_FAILURE); - } - delete[] argv; - - return true; - } - default: { /* Parent process */ - LOG4CXX_INFO(logger_, "Process created with pid " << pid_command); - if (wait) { - int status; - pid_t wait_pid; - do { - wait_pid = waitpid(pid_command, &status, WUNTRACED | WCONTINUED); - if (wait_pid == -1) { - LOG4CXX_ERROR_WITH_ERRNO(logger_, "Can't wait"); - _exit(EXIT_FAILURE); - return false; - } - } while (!WIFEXITED(status) && !WIFSIGNALED(status)); - return WEXITSTATUS(status) == 0; - } - - return true; - } + // did the child run successfully and exit cleanly? + return c.exit_code() == 0; } -} -#endif // __QNX__ + // if we got this far everything went well + return true; +} -} // utils +} // namespace utils