Mercurial > minori
diff dep/animia/src/fd/kvm.cc @ 169:e44b7c428d7c
dep/animia: add libkvm method (UNTESTED)
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 19 Nov 2023 17:30:38 -0500 |
parents | |
children | 8f6f8dd2eb23 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animia/src/fd/kvm.cc Sun Nov 19 17:30:38 2023 -0500 @@ -0,0 +1,134 @@ +/* kvm.cc: provides support for libkvm in multiple BSDs +** +** this is really the only way to get a thing that works on +** OpenBSD AND NetBSD. +** +** Much of this file is taken from the fstat source code in +** NetBSD. +*/ + +#include <kvm.h> + +namespace animia::internal::kvm { + +static bool GetFilename(kvm_t* kvm, struct vnode *vp, std::string& name) { + struct vnode vn; + if (!kvm_read(kvm, vp, &vn, sizeof(*vn))) + return 0; + + struct filestat fst; + const char* type = vfilestat(vn, &fst); + if (type == dead) + return false; + + for (DEVS* d = devs; d != NULL; d = d->next) { + if (d->fsid == fst->fsid && d->ino == fst->fileid) { + name = d->name; + break; + } + } + + return true; +} + +static bool GetFilePath(kvm_t* kvm, fdfile_t* fp, std::string& path) { + struct file file; + fdfile_t fdfile; + + if (!kvm_read(kvm, fp, &fdfile, sizeof(fdfile))) + return false; + + if (!fdfile.ff_file) + return false; + + if (!kvm_read(fdfile.ff_file, &file, sizeof(file))) + return false; + + if (file.f_type != DTYPE_VNODE) + return false; + + return GetFilename(kvm, file.f_data, path); +} + +static bool OpenFiles(kvm_t* kvm, struct kinfo_proc* p, open_file_proc_t open_file_proc) { + if (p->proc->p_fd == 0 || p->proc->p_cwdi == 0) + return false; + + struct filedesc filed; + if (!kvm_read(kvm, p->proc->p_fd, &filed, sizeof(filed))) + return false; + + if (filed.fd_lastfile == -1) + return false; + + struct cwdinfo cwdi; + if (!kvm_read(kvm, p->proc->p_cwdi, &cwdi, sizeof(cwdi))) + return false; + + struct fdtab dt; + if (!kvm_read(kvm, filed.fd_dt, &dt, sizeof(dt))) + return false; + + /* check for corrupted files? */ + if ((unsigned)filed.fd_lastfile >= dt.dt_nfiles || filed.fd_freefile > filed.fd_lastfile + 1) + return false; + + /* open files */ + std::unique_ptr<fdfile_t*[]> ofiles = nullptr; + { + ofiles.reset(malloc((filed.fd_lastfile + 1) * sizeof(fdfile_t*))); + if (!ofiles.get()) + return false; + } + + if (!kvm_read(kvm, &filed.fd_dt->dt_ff, ofiles.get(), filed.fd_lastfile + 1 * (sizeof(fdfile_t*)))) + return false; + + for (int i = 0; i <= filed.fd_lastfile; i++) { + if (!ofiles[i]) + continue; + std::string name; + GetFilePath(kvm, ofiles[i], name); + if (!open_file_proc(p->proc->p_pid, name)) + return false; + } + + return true; +} + +bool EnumerateOpenProcesses(process_proc_t process_proc) { + char errbuf[_POSIX2_LINE_MAX]; + kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); + if (!kernel) + return false; + + int entries = 0; + struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &nentries); + if (!kinfo) + return false; + + for (int i = 0; i < entries; i++) + if (!process_proc({kinfo[i].p_pid, kinfo[i].p_comm})) + return false; + + return true; +} + +bool EnumerateOpenFiles(std::set<pid_t>& pids, open_file_proc_t open_file_proc) { + kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); + if (!kernel) + return false; + + for (const auto& pid : pids) { + int cnt; + struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_PID, pid, &cnt); + if (!kinfo) + return false; + + for (int i = 0; i < cnt; i++) { + OpenFiles(kernel, kinfo, open_file_proc); + } + } +} + +}