1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
3 // Copyright (c) 2009 Boris Schaeling
4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9
10 #ifndef BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
11 #define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
12
13 #include <boost/process/detail/child_decl.hpp>
14 #include <boost/process/error.hpp>
15 #include <boost/process/pipe.hpp>
16 #include <boost/process/detail/posix/basic_pipe.hpp>
17 #include <boost/process/detail/posix/use_vfork.hpp>
18 #include <boost/fusion/algorithm/iteration/for_each.hpp>
19 #include <cstdlib>
20 #include <sys/types.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <unistd.h>
24
25 #include <boost/algorithm/string/predicate.hpp>
26 #include <boost/algorithm/string/split.hpp>
27 #include <boost/algorithm/string/classification.hpp>
28
29 namespace boost { namespace process { namespace detail { namespace posix {
30
31 template<typename Executor>
32 struct on_setup_t
33 {
34 Executor & exec;
on_setup_tboost::process::detail::posix::on_setup_t35 on_setup_t(Executor & exec) : exec(exec) {};
36 template<typename T>
operator ()boost::process::detail::posix::on_setup_t37 void operator()(T & t) const
38 {
39 if (!exec.error())
40 t.on_setup(exec);
41 }
42 };
43
44 template<typename Executor>
45 struct on_error_t
46 {
47 Executor & exec;
48 const std::error_code & error;
on_error_tboost::process::detail::posix::on_error_t49 on_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
50 template<typename T>
operator ()boost::process::detail::posix::on_error_t51 void operator()(T & t) const
52 {
53 t.on_error(exec, error);
54 }
55 };
56
57 template<typename Executor>
58 struct on_success_t
59 {
60 Executor & exec;
on_success_tboost::process::detail::posix::on_success_t61 on_success_t(Executor & exec) : exec(exec) {};
62 template<typename T>
operator ()boost::process::detail::posix::on_success_t63 void operator()(T & t) const {t.on_success(exec);}
64 };
65
66
67
68 template<typename Executor>
69 struct on_fork_error_t
70 {
71 Executor & exec;
72 const std::error_code & error;
on_fork_error_tboost::process::detail::posix::on_fork_error_t73 on_fork_error_t(Executor & exec, const std::error_code & error) : exec(exec), error(error) {};
74
75 template<typename T>
operator ()boost::process::detail::posix::on_fork_error_t76 void operator()(T & t) const
77 {
78 t.on_fork_error(exec, error);
79 }
80 };
81
82
83 template<typename Executor>
84 struct on_exec_setup_t
85 {
86 Executor & exec;
on_exec_setup_tboost::process::detail::posix::on_exec_setup_t87 on_exec_setup_t(Executor & exec) : exec(exec) {};
88
89 template<typename T>
operator ()boost::process::detail::posix::on_exec_setup_t90 void operator()(T & t) const
91 {
92 t.on_exec_setup(exec);
93 }
94 };
95
96
97 template<typename Executor>
98 struct on_exec_error_t
99 {
100 Executor & exec;
101 const std::error_code &ec;
on_exec_error_tboost::process::detail::posix::on_exec_error_t102 on_exec_error_t(Executor & exec, const std::error_code & error) : exec(exec), ec(error) {};
103
104 template<typename T>
operator ()boost::process::detail::posix::on_exec_error_t105 void operator()(T & t) const
106 {
107 t.on_exec_error(exec, ec);
108 }
109 };
110
111 template<typename Executor>
112 struct on_fork_success_t
113 {
114 Executor & exec;
on_fork_success_tboost::process::detail::posix::on_fork_success_t115 on_fork_success_t(Executor & exec) : exec(exec) {};
116
117 template<typename T>
operator ()boost::process::detail::posix::on_fork_success_t118 void operator()(T & t) const
119 {
120 t.on_fork_success(exec);
121 }
122 };
123
call_on_setup(Executor & exec)124 template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
call_on_error(Executor & exec,const std::error_code & ec)125 template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
126 {
127 return on_error_t<Executor> (exec, ec);
128 }
call_on_success(Executor & exec)129 template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
130
call_on_fork_error(Executor & exec,const std::error_code & ec)131 template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
132 {
133 return on_fork_error_t<Executor> (exec, ec);
134 }
135
136
call_on_exec_setup(Executor & exec)137 template<typename Executor> on_exec_setup_t <Executor> call_on_exec_setup (Executor & exec) {return exec;}
call_on_exec_error(Executor & exec,const std::error_code & ec)138 template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec)
139 {
140 return on_exec_error_t<Executor> (exec, ec);
141 }
142
143
144 template<typename Sequence>
145 class executor
146 {
147 template<typename HasHandler, typename UseVFork>
internal_error_handle(const std::error_code &,const char *,HasHandler,boost::mpl::true_,UseVFork)148 void internal_error_handle(const std::error_code&, const char*, HasHandler, boost::mpl::true_, UseVFork) {}
149
150 int _pipe_sink = -1;
151
write_error(const std::error_code & ec,const char * msg)152 void write_error(const std::error_code & ec, const char * msg)
153 {
154 //I am the child
155 int len = ec.value();
156 ::write(_pipe_sink, &len, sizeof(int));
157
158 len = std::strlen(msg) + 1;
159 ::write(_pipe_sink, &len, sizeof(int));
160 ::write(_pipe_sink, msg, len);
161 }
162
internal_error_handle(const std::error_code & ec,const char * msg,boost::mpl::true_,boost::mpl::false_,boost::mpl::false_)163 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
164 {
165 if (this->pid == 0) //on the fork.
166 write_error(ec, msg);
167 else
168 {
169 this->_ec = ec;
170 this->_msg = msg;
171 }
172 }
internal_error_handle(const std::error_code & ec,const char * msg,boost::mpl::false_,boost::mpl::false_,boost::mpl::false_)173 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::false_)
174 {
175 if (this->pid == 0)
176 write_error(ec, msg);
177 else
178 throw process_error(ec, msg);
179 }
180
181
internal_error_handle(const std::error_code & ec,const char * msg,boost::mpl::true_,boost::mpl::false_,boost::mpl::true_)182 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::true_)
183 {
184 this->_ec = ec;
185 this->_msg = msg;
186 }
internal_error_handle(const std::error_code & ec,const char * msg,boost::mpl::false_,boost::mpl::false_,boost::mpl::true_)187 void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::false_, boost::mpl::true_)
188 {
189 if (this->pid == 0)
190 {
191 this->_ec = ec;
192 this->_msg = msg;
193 }
194 else
195 throw process_error(ec, msg);
196 }
197
check_error(boost::mpl::true_)198 void check_error(boost::mpl::true_) {};
check_error(boost::mpl::false_)199 void check_error(boost::mpl::false_)
200 {
201 if (_ec)
202 throw process_error(_ec, _msg);
203 }
204
205 typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
206 typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
207 typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
208
209 inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
210 inline child invoke(boost::mpl::false_, boost::mpl::true_ );
211 inline child invoke(boost::mpl::true_ , boost::mpl::false_ );
212 inline child invoke(boost::mpl::false_, boost::mpl::false_ );
_write_error(int sink)213 void _write_error(int sink)
214 {
215 int data[2] = {_ec.value(),static_cast<int>(_msg.size())};
216 while (::write(sink, &data[0], sizeof(int) *2) == -1)
217 {
218 auto err = errno;
219
220 if (err == EBADF)
221 return;
222 else if ((err != EINTR) && (err != EAGAIN))
223 break;
224 }
225 while (::write(sink, &_msg.front(), _msg.size()) == -1)
226 {
227 auto err = errno;
228
229 if (err == EBADF)
230 return;
231 else if ((err != EINTR) && (err != EAGAIN))
232 break;
233 }
234 }
235
_read_error(int source)236 void _read_error(int source)
237 {
238 int data[2];
239
240 _ec.clear();
241 int count = 0;
242 while ((count = ::read(source, &data[0], sizeof(int) *2 ) ) == -1)
243 {
244 //actually, this should block until it's read.
245 auto err = errno;
246 if ((err != EAGAIN ) && (err != EINTR))
247 set_error(std::error_code(err, std::system_category()), "Error read pipe");
248 }
249 if (count == 0)
250 return ;
251
252 std::error_code ec(data[0], std::system_category());
253 std::string msg(data[1], ' ');
254
255 while (::read(source, &msg.front(), msg.size() ) == -1)
256 {
257 //actually, this should block until it's read.
258 auto err = errno;
259 if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
260 return;
261 //EAGAIN not yet forked, EINTR interrupted, i.e. try again
262 else if ((err != EAGAIN ) && (err != EINTR))
263 set_error(std::error_code(err, std::system_category()), "Error read pipe");
264 }
265 set_error(ec, std::move(msg));
266 }
267
268 std::string prepare_cmd_style_fn; //buffer
269
prepare_cmd_style()270 inline void prepare_cmd_style() //this does what execvpe does - but we execute it in the father process, to avoid allocations.
271 {
272 //use my own implementation
273 prepare_cmd_style_fn = exe;
274 if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
275 {
276 auto e = ::environ;
277 while ((*e != nullptr) && !boost::starts_with(*e, "PATH="))
278 e++;
279
280 if (e != nullptr)
281 {
282 std::vector<std::string> path;
283 boost::split(path, *e, boost::is_any_of(":"));
284
285 for (const std::string & pp : path)
286 {
287 auto p = pp + "/" + exe;
288 if (!::access(p.c_str(), X_OK))
289 {
290 prepare_cmd_style_fn = p;
291 break;
292 }
293 }
294 }
295 }
296 exe = prepare_cmd_style_fn.c_str();
297 }
298
299 std::error_code _ec;
300 std::string _msg;
301 public:
executor(Sequence & seq)302 executor(Sequence & seq) : seq(seq)
303 {
304 }
305
operator ()()306 child operator()()
307 {
308 return invoke(has_ignore_error(), shall_use_vfork());
309 }
310
311
312 Sequence & seq;
313 const char * exe = nullptr;
314 char *const* cmd_line = nullptr;
315 bool cmd_style = false;
316 char **env = ::environ;
317 pid_t pid = -1;
318 std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
319
error() const320 const std::error_code & error() const {return _ec;}
321
set_error(const std::error_code & ec,const char * msg)322 void set_error(const std::error_code &ec, const char* msg)
323 {
324 internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork());
325 }
set_error(const std::error_code & ec,const std::string & msg)326 void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
327
328 };
329
330 template<typename Sequence>
invoke(boost::mpl::true_,boost::mpl::false_)331 child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore errors
332 {
333 boost::fusion::for_each(seq, call_on_setup(*this));
334 if (_ec)
335 return child();
336 if (cmd_style)
337 prepare_cmd_style();
338
339 this->pid = ::fork();
340 if (pid == -1)
341 {
342 auto ec = boost::process::detail::get_last_error();
343 boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
344 return child();
345 }
346 else if (pid == 0)
347 {
348 boost::fusion::for_each(seq, call_on_exec_setup(*this));
349 ::execve(exe, cmd_line, env);
350 auto ec = boost::process::detail::get_last_error();
351 boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
352 _exit(EXIT_FAILURE);
353 }
354
355 child c(child_handle(pid), exit_status);
356
357 boost::fusion::for_each(seq, call_on_success(*this));
358
359 return c;
360 }
361
362 template<typename Sequence>
invoke(boost::mpl::false_,boost::mpl::false_)363 child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
364 {
365 {
366 struct pipe_guard
367 {
368 int p[2];
369 pipe_guard() : p{-1,-1} {}
370
371 ~pipe_guard()
372 {
373 if (p[0] != -1)
374 ::close(p[0]);
375 if (p[1] != -1)
376 ::close(p[1]);
377 }
378 } p{};
379
380 if (::pipe(p.p) == -1)
381 {
382 set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
383 return child();
384 }
385 if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1)
386 {
387 auto err = ::boost::process::detail::get_last_error();
388 set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe.
389 return child();
390 }
391 _ec.clear();
392 boost::fusion::for_each(seq, call_on_setup(*this));
393
394 if (_ec)
395 {
396 boost::fusion::for_each(seq, call_on_error(*this, _ec));
397 return child();
398 }
399
400 if (cmd_style)
401 prepare_cmd_style();
402
403 this->pid = ::fork();
404 if (pid == -1)
405 {
406 _ec = boost::process::detail::get_last_error();
407 _msg = "fork() failed";
408 boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
409 boost::fusion::for_each(seq, call_on_error(*this, _ec));
410 return child();
411 }
412 else if (pid == 0)
413 {
414 _pipe_sink = p.p[1];
415 ::close(p.p[0]);
416
417 boost::fusion::for_each(seq, call_on_exec_setup(*this));
418 ::execve(exe, cmd_line, env);
419 _ec = boost::process::detail::get_last_error();
420 _msg = "execve failed";
421 boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
422
423 _write_error(_pipe_sink);
424 ::close(p.p[1]);
425
426 _exit(EXIT_FAILURE);
427 return child();
428 }
429
430 ::close(p.p[1]);
431 p.p[1] = -1;
432 _read_error(p.p[0]);
433
434 }
435 if (_ec)
436 {
437 boost::fusion::for_each(seq, call_on_error(*this, _ec));
438 return child();
439 }
440
441 child c(child_handle(pid), exit_status);
442
443 boost::fusion::for_each(seq, call_on_success(*this));
444
445 if (_ec)
446 {
447 boost::fusion::for_each(seq, call_on_error(*this, _ec));
448 return child();
449 }
450
451 return c;
452 }
453
454 #if BOOST_POSIX_HAS_VFORK
455
456
457 template<typename Sequence>
invoke(boost::mpl::true_,boost::mpl::true_)458 child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore errors
459 {
460 boost::fusion::for_each(seq, call_on_setup(*this));
461 if (_ec)
462 return child();
463 this->pid = ::vfork();
464 if (pid == -1)
465 {
466 auto ec = boost::process::detail::get_last_error();
467 boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
468 return child();
469 }
470 else if (pid == 0)
471 {
472 boost::fusion::for_each(seq, call_on_exec_setup(*this));
473 ::execve(exe, cmd_line, env);
474 auto ec = boost::process::detail::get_last_error();
475 boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
476 _exit(EXIT_FAILURE);
477 }
478 child c(child_handle(pid), exit_status);
479
480 boost::fusion::for_each(seq, call_on_success(*this));
481
482 return c;
483 }
484
485 template<typename Sequence>
invoke(boost::mpl::false_,boost::mpl::true_)486 child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
487 {
488 boost::fusion::for_each(seq, call_on_setup(*this));
489
490 if (_ec)
491 {
492 boost::fusion::for_each(seq, call_on_error(*this, _ec));
493 return child();
494 }
495 _ec.clear();
496 if (cmd_style)
497 this->prepare_cmd_style();
498
499 this->pid = ::vfork();
500 if (pid == -1)
501 {
502 _ec = boost::process::detail::get_last_error();
503 _msg = "fork() failed";
504 boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
505 boost::fusion::for_each(seq, call_on_error(*this, _ec));
506
507 return child();
508 }
509 else if (pid == 0)
510 {
511 boost::fusion::for_each(seq, call_on_exec_setup(*this));
512
513 ::execve(exe, cmd_line, env);
514
515 _ec = boost::process::detail::get_last_error();
516 _msg = "execve failed";
517 boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
518
519 _exit(EXIT_FAILURE);
520 return child();
521 }
522 child c(child_handle(pid), exit_status);
523
524 check_error(has_error_handler());
525
526
527
528 if (_ec)
529 {
530 boost::fusion::for_each(seq, call_on_error(*this, _ec));
531 return child();
532 }
533 else
534 boost::fusion::for_each(seq, call_on_success(*this));
535
536 if (_ec)
537 {
538 boost::fusion::for_each(seq, call_on_error(*this, _ec));
539 return child();
540 }
541
542 return c;
543 }
544
545 #endif
546
547 template<typename Char, typename Tup>
make_executor(Tup & tup)548 inline executor<Tup> make_executor(Tup & tup)
549 {
550 return executor<Tup>(tup);
551 }
552
553 }}}}
554
555 #endif
556