Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:10

0001 // Copyright (c) 2022 Klemens D. Morgenstern
0002 // Copyright (c) 2022 Samuel Venable
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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         // yes, not the greatest solution.
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/*=MEMCMD*/, 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; //args is a null-terminated list
0191 
0192     for (auto n = 0u; n <= argc; n++)
0193     {
0194         auto e = std::find(itr, end, '\0');
0195         if (e == end && n < argc) // something off
0196         {
0197             BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
0198             return {};
0199         }
0200         argv[n] = &*itr;
0201         itr = e + 1; // start searching start
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) // done!
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; //args is a null-terminated list
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) // something off
0252         {
0253             BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
0254             return {};
0255         }
0256         argv[n] = &*itr;
0257         itr = e + 1; // start searching start
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 } // namespace ext
0459 
0460 BOOST_PROCESS_V2_END_NAMESPACE
0461 
0462 #endif // BOOST_PROCESS_V2_IMPL_CMD_IPP
0463