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 }