Mercurial > minori
diff dep/animia/src/fd/xnu.cc @ 160:900b5b530883
dep/animia: fd/xnu: use path args to get executable filename
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Fri, 17 Nov 2023 12:37:31 -0500 |
parents | 18c8eb5d1edc |
children | 61b76c7b656a |
line wrap: on
line diff
--- a/dep/animia/src/fd/xnu.cc Thu Nov 16 16:51:34 2023 -0500 +++ b/dep/animia/src/fd/xnu.cc Fri Nov 17 12:37:31 2023 -0500 @@ -9,6 +9,7 @@ #include <string> #include <unordered_map> #include <vector> +#include <memory> #include <fcntl.h> #include <libproc.h> @@ -16,27 +17,99 @@ #include <sys/types.h> #include <sys/user.h> +#include <iostream> + namespace animia::internal::xnu { -static std::string GetProcessName(pid_t pid) { - char name[2*MAXCOMLEN]; - proc_name(pid, name, sizeof(name)); +static bool GetProcessNameFromArgs(pid_t pid, std::string& result) { + /* sysctl shouldn't touch these, so we define them as const */ + const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)}; + const size_t mib_size = sizeof(mib)/sizeof(*mib); + + /* Get the initial size of the array */ + size_t size; + int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0); + if (ret) + return false; + + /* Reserve the space for it in a std::string */ + std::string args; + args.resize(size); + + /* Get the contents of argc and argv */ + ret = sysctl((int*)mib, mib_size, &args.front(), &size, NULL, 0); + if (ret) + return false; + + /* Is the size big enough to hold at least argc? */ + if (size < sizeof(int)) + return false; + + args.resize(size); + + /* Get argc using memcpy */ + int argc; + memcpy(&argc, &args.front(), sizeof(argc)); + + /* Check for a condition that, realistically, would never happen, + but better to be safe than sorry */ + if (argc < 1) + return false; - return name; + /* Find the first null character */ + size_t null_pos = args.find('\0', sizeof(argc)); + if (null_pos == std::string::npos) + return false; + + /* Find the last slash */ + size_t last_slash = args.rfind('/', null_pos); + if (last_slash == std::string::npos) + return false; + + /* Return our result */ + result = args.substr(last_slash + 1, null_pos - last_slash - 1); + return true; +} + +static bool GetProcessNameFromKernel(pid_t pid, std::string& result) { + result.reserve(2*MAXCOMLEN); + if (!proc_name(pid, &result.front(), result.length())) + return false; + + result.shrink_to_fit(); + return true; +} + +static bool GetProcessName(pid_t pid, std::string& result) { + /* First try parsing the arguments, this prevents the process name being + cut off to 2*MAXCOMLEN (32 chars) */ + if (GetProcessNameFromArgs(pid, result)) + return true; + + /* Then attempt getting it from the kernel, which results in the process name + being cut to 32 chars (16 chars if p_name is unavailable) */ + if (GetProcessNameFromKernel(pid, result)) + return true; + + return false; } bool XnuFdTools::EnumerateOpenProcesses(process_proc_t process_proc) { - std::vector<pid_t> pids; - pids.reserve(1024); + size_t pids_size = 512; + std::unique_ptr<pid_t[]> pids; - for (int returned_size = pids.capacity(); pids.capacity() > returned_size; pids.reserve(pids.capacity() * 2)) { - returned_size = proc_listpids(PROC_ALL_PIDS, 0, pids.data(), pids.capacity() * sizeof(pid_t)); + int returned_size = 0; + do { + pids.reset(new pid_t[pids_size]); + returned_size = proc_listpids(PROC_ALL_PIDS, 0, pids.get(), pids_size * sizeof(pid_t)); if (returned_size == -1) return false; - } + } while ((pids_size * sizeof(size_t)) < returned_size); - for (const auto& pid : pids) { - if (!process_proc({pid, GetProcessName(pid)})) + for (int i = 0; i < pids_size; i++) { + std::string result; + GetProcessName(pids[i], result); + if (!process_proc({pids[i], result})) return false; }