24 #include <core/exception.h> 26 #include <boost/bind.hpp> 29 # include <libdaemon/dfork.h> 31 #include <sys/types.h> 57 : progname_(progname),
58 io_service_work_(io_service_), logger_(NULL),
59 sd_stdin_(io_service_), sd_stdout_(io_service_), sd_stderr_(io_service_)
61 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
62 run_proc(file, argv, envp);
78 : progname_(progname),
79 io_service_work_(io_service_), logger_(logger),
80 sd_stdin_(io_service_), sd_stdout_(io_service_), sd_stderr_(io_service_)
82 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
83 run_proc(file, argv, envp);
92 io_service_thread_.join();
102 if (pid_ > 0)
::kill(pid_, signum);
107 SubProcess::run_proc(
const char *file,
const char *argv[],
const char *envp[],
114 if (pipe(pipe_stdin) < 0) {
115 throw Exception(errno,
"Failed to create OpenPRS stdin pipe (%s)", file);
117 if (pipe(pipe_stdout) < 0) {
118 close(pipe_stdin[0]);
119 close(pipe_stdin[1]);
120 throw Exception(errno,
"Failed to create OpenPRS stdout pipe (%s)", file);
122 if (pipe(pipe_stderr) < 0) {
123 close(pipe_stdin[0]);
124 close(pipe_stdin[1]);
125 close(pipe_stdout[0]);
126 close(pipe_stdout[1]);
127 throw Exception(errno,
"Failed to create OpenPRS stderr pipe (%s)", file);
132 close(pipe_stdin[0]);
133 close(pipe_stdin[1]);
134 close(pipe_stdout[0]);
135 close(pipe_stdout[1]);
136 close(pipe_stderr[0]);
137 close(pipe_stderr[1]);
138 throw Exception(errno,
"Failed to fork for OpenPRS %s", file);
140 close(pipe_stdin[0]);
141 close(pipe_stdout[1]);
142 close(pipe_stderr[1]);
146 pipe_stderr_r = pipe_stderr[0];
150 #ifdef HAVE_LIBDAEMON 151 daemon_close_all(STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
152 pipe_stdin[0], pipe_stdout[1], pipe_stderr[1], -1);
155 if (dup2(pipe_stdin[0], STDIN_FILENO) == -1) {
156 perror(
"Failed to dup stdin");
159 if (dup2(pipe_stdout[1], STDOUT_FILENO) == -1) {
160 perror(
"Failed to dup stdout");
163 if (dup2(pipe_stderr[1], STDERR_FILENO) == -1) {
164 perror(
"Failed to dup stderr");
168 close(pipe_stdin[0]);
169 close(pipe_stdout[0]);
170 close(pipe_stderr[0]);
171 close(pipe_stdin[1]);
172 close(pipe_stdout[1]);
173 close(pipe_stderr[1]);
175 execvpe(file, (
char *
const *)argv, envp ? (
char *
const *)envp : environ);
178 perror(
"Failed to execute command");
185 SubProcess::run_proc(
const char *file,
const char *argv[],
const char *envp[])
187 pid_ = run_proc(file, argv, envp,
188 pipe_stdin_w_, pipe_stdout_r_, pipe_stderr_r_);
190 sd_stdin_.assign(dup(pipe_stdin_w_));
191 sd_stdout_.assign(dup(pipe_stdout_r_));
192 sd_stderr_.assign(dup(pipe_stderr_r_));
195 start_log(progname_.c_str(),
Logger::LL_INFO, sd_stdout_, buf_stdout_);
196 start_log(progname_.c_str(),
Logger::LL_WARN, sd_stderr_, buf_stderr_);
203 boost::asio::posix::stream_descriptor &sd, boost::asio::streambuf &buf)
205 boost::asio::async_read_until(sd, buf,
'\n',
207 &SubProcess::handle_log_line,
this,
208 logname, log_level, boost::ref(sd), boost::ref(buf),
209 boost::asio::placeholders::error,
210 boost::asio::placeholders::bytes_transferred
216 SubProcess::handle_log_line(
const char *logname,
Logger::LogLevel log_level,
217 boost::asio::posix::stream_descriptor &sd, boost::asio::streambuf &buf,
218 boost::system::error_code ec,
size_t bytes_read)
221 if (ec == boost::asio::error::eof) {
225 logger_->
log_error(logname,
"Failed to read log line %i (%s), continuing", ec.value(),
226 ec.message().c_str());
230 std::istream in_stream(&buf);
231 std::getline(in_stream, line);
232 logger_->
log(log_level, logname,
"%s", line.c_str());
234 start_log(logname, log_level, sd, buf);
244 if (waitpid(pid_, &status, WUNTRACED | WCONTINUED | WNOHANG) > 0) {
245 if (WIFEXITED(status)) {
246 logger_->
log_error(progname_.c_str(),
"PID %i exited, status=%d",
247 pid_, WEXITSTATUS(status));
249 }
else if (WIFSIGNALED(status)) {
250 logger_->
log_error(progname_.c_str(),
"PID %i killed by signal %s",
251 pid_, strsignal(WTERMSIG(status)));
253 }
else if (WIFSTOPPED(status)) {
254 logger_->
log_warn(progname_.c_str(),
"PID %i stopped by signal %s",
255 pid_, strsignal(WSTOPSIG(status)));
256 }
else if (WIFCONTINUED(status)) {
257 logger_->
log_warn(progname_.c_str(),
"PID %i continued", pid_);
informational output about normal procedures
SubProcess(const char *progname, const char *file, const char *argv[], const char *envp[])
Constructor.
Fawkes library namespace.
int pipe_stdout_r() const
Get stdout pipe file descriptor.
void kill(int signum)
Send a signal to the process.
warning, should be investigated but software still functions, an example is that something was reques...
void check_proc()
Check if the process is still alive.
int pipe_stderr_r() const
Get stderr pipe file descriptor.
Base class for exceptions in Fawkes.
int pipe_stdin_w() const
Get stdin pipe file descriptor.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
pid_t pid() const
Get PID of sub-process.
virtual void log(LogLevel level, const char *component, const char *format,...)
Log message of given log level.