File indexing completed on 2025-01-18 09:50:10
0001
0002
0003
0004
0005
0006 #ifndef BOOST_PROCESS_V2_IMPL_CMD_IPP
0007 #define BOOST_PROCESS_V2_IMPL_CMD_IPP
0008
0009 #include <boost/process/v2/detail/config.hpp>
0010 #include <boost/process/v2/detail/last_error.hpp>
0011 #include <boost/process/v2/detail/throw_error.hpp>
0012 #include <boost/process/v2/ext/detail/proc_info.hpp>
0013 #include <boost/process/v2/ext/cmd.hpp>
0014
0015 #if defined(BOOST_PROCESS_V2_WINDOWS)
0016 #include <windows.h>
0017 #include <shellapi.h>
0018 #else
0019 #include <cstdlib>
0020 #endif
0021
0022 #if (defined(__linux__) || defined(__ANDROID__))
0023 #include <cstdio>
0024 #endif
0025
0026 #if defined(__FreeBSD__)
0027 #include <sys/socket.h>
0028 #include <sys/sysctl.h>
0029 #include <sys/param.h>
0030 #include <sys/queue.h>
0031 #include <sys/user.h>
0032 #include <libprocstat.h>
0033 #endif
0034
0035 #if (defined(__DragonFly__) || defined(__OpenBSD__))
0036 #include <sys/types.h>
0037 #include <sys/param.h>
0038 #include <sys/sysctl.h>
0039 #include <sys/user.h>
0040 #include <kvm.h>
0041 #endif
0042
0043 #if defined(__NetBSD__)
0044 #include <sys/types.h>
0045 #include <kvm.h>
0046 #include <sys/param.h>
0047 #include <sys/sysctl.h>
0048 #endif
0049
0050 #if defined(__sun)
0051 #include <sys/types.h>
0052 #include <kvm.h>
0053 #include <sys/param.h>
0054 #include <sys/time.h>
0055 #include <sys/proc.h>
0056 #endif
0057
0058 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0059
0060 struct make_cmd_shell_
0061 {
0062 #if defined(BOOST_PROCESS_V2_WINDOWS)
0063 static shell make(std::wstring data)
0064 {
0065 shell res;
0066 res.input_ = res.buffer_ = std::move(data);
0067 res.parse_();
0068 return res;
0069 }
0070 #else
0071 static shell make(std::string data,
0072 int argc, char ** argv,
0073 void(*free_func)(int, char**))
0074 {
0075 shell res;
0076 res.argc_ = argc;
0077 res.input_ = res.buffer_ = std::move(data);
0078 res.argv_ = argv;
0079 res.free_argv_ = free_func;
0080
0081 return res;
0082 }
0083
0084 static shell clone(char ** cmd)
0085 {
0086 shell res;
0087 res.argc_ = 0;
0088 std::size_t str_lengths = 0;
0089 for (auto c = cmd; *c != nullptr; c++)
0090 {
0091 res.argc_++;
0092 str_lengths += (std::strlen(*c) + 1);
0093 }
0094
0095 res.buffer_.resize(str_lengths);
0096
0097 res.argv_ = new char*[res.argc_ + 1];
0098 res.free_argv_ = +[](int argc, char ** argv) {delete[] argv;};
0099 res.argv_[res.argc_] = nullptr;
0100 auto p = &*res.buffer_.begin();
0101
0102 for (int i = 0; i < res.argc_; i++)
0103 {
0104 const auto ln = std::strlen(cmd[i]);
0105 res.argv_[i] = std::strcpy(p, cmd[i]);
0106 p += (ln + 1);
0107 }
0108
0109 return res;
0110 }
0111
0112 #endif
0113 };
0114
0115 namespace ext {
0116
0117 #if defined(BOOST_PROCESS_V2_WINDOWS)
0118
0119 shell cmd(HANDLE proc, error_code & ec)
0120 {
0121 std::wstring buffer = boost::process::v2::detail::ext::cwd_cmd_from_proc(proc, 0, ec);
0122
0123 if (!ec)
0124 return make_cmd_shell_::make(std::move(buffer));
0125 else
0126 return {};
0127 }
0128
0129 shell cmd(HANDLE proc)
0130 {
0131 boost::system::error_code ec;
0132 auto res = cmd(proc, ec);
0133 if (ec)
0134 detail::throw_error(ec, "cmd");
0135 return res;
0136 }
0137
0138 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0139 {
0140 struct del
0141 {
0142 void operator()(HANDLE h)
0143 {
0144 ::CloseHandle(h);
0145 };
0146 };
0147 std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
0148 if (proc == nullptr)
0149 {
0150 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
0151 return shell{};
0152 }
0153 else
0154 return cmd(proc.get(), ec);
0155
0156 }
0157
0158 #elif (defined(__APPLE__) && defined(__MACH__))
0159
0160 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0161 {
0162 int mib[3] = {CTL_KERN, KERN_ARGMAX, 0};
0163 int argmax = 0;
0164 auto size = sizeof(argmax);
0165 if (sysctl(mib, 2, &argmax, &size, nullptr, 0) == -1)
0166 {
0167 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0168 return {};
0169 }
0170
0171 std::string procargs;
0172 procargs.resize(argmax - 1);
0173 mib[1] = KERN_PROCARGS;
0174 mib[2] = pid;
0175
0176 size = argmax;
0177
0178 if (sysctl(mib, 3, &*procargs.begin(), &size, nullptr, 0) != 0)
0179 {
0180 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0181 return {};
0182 }
0183
0184 int argc = *reinterpret_cast<const int*>(procargs.data());
0185 auto itr = procargs.begin() + sizeof(argc);
0186
0187 std::unique_ptr<char*[]> argv{new char*[argc + 1]};
0188 const auto end = procargs.end();
0189
0190 argv[argc] = nullptr;
0191
0192 for (auto n = 0u; n <= argc; n++)
0193 {
0194 auto e = std::find(itr, end, '\0');
0195 if (e == end && n < argc)
0196 {
0197 BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
0198 return {};
0199 }
0200 argv[n] = &*itr;
0201 itr = e + 1;
0202 }
0203
0204 auto fr_func = +[](int argc, char ** argv) {delete [] argv;};
0205
0206 return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func);
0207 }
0208
0209 #elif (defined(__linux__) || defined(__ANDROID__))
0210
0211 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0212 {
0213 std::string procargs;
0214 procargs.resize(4096);
0215 int f = ::open(("/proc/" + std::to_string(pid) + "/cmdline").c_str(), O_RDONLY);
0216
0217 while (procargs.back() != EOF)
0218 {
0219 auto r = ::read(f, &*(procargs.end() - 4096), 4096);
0220 if (r < 0)
0221 {
0222 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0223 ::close(f);
0224 return {};
0225 }
0226 if (r < 4096)
0227 {
0228 procargs.resize(procargs.size() - 4096 + r);
0229 break;
0230 }
0231 procargs.resize(procargs.size() + 4096);
0232 }
0233 ::close(f);
0234
0235 if (procargs.back() == EOF)
0236 procargs.pop_back();
0237
0238 auto argc = std::count(procargs.begin(), procargs.end(), '\0');
0239
0240 auto itr = procargs.begin();
0241
0242 std::unique_ptr<char*[]> argv{new char*[argc + 1]};
0243 const auto end = procargs.end();
0244
0245 argv[argc] = nullptr;
0246
0247
0248 for (auto n = 0u; n <= argc; n++)
0249 {
0250 auto e = std::find(itr, end, '\0');
0251 if (e == end && n < argc)
0252 {
0253 BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
0254 return {};
0255 }
0256 argv[n] = &*itr;
0257 itr = e + 1;
0258 }
0259
0260 auto fr_func = +[](int argc, char ** argv) {delete [] argv;};
0261
0262 return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func);
0263 }
0264
0265 #elif defined(__FreeBSD__)
0266
0267 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0268 {
0269 struct cl_proc_stat
0270 {
0271 void operator()(struct procstat *proc_stat)
0272 {
0273 procstat_close(proc_stat);
0274 }
0275 };
0276 std::unique_ptr<struct procstat, cl_proc_stat> proc_stat{procstat_open_sysctl()};
0277 if (!proc_stat)
0278 {
0279 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0280 return {};
0281 }
0282
0283 struct proc_info_close
0284 {
0285 struct procstat * proc_stat;
0286
0287 void operator()(struct kinfo_proc * proc_info)
0288 {
0289 procstat_freeprocs(proc_stat, proc_info);
0290 }
0291 };
0292
0293 unsigned cntp;
0294 std::unique_ptr<struct kinfo_proc, proc_info_close> proc_info{
0295 procstat_getprocs(proc_stat.get(), KERN_PROC_PID, pid, &cntp),
0296 proc_info_close{proc_stat.get()}};
0297
0298 if (!proc_info)
0299 {
0300 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0301 return {};
0302 }
0303
0304 char **cmd = procstat_getargv(proc_stat.get(), proc_info.get(), 0);
0305 if (!cmd)
0306 {
0307 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0308 return {};
0309 }
0310 auto res = make_cmd_shell_::clone(cmd);
0311 procstat_freeargv(proc_stat.get());
0312 return res;
0313 }
0314
0315 #elif defined(__DragonFly__)
0316
0317 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0318 {
0319 int cntp = 0;
0320 kinfo_proc *proc_info = nullptr;
0321 const char *nlistf, *memf;
0322 nlistf = memf = "/dev/null";
0323 struct closer
0324 {
0325 void operator()(kvm_t * kd)
0326 {
0327 kvm_close(kd);
0328 }
0329 };
0330
0331 std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
0332 if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return {};}
0333 if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, &cntp)))
0334 {
0335 char **cmd = kvm_getargv(kd.get(), proc_info, 0);
0336 if (cmd)
0337 return make_cmd_shell_::clone(cmd);
0338 else
0339 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0340 }
0341 else
0342 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0343 return {};
0344 }
0345
0346 #elif defined(__NetBSD__)
0347
0348 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0349 {
0350
0351 std::vector<std::string> vec;
0352 int cntp = 0;
0353 kinfo_proc2 *proc_info = nullptr;
0354 struct closer
0355 {
0356 void operator()(kvm_t * kd)
0357 {
0358 kvm_close(kd);
0359 }
0360 };
0361
0362 std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
0363
0364 if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return vec;}
0365 if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &cntp)))
0366 {
0367 char **cmd = kvm_getargv2(kd.get(), proc_info, 0);
0368 if (cmd)
0369 return make_cmd_shell_::clone(cmd);
0370 else
0371 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0372 }
0373 else
0374 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0375 return vec;
0376 }
0377
0378 #elif defined(__OpenBSD__)
0379
0380 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0381 {
0382 std::vector<std::string> vec;
0383 int cntp = 0;
0384 kinfo_proc *proc_info = nullptr;
0385
0386 struct closer
0387 {
0388 void operator()(kvm_t * kd)
0389 {
0390 kvm_close(kd);
0391 }
0392 };
0393
0394 std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
0395 if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return vec;}
0396 if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &cntp)))
0397 {
0398 char **cmd = kvm_getargv(kd.get(), proc_info, 0);
0399 if (cmd)
0400 return make_cmd_shell_::clone(cmd);
0401 else
0402 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0403 }
0404 else
0405 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0406 kvm_close(kd);
0407 return {};
0408 }
0409
0410 #elif defined(__sun)
0411
0412 shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
0413 {
0414 char **cmd = nullptr;
0415 proc *proc_info = nullptr;
0416 user *proc_user = nullptr;
0417 kd = kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr);
0418 if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return {};}
0419 if ((proc_info = kvm_getproc(kd, pid)))
0420 {
0421 if ((proc_user = kvm_getu(kd, proc_info)))
0422 {
0423 if (!kvm_getcmd(kd, proc_info, proc_user, &cmd, nullptr))
0424 {
0425 int argc = 0;
0426 for (int i = 0; cmd[i] != nullptr; i++)
0427 argc ++;
0428 return make_cmd_shell_::make(
0429 {}, argc, cmd,
0430 +[](int, char ** argv) {::free(argv);})
0431 }
0432 else
0433 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0434 }
0435 else
0436 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0437 }
0438 else
0439 BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
0440
0441 kvm_close(kd);
0442 return {};
0443 }
0444
0445 #else
0446 #error "Platform not supported"
0447 #endif
0448
0449 shell cmd(boost::process::v2::pid_type pid)
0450 {
0451 boost::system::error_code ec;
0452 auto res = cmd(pid, ec);
0453 if (ec)
0454 detail::throw_error(ec, "cmd");
0455 return res;
0456 }
0457
0458 }
0459
0460 BOOST_PROCESS_V2_END_NAMESPACE
0461
0462 #endif
0463