Mercurial > minori
diff dep/animia/src/fd/xnu.cc @ 153:bd439dd6ffc5
*: make win stuff actually work, rename bsd.cc to xnu.cc
It's been OS X only for ages, and these functions are different between
most BSDs anyway
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Wed, 15 Nov 2023 13:28:18 -0500 |
parents | |
children | d43d68408d3c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animia/src/fd/xnu.cc Wed Nov 15 13:28:18 2023 -0500 @@ -0,0 +1,101 @@ +/* +** fd/xnu.cpp +** - provides support for XNU (part of Darwin) +*/ +#include "animia/fd/xnu.h" +#include "animia.h" + +#include <unordered_map> +#include <vector> +#include <string> + +#include <fcntl.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/user.h> +#include <libproc.h> + +namespace animia::internal::xnu { + +static bool GetProcessName(pid_t pid, std::string& result) { + 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; +} + +/* 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 XnuFdTools::EnumerateOpenProcesses(process_proc_t process_proc) { + 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 false; + + /* 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); + return false; + } + + for (int i = 0; i < length / sizeof(*result); i++) { + const pid_t pid = result[i].kp_proc.p_pid; + if (!process_proc({pid, GetProcessName(pid)})) + return false; + } +} + +bool XnuFdTools::EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) { + if (!open_file_proc) + return false; + + 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; + */ + + if (!open_file_proc({pid, vnodeInfo.pvip.vip_path})) + return false; + } + } + } + return true; +} + +} // namespace animia::internal::unix