// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph distributed storage system * * Copyright (C) 2015 Mirantis Inc * * Author: Mykola Golub * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ #ifndef SUB_PROCESS_H #define SUB_PROCESS_H #if defined(__FreeBSD__) || defined(__APPLE__) #include #endif #ifndef _WIN32 #include #endif #include #include #include "include/compat.h" /** * SubProcess: * A helper class to spawn a subprocess. * * Example: * * SubProcess cat("cat", SubProcess::PIPE, SubProcess::PIPE); * if (cat.spawn() != 0) { * std::cerr << "cat failed: " << cat.err() << std::endl; * return false; * } * write_to_fd(cat.get_stdout(), "hello world!\n"); * cat.close_stdout(); * read_from_fd(cat.get_stdin(), buf); * if (cat.join() != 0) { * std::cerr << cat.err() << std::endl; * return false; * } */ class SubProcess { public: enum std_fd_op{ KEEP, CLOSE, PIPE }; public: SubProcess(const char *cmd, std_fd_op stdin_op = CLOSE, std_fd_op stdout_op = CLOSE, std_fd_op stderr_op = CLOSE); virtual ~SubProcess(); void add_cmd_args(const char *arg, ...); void add_cmd_arg(const char *arg); virtual int spawn(); // Returns 0 on success or -errno on failure. virtual int join(); // Returns exit code (0 on success). bool is_spawned() const { return pid > 0; } int get_stdin() const; int get_stdout() const; int get_stderr() const; void close_stdin(); void close_stdout(); void close_stderr(); void kill(int signo = SIGTERM) const; const std::string err() const; protected: bool is_child() const { return pid == 0; } virtual void exec(); void close(int &fd); #ifdef _WIN32 void close_h(HANDLE &handle); #endif protected: std::string cmd; std::vector cmd_args; std_fd_op stdin_op; std_fd_op stdout_op; std_fd_op stderr_op; int stdin_pipe_out_fd; int stdout_pipe_in_fd; int stderr_pipe_in_fd; int pid; std::ostringstream errstr; #ifdef _WIN32 HANDLE proc_handle = INVALID_HANDLE_VALUE; #endif }; class SubProcessTimed : public SubProcess { public: SubProcessTimed(const char *cmd, std_fd_op stdin_op = CLOSE, std_fd_op stdout_op = CLOSE, std_fd_op stderr_op = CLOSE, int timeout = 0, int sigkill = SIGKILL); #ifdef _WIN32 int spawn() override; int join() override; #endif protected: void exec() override; private: int timeout; int sigkill; #ifdef _WIN32 std::thread waiter; #endif }; void timeout_sighandler(int sig); #endif