Mercurial > minori
view dep/animone/src/fd/bsd.cc @ 337:a7d4e5107531
dep/animone: REFACTOR ALL THE THINGS
1: animone now has its own syntax divergent from anisthesia,
making different platforms actually have their own sections
2: process names in animone are now called `comm' (this will
probably break things). this is what its called in bsd/linux
so I'm just going to use it everywhere
3: the X11 code now checks for the existence of a UTF-8 window title
and passes it if available
4: ANYTHING THATS NOT LINUX IS 100% UNTESTED AND CAN AND WILL BREAK!
I still actually need to test the bsd code. to be honest I'm probably
going to move all of the bsds into separate files because they're
all essentially different operating systems at this point
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Wed, 19 Jun 2024 12:51:15 -0400 |
parents | a4257370de16 |
children |
line wrap: on
line source
/* * fd/win32.cc: support for most BSDs * * should support (Free/Open/Net)BSD. possibly more, * but this code is untested outside of FreeBSD. */ #include "animone/fd/bsd.h" #include "animone.h" #include "animone/fd.h" #include <sys/file.h> #include <sys/filedesc.h> #include <sys/param.h> #include <sys/queue.h> #include <sys/sysctl.h> #include <sys/types.h> #include <sys/user.h> #include <sys/vnode.h> #ifdef HAVE_KVM_GETFILES # include <kvm.h> # include <fts.h> #elif defined(LIBUTIL) # include <libutil.h> #endif #include <string> namespace animone::internal::bsd { static std::string Basename(const std::string& name) { size_t s = name.find_last_of('/'); if (s == std::string::npos) return name; return name.substr(s, name.size()); } bool GetProcessName(pid_t pid, std::string& name) { #ifdef HAVE_KVM_GETFILES char errbuf[_POSIX2_LINE_MAX]; kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); if (!kernel) return false; int entries = 0; struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_PID, pid, &entries); if (!kinfo) { kvm_close(kernel); return false; } if (entries < 1) { kvm_close(kernel); return false; } name = Basename(kinfo[0].ki_paddr->p_comm); return true; #else /* use sysctl as a fallback */ static const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; struct kinfo_proc result; size_t length = 1; if (sysctl((int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, &result, &length, NULL, 0) == -1) return false; name = Basename(result.ki_comm); return true; #endif } /* Most of the BSDs share the common kvm library, * so accessing this information can be trivial. */ bool EnumerateOpenProcesses(process_proc_t process_proc) { #ifdef HAVE_KVM_GETFILES char errbuf[_POSIX2_LINE_MAX]; kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); if (!kernel) return false; int entries = 0; struct kinfo_proc* kinfo = kvm_getprocs(kernel, KERN_PROC_ALL, 0, &entries); if (!kinfo) { kvm_close(kernel); return false; } for (int i = 0; i < entries; i++) { if (!process_proc({.platform = ExecutablePlatform::Posix, .pid = kinfo[i].ki_paddr->p_pid, .comm = Basename(kinfo[i].ki_paddr->p_comm)})) { kvm_close(kernel); return false; } } kvm_close(kernel); return true; #else /* use sysctl as a fallback */ static const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; size_t length = 0; sysctl((int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, NULL, &length, NULL, 0); std::unique_ptr<struct kinfo_proc[]> result; result.reset(new struct kinfo_proc[length]); if (!result.get()) return false; /* actually get our results */ if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM) return false; if (length < sizeof(struct kinfo_proc)) return false; for (int i = 0; i < length / sizeof(result[0]); i++) if (!process_proc({.platform = ExecutablePlatform::Posix, .pid = result[i].ki_pid, .comm = result[i].ki_comm})) return false; return true; #endif } #ifdef HAVE_KVM_GETFILES static bool GetOpenFileName(const struct kinfo_file& file, std::string& name) { /* OpenBSD doesn't provide a native API for this, so we have * to do it ourselves */ static constexpr std::string_view root = "/"; FTS* file_system = fts_open(root.data(), FTS_COMFOLLOW | FTS_NOCHDIR, nullptr); if (!file_system) return false; /* Search through the filesystem for a file that matches our * kinfo_file structure */ FTSENT* parent = nullptr; while ((parent = fts_read(file_system))) { FTSENT* child = fts_children(file_system, 0); while (child && child->fts_link) { child = child->fts_link; if (!S_ISREG(child->fts_statp->st_mode) || !S_ISLNK(child->fts_statp->st_mode)) continue; if (child->fts_statp->st_dev != file->va_fsid) continue; if (child->fts_statp->st_ino != file->va_fileid) continue; name = std::string(child->fts_path) + child->fts_name; fts_close(file_system); return true; } } fts_close(filesystem); return false; } #endif /* HAVE_KVM_GETFILES */ bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) { #ifdef HAVE_KVM_GETFILES char errbuf[_POSIX2_LINE_MAX]; kvm_t* kernel = kvm_openfiles(nullptr, nullptr, nullptr, O_RDONLY, errbuf); if (!kernel) return false; for (const auto& pid : pids) { int cnt; struct kinfo_file* kfile = kvm_getfiles(kernel, KERN_FILE_BYPID, pid, &cnt); if (!kfile) { kvm_close(kernel); return false; } for (int i = 0; i < cnt; i++) { uint32_t oflags = kfile[i].kf_flags & O_ACCMODE; if (oflags == O_WRONLY || oflags == O_RDWR) continue; std::string name; if (!GetOpenFileName(kfile[i], name)) continue; if (!open_file_proc({pid, name})) { kvm_close(kernel); return false; } } } kvm_close(kernel); return true; #elif defined(LIBUTIL) for (const auto& pid : pids) { int cnt; std::unique_ptr<struct kinfo_file[]> files(kinfo_getfile(pid, &cnt)); if (!files) return false; for (int i = 0; i < cnt; i++) { const struct kinfo_file& current = files[i]; if (current.kf_vnode_type != KF_VTYPE_VREG || current.kf_vnode_type != KF_VTYPE_VLNK) continue; const int oflags = current.kf_flags & O_ACCMODE; if (oflags == O_WRONLY || oflags == O_RDWR) continue; if (!open_file_proc({pid, current.kf_path})) return false; } } return true; #else /* NetBSD doesn't even provide a real API for this */ return false; #endif } } // namespace animone::internal::kvm