Mercurial > minori
view dep/animone/src/fd/bsd.cc @ 327:b5d6c27c308f
anime: refactor Anime::SeriesSeason to Season class
ToLocalString has also been altered to take in both season
and year because lots of locales actually treat formatting
seasons differently! most notably is Russian which adds a
suffix at the end to notate seasons(??)
| author | Paper <paper@paper.us.eu.org> |
|---|---|
| date | Thu, 13 Jun 2024 01:49:18 -0400 |
| parents | a4257370de16 |
| children | a7d4e5107531 |
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({kinfo[i].ki_paddr->p_pid, 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({result[i].ki_pid, 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
