24 #include <core/exception.h>
26 #include <boost/bind.hpp>
29 # include <libdaemon/dfork.h>
31 #include <sys/types.h>
59 : progname_(progname),
60 io_service_work_(io_service_),
62 sd_stdin_(io_service_),
63 sd_stdout_(io_service_),
64 sd_stderr_(io_service_),
67 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
68 run_proc(file, argv, envp);
86 : progname_(progname),
87 io_service_work_(io_service_),
89 sd_stdin_(io_service_),
90 sd_stdout_(io_service_),
91 sd_stderr_(io_service_),
94 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
95 run_proc(file, argv, envp);
108 const std::string & file,
109 const std::vector<std::string> &argv,
110 const std::vector<std::string> &envp)
111 : progname_(progname),
112 io_service_work_(io_service_),
114 sd_stdin_(io_service_),
115 sd_stdout_(io_service_),
116 sd_stderr_(io_service_),
119 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
121 const char *argvc[argv.size() + 1];
122 for (
size_t i = 0; i < argv.size(); ++i) {
123 argvc[i] = argv[i].c_str();
125 argvc[argv.size()] = NULL;
126 const char *envpc[envp.size() + 1];
127 for (
size_t i = 0; i < envp.size(); ++i) {
128 envpc[i] = envp[i].c_str();
130 envpc[envp.size()] = NULL;
131 run_proc(file.c_str(), argvc, envpc);
145 const std::string & file,
146 const std::vector<std::string> &argv,
147 const std::vector<std::string> &envp,
149 : progname_(progname),
150 io_service_work_(io_service_),
152 sd_stdin_(io_service_),
153 sd_stdout_(io_service_),
154 sd_stderr_(io_service_),
157 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
159 const char *argvc[argv.size() + 1];
160 for (
size_t i = 0; i < argv.size(); ++i) {
161 argvc[i] = argv[i].c_str();
163 argvc[argv.size()] = NULL;
165 run_proc(file.c_str(), argvc, NULL);
167 const char *envpc[envp.size() + 1];
168 for (
size_t i = 0; i < envp.size(); ++i) {
169 envpc[i] = envp[i].c_str();
171 envpc[envp.size()] = NULL;
172 run_proc(file.c_str(), argvc, envpc);
181 io_service_thread_.join();
195 SubProcess::run_proc(
const char *file,
206 if (pipe(pipe_stdin) < 0) {
207 throw Exception(errno,
"Failed to create OpenPRS stdin pipe (%s)", file);
209 if (pipe(pipe_stdout) < 0) {
210 close(pipe_stdin[0]);
211 close(pipe_stdin[1]);
212 throw Exception(errno,
"Failed to create OpenPRS stdout pipe (%s)", file);
214 if (pipe(pipe_stderr) < 0) {
215 close(pipe_stdin[0]);
216 close(pipe_stdin[1]);
217 close(pipe_stdout[0]);
218 close(pipe_stdout[1]);
219 throw Exception(errno,
"Failed to create OpenPRS stderr pipe (%s)", file);
224 close(pipe_stdin[0]);
225 close(pipe_stdin[1]);
226 close(pipe_stdout[0]);
227 close(pipe_stdout[1]);
228 close(pipe_stderr[0]);
229 close(pipe_stderr[1]);
230 throw Exception(errno,
"Failed to fork for OpenPRS %s", file);
232 close(pipe_stdin[0]);
233 close(pipe_stdout[1]);
234 close(pipe_stderr[1]);
242 #ifdef HAVE_LIBDAEMON
243 daemon_close_all(STDIN_FILENO,
252 if (dup2(pipe_stdin[0], STDIN_FILENO) == -1) {
253 perror(
"Failed to dup stdin");
256 if (dup2(pipe_stdout[1], STDOUT_FILENO) == -1) {
257 perror(
"Failed to dup stdout");
260 if (dup2(pipe_stderr[1], STDERR_FILENO) == -1) {
261 perror(
"Failed to dup stderr");
265 close(pipe_stdin[0]);
266 close(pipe_stdout[0]);
267 close(pipe_stderr[0]);
268 close(pipe_stdin[1]);
269 close(pipe_stdout[1]);
270 close(pipe_stderr[1]);
274 execve(file, (
char *
const *)argv, (
char *
const *)envp);
276 execv(file, (
char *
const *)argv);
279 execvpe(file, (
char *
const *)argv, envp ? (
char *
const *)envp : environ);
283 perror(
"Failed to execute command");
289 SubProcess::run_proc(
const char *file,
const char *argv[],
const char *envp[])
291 pid_ = run_proc(file, argv, envp, pipe_stdin_w_, pipe_stdout_r_, pipe_stderr_r_);
293 sd_stdin_.assign(dup(pipe_stdin_w_));
294 sd_stdout_.assign(dup(pipe_stdout_r_));
295 sd_stderr_.assign(dup(pipe_stderr_r_));
298 start_log(progname_.c_str(),
Logger::LL_INFO, sd_stdout_, buf_stdout_);
299 start_log(progname_.c_str(),
Logger::LL_WARN, sd_stderr_, buf_stderr_);
304 SubProcess::start_log(
const char * logname,
306 boost::asio::posix::stream_descriptor &sd,
307 boost::asio::streambuf & buf)
309 boost::asio::async_read_until(sd,
312 boost::bind(&SubProcess::handle_log_line,
318 boost::asio::placeholders::error,
319 boost::asio::placeholders::bytes_transferred));
323 SubProcess::handle_log_line(
const char * logname,
325 boost::asio::posix::stream_descriptor &sd,
326 boost::asio::streambuf & buf,
327 boost::system::error_code ec,
331 if (ec == boost::asio::error::eof) {
336 "Failed to read log line %i (%s), continuing",
338 ec.message().c_str());
342 std::istream in_stream(&buf);
343 std::getline(in_stream, line);
344 logger_->
log(log_level, logname,
"%s", line.c_str());
346 start_log(logname, log_level, sd, buf);
368 throw Exception(
"Cannot get status while process still alive");
379 if (waitpid(pid_, &status, WUNTRACED | WCONTINUED | WNOHANG) > 0) {
380 if (WIFEXITED(status)) {
381 exit_status_ = WEXITSTATUS(status);
382 if (exit_status_ != 0) {
384 "PID %i exited, status=%d",
386 WEXITSTATUS(status));
389 }
else if (WIFSIGNALED(status)) {
391 "PID %i killed by signal %s",
393 strsignal(WTERMSIG(status)));
395 }
else if (WIFSTOPPED(status)) {
396 logger_->
log_warn(progname_.c_str(),
397 "PID %i stopped by signal %s",
399 strsignal(WSTOPSIG(status)));
400 }
else if (WIFCONTINUED(status)) {
401 logger_->
log_warn(progname_.c_str(),
"PID %i continued", pid_);