1 // Copyright (c) 2019 Klemens D. Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
7 #define BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
8
9 #include <vector>
10 #include <system_error>
11 #include <dirent.h>
12 #include <sys/stat.h>
13 #include <algorithm>
14 #include <boost/process/detail/posix/handler.hpp>
15
16 namespace boost { namespace process { namespace detail { namespace posix {
17
18
19 using native_handle_type = int;
20
get_handles(std::error_code & ec)21 inline std::vector<native_handle_type> get_handles(std::error_code & ec)
22 {
23 std::vector<native_handle_type> res;
24
25 std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
26 if (!dir)
27 {
28 ec = ::boost::process::detail::get_last_error();
29 return {};
30 }
31 else
32 ec.clear();
33
34 auto my_fd = ::dirfd(dir.get());
35
36 struct ::dirent * ent_p;
37
38 while ((ent_p = readdir(dir.get())) != nullptr)
39 {
40 if (ent_p->d_name[0] == '.')
41 continue;
42
43 const auto conv = std::atoi(ent_p->d_name);
44 if (conv == 0 && (ent_p->d_name[0] != '0' && ent_p->d_name[1] != '\0'))
45 continue;
46
47 if (conv == my_fd)
48 continue;
49
50 res.push_back(conv);
51 }
52 return res;
53 }
54
get_handles()55 inline std::vector<native_handle_type> get_handles()
56 {
57 std::error_code ec;
58
59 auto res = get_handles(ec);
60 if (ec)
61 boost::process::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
62
63 return res;
64 }
65
66
is_stream_handle(native_handle_type handle,std::error_code & ec)67 inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
68 {
69 struct ::stat stat_;
70
71 if (::fstat(handle, &stat_) != 0)
72 {
73 ec = ::boost::process::detail::get_last_error();
74 }
75 else
76 ec.clear();
77
78 return S_ISCHR (stat_.st_mode) //This macro returns non-zero if the file is a character special file (a device like a terminal).
79 || S_ISBLK (stat_.st_mode) // This macro returns non-zero if the file is a block special file (a device like a disk).
80 || S_ISREG (stat_.st_mode) // This macro returns non-zero if the file is a regular file.
81 || S_ISFIFO (stat_.st_mode) // This macro returns non-zero if the file is a FIFO special file, or a pipe. See section 15. Pipes and FIFOs.
82 || S_ISSOCK (stat_.st_mode) ;// This macro returns non-zero if the file is a socket. See section 16. Sockets.;
83 }
84
85
is_stream_handle(native_handle_type handle)86 inline bool is_stream_handle(native_handle_type handle)
87 {
88 std::error_code ec;
89 auto res = is_stream_handle(handle, ec);
90 if (ec)
91 boost::process::detail::throw_error(ec, "fstat() failed");
92
93 return res;
94 }
95
96 struct limit_handles_ : handler_base_ext
97 {
limit_handles_boost::process::detail::posix::limit_handles_98 limit_handles_() {}
~limit_handles_boost::process::detail::posix::limit_handles_99 ~limit_handles_() {}
100 mutable std::vector<int> used_handles;
101
102 template<typename Executor>
on_setupboost::process::detail::posix::limit_handles_103 void on_setup(Executor & exec) const
104 {
105 used_handles = get_used_handles(exec);
106 }
107
108 template<typename Executor>
on_exec_setupboost::process::detail::posix::limit_handles_109 void on_exec_setup(Executor & exec) const
110 {
111 auto dir = ::opendir("/dev/fd");
112 if (!dir)
113 {
114 exec.set_error(::boost::process::detail::get_last_error(), "opendir(\"/dev/fd\")");
115 return;
116 }
117
118 auto my_fd = ::dirfd(dir);
119 struct ::dirent * ent_p;
120
121 while ((ent_p = readdir(dir)) != nullptr)
122 {
123 if (ent_p->d_name[0] == '.')
124 continue;
125
126 const auto conv = std::atoi(ent_p->d_name);
127
128 if ((conv == my_fd) || (conv == -1))
129 continue;
130
131 if (std::find(used_handles.begin(), used_handles.end(), conv) != used_handles.end())
132 continue;
133
134 if (::close(conv) != 0)
135 {
136 exec.set_error(::boost::process::detail::get_last_error(), "close() failed");
137 return;
138 }
139 }
140 ::closedir(dir);
141 }
142 };
143
144 }}}}
145
146 #endif //PROCESS_HANDLES_HPP
147