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 // Copyright (c) 2016 Klemens D. Morgenstern
7 //
8 // Distributed under the Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 
11 /**
12  * \file boost/process/system.hpp
13  *
14  * Defines a system function.
15  */
16 
17 #ifndef BOOST_PROCESS_SYSTEM_HPP
18 #define BOOST_PROCESS_SYSTEM_HPP
19 
20 #include <boost/process/detail/config.hpp>
21 #include <boost/process/detail/on_exit.hpp>
22 #include <boost/process/child.hpp>
23 #include <boost/process/detail/async_handler.hpp>
24 #include <boost/process/detail/execute_impl.hpp>
25 #include <boost/asio/post.hpp>
26 #include <type_traits>
27 #include <mutex>
28 #include <condition_variable>
29 
30 #if defined(BOOST_POSIX_API)
31 #include <boost/process/posix.hpp>
32 #endif
33 
34 namespace boost {
35 
36 namespace process {
37 
38 namespace detail
39 {
40 
41 struct system_impl_success_check : handler
42 {
43     bool succeeded = false;
44 
45     template<typename Exec>
on_successboost::process::detail::system_impl_success_check46     void on_success(Exec &) { succeeded = true; }
47 };
48 
49 template<typename IoService, typename ...Args>
system_impl(std::true_type,std::true_type,Args &&...args)50 inline int system_impl(
51         std::true_type, /*needs ios*/
52         std::true_type, /*has io_context*/
53         Args && ...args)
54 {
55     IoService & ios = ::boost::process::detail::get_io_context_var(args...);
56 
57     system_impl_success_check check;
58 
59     std::atomic_bool exited{false};
60 
61     child c(std::forward<Args>(args)...,
62             check,
63             ::boost::process::on_exit(
64                 [&](int, const std::error_code&)
65                 {
66                     boost::asio::post(ios.get_executor(), [&]{exited.store(true);});
67                 }));
68     if (!c.valid() || !check.succeeded)
69         return -1;
70 
71     while (!exited.load())
72         ios.poll();
73 
74     return c.exit_code();
75 }
76 
77 template<typename IoService, typename ...Args>
system_impl(std::true_type,std::false_type,Args &&...args)78 inline int system_impl(
79         std::true_type,  /*needs ios */
80         std::false_type, /*has io_context*/
81         Args && ...args)
82 {
83     IoService ios;
84     child c(ios, std::forward<Args>(args)...);
85     if (!c.valid())
86         return -1;
87 
88     ios.run();
89     if (c.running())
90         c.wait();
91     return c.exit_code();
92 }
93 
94 
95 template<typename IoService, typename ...Args>
system_impl(std::false_type,std::true_type,Args &&...args)96 inline int system_impl(
97         std::false_type, /*needs ios*/
98         std::true_type, /*has io_context*/
99         Args && ...args)
100 {
101     child c(std::forward<Args>(args)...);
102     if (!c.valid())
103         return -1;
104     c.wait();
105     return c.exit_code();
106 }
107 
108 template<typename IoService, typename ...Args>
system_impl(std::false_type,std::false_type,Args &&...args)109 inline int system_impl(
110         std::false_type, /*has async */
111         std::false_type, /*has io_context*/
112         Args && ...args)
113 {
114     child c(std::forward<Args>(args)...
115 #if defined(BOOST_POSIX_API)
116             ,::boost::process::posix::sig.dfl()
117 #endif
118             );
119     if (!c.valid())
120         return -1;
121     c.wait();
122     return c.exit_code();
123 }
124 
125 }
126 
127 /** Launches a process and waits for its exit.
128 It works as std::system, though it allows
129 all the properties boost.process provides. It will execute the process and wait for it's exit; then return the exit_code.
130 
131 \code{.cpp}
132 int ret = system("ls");
133 \endcode
134 
135 \attention Using this function with synchronous pipes leads to many potential deadlocks.
136 
137 When using this function with an asynchronous properties and NOT passing an io_context object,
138 the system function will create one and run it. When the io_context is passed to the function,
139 the system function will check if it is active, and call the io_context::run function if not.
140 
141 */
142 template<typename ...Args>
system(Args &&...args)143 inline int system(Args && ...args)
144 {
145     typedef typename ::boost::process::detail::needs_io_context<Args...>::type
146             need_ios;
147     typedef typename ::boost::process::detail::has_io_context<Args...>::type
148             has_ios;
149     return ::boost::process::detail::system_impl<boost::asio::io_context>(
150             need_ios(), has_ios(),
151             std::forward<Args>(args)...);
152 }
153 
154 
155 }}
156 #endif
157 
158