Mercurial > minori
diff dep/animia/src/fd/bsd.cc @ 138:28842a8d0c6b
dep/animia: huge refactor (again...)
but this time, it actually compiles! and it WORKS! (on win32... not sure about
other platforms...)
configuring players is still not supported: at some point I'll prune something
up...
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 12 Nov 2023 04:53:19 -0500 |
parents | |
children | 478f3b366199 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animia/src/fd/bsd.cc Sun Nov 12 04:53:19 2023 -0500 @@ -0,0 +1,116 @@ +/** + * bsd.cpp + * - provides support for most* versions of BSD + * - this also works for OS X :) + * more technical details: this is essentially a wrapper + * around the very C-like BSD system functions that are... + * kind of unnatural to use in modern C++. + **/ +#include <fcntl.h> +#include <iostream> +#include <string> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/user.h> +#include <unordered_map> +#include <vector> +#ifdef __FreeBSD__ +# include <libutil.h> +#elif defined(__APPLE__) +# include <libproc.h> +#endif + +namespace animia::internal::unix { + +/* this is a cleaned up version of a function from... Apple? + ...anyway, what it essentially does is gets the size and stuff from + sysctl() and reserves the space in a vector to store the PIDs */ +bool GetAllPids(std::set<pid_t>& pids) { + struct kinfo_proc* result = NULL; + size_t length = 0; + static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; + + /* get appropriate length from sysctl() + note: the reason this isn't checked is actually because this will + *always* return an error on OS X (or... maybe I'm doing it wrong :) ) */ + sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0); + + result = (struct kinfo_proc*)malloc(length); + if (result == NULL) + return std::vector<int>(); + + /* TODO: this might actually return ENOMEM if the amount of file handles changes between the + original sysctl() call and this one, which is technically possible */ + if (sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, result, &length, NULL, 0) == ENOMEM) { + assert(result != NULL); + free(result); + throw std::bad_alloc(); + } + + /* add pids to our vector */ + pids.reserve(length / sizeof(*result)); + for (int i = 0; i < length / sizeof(*result); i++) + pids.push_back(result[i].kp_proc.p_pid); +} + +bool GetProcessName(pid_t pid, std::string& result) { +#ifdef __FreeBSD__ + struct kinfo_proc* proc = kinfo_getproc(pid); + if (!proc) + return false; + result = proc->ki_comm; + + /* FreeBSD manpage for kinfo_getproc(): + "The pointer was obtained by an internal call to malloc(3) and + must be freed by the caller with a call to free(3)." */ + free(proc); + + return true; +#elif defined(__APPLE__) + struct proc_bsdinfo proc; + + int st = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc, PROC_PIDTBSDINFO_SIZE); + if (st != PROC_PIDTBSDINFO_SIZE) + return false; + + /* fixme: is this right? pbi_comm is an alternative, but it reduces the string size to + 16 chars. does pbi_name do the same, or is it different? */ + result = proc.pbi_name; + return true; +#endif +} + +/* this only works on OS X :( */ +bool EnumerateOpenFiles(const std::set<pid_t>& pids, std::vector<std::tuple<pid_t, std::string>>& files) { + for (const auto& pid : pids) { + int bufsz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); + if (bufsz == -1) + return false; + + struct proc_fdinfo* info = (struct proc_fdinfo*)malloc(bufsz); + if (!info) + return false; + + proc_pidinfo(pid, PROC_PIDLISTFDS, 0, info, bufsz); + + for (int i = 0; i < bufsz / sizeof(info[0]); i++) { + if (info[i].proc_fdtype == PROX_FDTYPE_VNODE) { + struct vnode_fdinfowithpath vnodeInfo; + + int sz = proc_pidfdinfo(pid, info[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE); + if (sz != PROC_PIDFDVNODEPATHINFO_SIZE) + return false; + + /* this doesn't work! + if (vnodeInfo.pfi.fi_openflags & O_WRONLY || vnodeInfo.pfi.fi_openflags & O_RDWR) + continue; + */ + + files.push_back({pid, vnodeInfo.pvip.vip_path}); + } + } + } + return true; +} + +} // namespace animia::internal::unix