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