comparison dep/animone/src/fd/bsd.cc @ 266:1a6a5d3a94cd

dep/animone: make bsd.cc and x11.cc actually work apparently I broke these, and even now the x11 code *still* doesn't want to work correctly (at least on FreeBSD). half of the PID response codes are just 0 or the PID for the X server itself... wtf? maybe dwm just doesn't support the XRes extension, or I'm just stupid. i don't know.
author Paper <paper@paper.us.eu.org>
date Thu, 11 Apr 2024 22:05:41 -0400
parents dep/animone/src/fd/kvm.cc@862d0d8619f6
children 0718f538c5f9
comparison
equal deleted inserted replaced
265:ff0b2052b234 266:1a6a5d3a94cd
1 #include "animone/fd/bsd.h"
2 #include "animone.h"
3 #include "animone/fd.h"
4
5 #include <sys/file.h>
6 #include <sys/filedesc.h>
7 #include <sys/param.h>
8 #include <sys/queue.h>
9 #include <sys/sysctl.h>
10 #include <sys/types.h>
11 #include <sys/user.h>
12 #include <sys/vnode.h>
13
14 #ifdef HAVE_KVM_GETFILES
15 # include <kvm.h>
16 #elif defined(LIBUTIL)
17 # include <libutil.h>
18 #endif
19
20 #include <string>
21 #include <iostream>
22
23 namespace animone::internal::bsd {
24
25 static std::string Basename(const std::string& name) {
26 size_t s = name.find_last_of('/');
27
28 if (s == std::string::npos)
29 return name;
30
31 return name.substr(s, name.size());
32 }
33
34 bool GetProcessName(pid_t pid, std::string& name) {
35 #ifdef HAVE_KVM_GETFILES
36 char errbuf[_POSIX2_LINE_MAX];
37 kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
38 if (!kernel)
39 return false;
40
41 int entries = 0;
42 struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_PID, pid, &entries);
43 if (!kinfo) {
44 kvm_close(kernel);
45 return false;
46 }
47
48 if (entries < 1) {
49 kvm_close(kernel);
50 return false;
51 }
52
53 name = Basename(kinfo[0].ki_paddr->p_comm);
54
55 return true;
56 #else
57 /* use sysctl as a fallback */
58 static const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
59
60 struct kinfo_proc result;
61
62 size_t length = 1;
63 if (sysctl((int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, &result, &length, NULL, 0) == -1)
64 return false;
65
66 name = Basename(result.ki_comm);
67
68 return true;
69 #endif
70 }
71
72 /* Most of the BSDs share the common kvm library,
73 * so accessing this information can be trivial.
74 */
75 bool EnumerateOpenProcesses(process_proc_t process_proc) {
76 #ifdef HAVE_KVM_GETFILES
77 char errbuf[_POSIX2_LINE_MAX];
78 kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
79 if (!kernel)
80 return false;
81
82 int entries = 0;
83 struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_ALL, 0, &entries);
84 if (!kinfo) {
85 kvm_close(kernel);
86 return false;
87 }
88
89 for (int i = 0; i < entries; i++) {
90 if (!process_proc({kinfo[i].ki_paddr->p_pid, Basename(kinfo[i].ki_paddr->p_comm)})) {
91 kvm_close(kernel);
92 return false;
93 }
94 }
95
96 kvm_close(kernel);
97
98 return true;
99 #else
100 /* use sysctl as a fallback */
101 static const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
102 size_t length = 0;
103
104 sysctl((int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, NULL, &length, NULL, 0);
105
106 std::unique_ptr<struct kinfo_proc[]> result;
107 result.reset(new struct kinfo_proc[length]);
108
109 if (!result.get())
110 return false;
111
112 /* actually get our results */
113 if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM) {
114 result.reset();
115 throw std::bad_alloc();
116 }
117
118 if (length < sizeof(struct kinfo_proc))
119 return false;
120
121 for (int i = 0; i < length / sizeof(result[0]); i++)
122 if (!process_proc({result[i].ki_pid, result[i].ki_comm}))
123 return false;
124
125 return true;
126 #endif
127 }
128
129 bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) {
130 #ifdef HAVE_KVM_GETFILES
131 char errbuf[_POSIX2_LINE_MAX];
132 kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
133 if (!kernel)
134 return false;
135
136 for (const auto& pid : pids) {
137 int cnt;
138 struct kinfo_file* kfile = kvm_getfiles(kernel, KERN_FILE_BYPID, pid, &cnt);
139 if (!kfile) {
140 kvm_close(kernel);
141 return false;
142 }
143
144 for (int i = 0; i < cnt; i++) {
145 if (!open_file_proc({pid, kfile[i].kf_path})) {
146 kvm_close(kernel);
147 return false;
148 }
149 }
150 }
151
152 kvm_close(kernel);
153
154 return true;
155 #elif defined(LIBUTIL)
156 /* does this code even work? */
157 for (const auto& pid : pids) {
158 int cnt;
159 std::unique_ptr<struct kinfo_file[]> files(kinfo_getfile(pid, &cnt));
160 if (!files)
161 return false;
162
163 for (int i = 0; i < cnt; i++) {
164 const struct kinfo_file& current = files[i];
165 if (current.kf_vnode_type != KF_VTYPE_VREG)
166 continue;
167
168 if (!open_file_proc({pid, current.kf_path}))
169 return false;
170 }
171 }
172
173 return true;
174 #else
175 for (const auto& pid : pids) {
176 int mib[6] = {CTL_KERN, KERN_FILE2, KERN_FILE_BYPID, pid, sizeof(struct kinfo_file), 0};
177
178 size_t len = 0;
179 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) == -1)
180 return false;
181
182 mib[5] = len / sizeof(struct kinfo_file);
183
184 std::unique_ptr<struct kinfo_file[]> buf(new struct kinfo_file[mib[5]]);
185 if (!buf)
186 return false;
187
188 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf.get(), &len, NULL, 0) == -1)
189 return false;
190
191 /* TODO: check kfile[i].ki_ofileflags */
192 for (size_t i = 0; i < mib[5]; i++)
193 if (!open_file_proc({pid, kfile[i].kf_path}))
194 return false;
195 }
196
197 return true;
198 #endif
199 }
200
201 } // namespace animone::internal::kvm