# HG changeset patch # User Paper # Date 1700242651 18000 # Node ID 900b5b5308839b5e985ac4412b3da2d17f0544c4 # Parent 18c8eb5d1edce2e60210d7d13b6c3e1fb3fd14af dep/animia: fd/xnu: use path args to get executable filename diff -r 18c8eb5d1edc -r 900b5b530883 dep/animia/src/fd/xnu.cc --- 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 #include #include +#include #include #include @@ -16,27 +17,99 @@ #include #include +#include + 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(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 pids; - pids.reserve(1024); + size_t pids_size = 512; + std::unique_ptr 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; }