comparison dep/animone/src/fd/bsd.cc @ 270:0718f538c5f9

dep/animone: filter open files by access mode
author Paper <paper@paper.us.eu.org>
date Fri, 12 Apr 2024 19:13:50 -0400
parents 1a6a5d3a94cd
children 65df2813d0de
comparison
equal deleted inserted replaced
269:3efac0541151 270:0718f538c5f9
11 #include <sys/user.h> 11 #include <sys/user.h>
12 #include <sys/vnode.h> 12 #include <sys/vnode.h>
13 13
14 #ifdef HAVE_KVM_GETFILES 14 #ifdef HAVE_KVM_GETFILES
15 # include <kvm.h> 15 # include <kvm.h>
16 # include <fts.h>
16 #elif defined(LIBUTIL) 17 #elif defined(LIBUTIL)
17 # include <libutil.h> 18 # include <libutil.h>
18 #endif 19 #endif
19 20
20 #include <string> 21 #include <string>
108 109
109 if (!result.get()) 110 if (!result.get())
110 return false; 111 return false;
111 112
112 /* actually get our results */ 113 /* actually get our results */
113 if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM) { 114 if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM)
114 result.reset(); 115 return false;
115 throw std::bad_alloc();
116 }
117 116
118 if (length < sizeof(struct kinfo_proc)) 117 if (length < sizeof(struct kinfo_proc))
119 return false; 118 return false;
120 119
121 for (int i = 0; i < length / sizeof(result[0]); i++) 120 for (int i = 0; i < length / sizeof(result[0]); i++)
124 123
125 return true; 124 return true;
126 #endif 125 #endif
127 } 126 }
128 127
128 #ifdef HAVE_KVM_GETFILES
129 static bool GetOpenFileName(const struct kinfo_file& file, std::string& name) {
130 /* OpenBSD doesn't provide a native API for this, so we have
131 * to do it ourselves */
132 static constexpr std::string_view root = "/";
133
134 FTS* file_system = fts_open(root.data(), FTS_COMFOLLOW | FTS_NOCHDIR, nullptr);
135 if (!file_system)
136 return false;
137
138 /* Search through the filesystem for a file that matches our
139 * kinfo_file structure */
140 FTSENT* parent = nullptr;
141 while ((parent = fts_read(file_system))) {
142 FTSENT* child = fts_children(file_system, 0);
143 while (child && child->fts_link) {
144 child = child->fts_link;
145 if (!S_ISREG(child->fts_statp->st_mode) || !S_ISLNK(child->fts_statp->st_mode))
146 continue;
147
148 if (child->fts_statp->st_dev != file->va_fsid)
149 continue;
150
151 if (child->fts_statp->st_ino != file->va_fileid)
152 continue;
153
154 name = std::string(child->fts_path) + child->fts_name;
155 fts_close(file_system);
156 return true;
157 }
158 }
159
160 fts_close(filesystem);
161 return false;
162 }
163 #endif /* HAVE_KVM_GETFILES */
164
129 bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) { 165 bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) {
130 #ifdef HAVE_KVM_GETFILES 166 #ifdef HAVE_KVM_GETFILES
131 char errbuf[_POSIX2_LINE_MAX]; 167 char errbuf[_POSIX2_LINE_MAX];
132 kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 168 kvm_t* kernel = kvm_openfiles(nullptr, nullptr, nullptr, O_RDONLY, errbuf);
133 if (!kernel) 169 if (!kernel)
134 return false; 170 return false;
135 171
136 for (const auto& pid : pids) { 172 for (const auto& pid : pids) {
137 int cnt; 173 int cnt;
140 kvm_close(kernel); 176 kvm_close(kernel);
141 return false; 177 return false;
142 } 178 }
143 179
144 for (int i = 0; i < cnt; i++) { 180 for (int i = 0; i < cnt; i++) {
145 if (!open_file_proc({pid, kfile[i].kf_path})) { 181 uint32_t oflags = kfile[i].kf_flags & O_ACCMODE;
182 if (oflags == O_WRONLY || oflags == O_RDWR)
183 continue;
184
185 std::string name;
186 if (!GetOpenFileName(kfile[i], name))
187 continue;
188
189 if (!open_file_proc({pid, name})) {
146 kvm_close(kernel); 190 kvm_close(kernel);
147 return false; 191 return false;
148 } 192 }
149 } 193 }
150 } 194 }
151 195
152 kvm_close(kernel); 196 kvm_close(kernel);
153
154 return true; 197 return true;
155 #elif defined(LIBUTIL) 198 #elif defined(LIBUTIL)
156 /* does this code even work? */
157 for (const auto& pid : pids) { 199 for (const auto& pid : pids) {
158 int cnt; 200 int cnt;
159 std::unique_ptr<struct kinfo_file[]> files(kinfo_getfile(pid, &cnt)); 201 std::unique_ptr<struct kinfo_file[]> files(kinfo_getfile(pid, &cnt));
160 if (!files) 202 if (!files)
161 return false; 203 return false;
162 204
163 for (int i = 0; i < cnt; i++) { 205 for (int i = 0; i < cnt; i++) {
164 const struct kinfo_file& current = files[i]; 206 const struct kinfo_file& current = files[i];
165 if (current.kf_vnode_type != KF_VTYPE_VREG) 207 if (current.kf_vnode_type != KF_VTYPE_VREG || current.kf_vnode_type != KF_VTYPE_VLNK)
208 continue;
209
210 const int oflags = current.kf_flags & O_ACCMODE;
211 if (oflags == O_WRONLY || oflags == O_RDWR)
166 continue; 212 continue;
167 213
168 if (!open_file_proc({pid, current.kf_path})) 214 if (!open_file_proc({pid, current.kf_path}))
169 return false; 215 return false;
170 } 216 }
171 } 217 }
172 218
173 return true; 219 return true;
174 #else 220 #else
175 for (const auto& pid : pids) { 221 /* NetBSD doesn't even provide a real API for this */
176 int mib[6] = {CTL_KERN, KERN_FILE2, KERN_FILE_BYPID, pid, sizeof(struct kinfo_file), 0}; 222 return false;
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 223 #endif
199 } 224 }
200 225
201 } // namespace animone::internal::kvm 226 } // namespace animone::internal::kvm