Mercurial > minori
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 157:18c8eb5d1edc | 160:900b5b530883 |
|---|---|
| 7 | 7 |
| 8 #include <cassert> | 8 #include <cassert> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <unordered_map> | 10 #include <unordered_map> |
| 11 #include <vector> | 11 #include <vector> |
| 12 #include <memory> | |
| 12 | 13 |
| 13 #include <fcntl.h> | 14 #include <fcntl.h> |
| 14 #include <libproc.h> | 15 #include <libproc.h> |
| 15 #include <sys/sysctl.h> | 16 #include <sys/sysctl.h> |
| 16 #include <sys/types.h> | 17 #include <sys/types.h> |
| 17 #include <sys/user.h> | 18 #include <sys/user.h> |
| 18 | 19 |
| 20 #include <iostream> | |
| 21 | |
| 19 namespace animia::internal::xnu { | 22 namespace animia::internal::xnu { |
| 20 | 23 |
| 21 static std::string GetProcessName(pid_t pid) { | 24 static bool GetProcessNameFromArgs(pid_t pid, std::string& result) { |
| 22 char name[2*MAXCOMLEN]; | 25 /* sysctl shouldn't touch these, so we define them as const */ |
| 23 proc_name(pid, name, sizeof(name)); | 26 const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)}; |
| 27 const size_t mib_size = sizeof(mib)/sizeof(*mib); | |
| 24 | 28 |
| 25 return name; | 29 /* Get the initial size of the array */ |
| 30 size_t size; | |
| 31 int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0); | |
| 32 if (ret) | |
| 33 return false; | |
| 34 | |
| 35 /* Reserve the space for it in a std::string */ | |
| 36 std::string args; | |
| 37 args.resize(size); | |
| 38 | |
| 39 /* Get the contents of argc and argv */ | |
| 40 ret = sysctl((int*)mib, mib_size, &args.front(), &size, NULL, 0); | |
| 41 if (ret) | |
| 42 return false; | |
| 43 | |
| 44 /* Is the size big enough to hold at least argc? */ | |
| 45 if (size < sizeof(int)) | |
| 46 return false; | |
| 47 | |
| 48 args.resize(size); | |
| 49 | |
| 50 /* Get argc using memcpy */ | |
| 51 int argc; | |
| 52 memcpy(&argc, &args.front(), sizeof(argc)); | |
| 53 | |
| 54 /* Check for a condition that, realistically, would never happen, | |
| 55 but better to be safe than sorry */ | |
| 56 if (argc < 1) | |
| 57 return false; | |
| 58 | |
| 59 /* Find the first null character */ | |
| 60 size_t null_pos = args.find('\0', sizeof(argc)); | |
| 61 if (null_pos == std::string::npos) | |
| 62 return false; | |
| 63 | |
| 64 /* Find the last slash */ | |
| 65 size_t last_slash = args.rfind('/', null_pos); | |
| 66 if (last_slash == std::string::npos) | |
| 67 return false; | |
| 68 | |
| 69 /* Return our result */ | |
| 70 result = args.substr(last_slash + 1, null_pos - last_slash - 1); | |
| 71 return true; | |
| 72 } | |
| 73 | |
| 74 static bool GetProcessNameFromKernel(pid_t pid, std::string& result) { | |
| 75 result.reserve(2*MAXCOMLEN); | |
| 76 if (!proc_name(pid, &result.front(), result.length())) | |
| 77 return false; | |
| 78 | |
| 79 result.shrink_to_fit(); | |
| 80 return true; | |
| 81 } | |
| 82 | |
| 83 static bool GetProcessName(pid_t pid, std::string& result) { | |
| 84 /* First try parsing the arguments, this prevents the process name being | |
| 85 cut off to 2*MAXCOMLEN (32 chars) */ | |
| 86 if (GetProcessNameFromArgs(pid, result)) | |
| 87 return true; | |
| 88 | |
| 89 /* Then attempt getting it from the kernel, which results in the process name | |
| 90 being cut to 32 chars (16 chars if p_name is unavailable) */ | |
| 91 if (GetProcessNameFromKernel(pid, result)) | |
| 92 return true; | |
| 93 | |
| 94 return false; | |
| 26 } | 95 } |
| 27 | 96 |
| 28 bool XnuFdTools::EnumerateOpenProcesses(process_proc_t process_proc) { | 97 bool XnuFdTools::EnumerateOpenProcesses(process_proc_t process_proc) { |
| 29 std::vector<pid_t> pids; | 98 size_t pids_size = 512; |
| 30 pids.reserve(1024); | 99 std::unique_ptr<pid_t[]> pids; |
| 31 | 100 |
| 32 for (int returned_size = pids.capacity(); pids.capacity() > returned_size; pids.reserve(pids.capacity() * 2)) { | 101 int returned_size = 0; |
| 33 returned_size = proc_listpids(PROC_ALL_PIDS, 0, pids.data(), pids.capacity() * sizeof(pid_t)); | 102 do { |
| 103 pids.reset(new pid_t[pids_size]); | |
| 104 returned_size = proc_listpids(PROC_ALL_PIDS, 0, pids.get(), pids_size * sizeof(pid_t)); | |
| 34 if (returned_size == -1) | 105 if (returned_size == -1) |
| 35 return false; | 106 return false; |
| 36 } | 107 } while ((pids_size * sizeof(size_t)) < returned_size); |
| 37 | 108 |
| 38 for (const auto& pid : pids) { | 109 for (int i = 0; i < pids_size; i++) { |
| 39 if (!process_proc({pid, GetProcessName(pid)})) | 110 std::string result; |
| 111 GetProcessName(pids[i], result); | |
| 112 if (!process_proc({pids[i], result})) | |
| 40 return false; | 113 return false; |
| 41 } | 114 } |
| 42 | 115 |
| 43 return true; | 116 return true; |
| 44 } | 117 } |
