File indexing completed on 2025-01-18 09:50:06
0001
0002
0003
0004
0005
0006 #ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
0007 #define BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
0008
0009 #include <vector>
0010 #include <system_error>
0011 #include <dirent.h>
0012 #include <sys/stat.h>
0013 #include <algorithm>
0014 #include <memory>
0015 #include <cstdlib>
0016 #include <boost/process/detail/posix/handler.hpp>
0017
0018 namespace boost { namespace process { namespace detail { namespace posix {
0019
0020
0021 using native_handle_type = int;
0022
0023 inline std::vector<native_handle_type> get_handles(std::error_code & ec)
0024 {
0025 std::vector<native_handle_type> res;
0026
0027 std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
0028 if (!dir)
0029 {
0030 ec = ::boost::process::detail::get_last_error();
0031 return {};
0032 }
0033 else
0034 ec.clear();
0035
0036 auto my_fd = dirfd(dir.get());
0037
0038 struct ::dirent * ent_p;
0039
0040 while ((ent_p = readdir(dir.get())) != nullptr)
0041 {
0042 if (ent_p->d_name[0] == '.')
0043 continue;
0044
0045 const auto conv = std::atoi(ent_p->d_name);
0046 if (conv == 0 && (ent_p->d_name[0] != '0' && ent_p->d_name[1] != '\0'))
0047 continue;
0048
0049 if (conv == my_fd)
0050 continue;
0051
0052 res.push_back(conv);
0053 }
0054 return res;
0055 }
0056
0057 inline std::vector<native_handle_type> get_handles()
0058 {
0059 std::error_code ec;
0060
0061 auto res = get_handles(ec);
0062 if (ec)
0063 boost::process::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
0064
0065 return res;
0066 }
0067
0068
0069 inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
0070 {
0071 struct ::stat stat_;
0072
0073 if (::fstat(handle, &stat_) != 0)
0074 {
0075 ec = ::boost::process::detail::get_last_error();
0076 }
0077 else
0078 ec.clear();
0079
0080 return S_ISCHR (stat_.st_mode)
0081 || S_ISBLK (stat_.st_mode)
0082 || S_ISREG (stat_.st_mode)
0083 || S_ISFIFO (stat_.st_mode)
0084 || S_ISSOCK (stat_.st_mode) ;
0085 }
0086
0087
0088 inline bool is_stream_handle(native_handle_type handle)
0089 {
0090 std::error_code ec;
0091 auto res = is_stream_handle(handle, ec);
0092 if (ec)
0093 boost::process::detail::throw_error(ec, "fstat() failed");
0094
0095 return res;
0096 }
0097
0098 struct limit_handles_ : handler_base_ext
0099 {
0100 limit_handles_() {}
0101 ~limit_handles_() {}
0102 mutable std::vector<int> used_handles;
0103
0104 template<typename Executor>
0105 void on_setup(Executor & exec) const
0106 {
0107 used_handles = get_used_handles(exec);
0108 }
0109
0110 template<typename Executor>
0111 void on_exec_setup(Executor & exec) const
0112 {
0113 auto dir = ::opendir("/dev/fd");
0114 if (!dir)
0115 {
0116 exec.set_error(::boost::process::detail::get_last_error(), "opendir(\"/dev/fd\")");
0117 return;
0118 }
0119
0120 auto my_fd = dirfd(dir);
0121 struct ::dirent * ent_p;
0122
0123 while ((ent_p = readdir(dir)) != nullptr)
0124 {
0125 if (ent_p->d_name[0] == '.')
0126 continue;
0127
0128 const auto conv = std::atoi(ent_p->d_name);
0129
0130 if ((conv == my_fd) || (conv == -1))
0131 continue;
0132
0133 if (std::find(used_handles.begin(), used_handles.end(), conv) != used_handles.end())
0134 continue;
0135
0136 if (::close(conv) != 0)
0137 {
0138 exec.set_error(::boost::process::detail::get_last_error(), "close() failed");
0139 return;
0140 }
0141 }
0142 ::closedir(dir);
0143 }
0144 };
0145
0146 }}}}
0147
0148 #endif