Mercurial > minori
view dep/animone/src/fd/xnu.cc @ 365:f81bed4e04ac
*: megacommit that probably breaks things
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Wed, 02 Oct 2024 23:06:43 -0400 |
parents | a7d4e5107531 |
children |
line wrap: on
line source
/* * fd/xnu.cc: support for macOS's kernel * * this used to have all sorts of hacks for getting the process name, * but ultimately I just decided that it's better to just parse the * PID path from xnu, which should work perfectly fine. */ #include "animone/fd/xnu.h" #include "animone.h" #include <cassert> #include <memory> #include <string> #include <unordered_map> #include <vector> #include <fcntl.h> #include <libproc.h> #include <sys/sysctl.h> #include <sys/types.h> #include <sys/user.h> /* you may be asking: WTF is FWRITE? * well, from bsd/sys/fcntl.h in the XNU kernel: * * Kernel encoding of open mode; separate read and write bits that are * independently testable: 1 greater than [O_RDONLY and O_WRONLY]. * * It's just how the kernel defines write mode. */ #ifndef FWRITE #define FWRITE 0x0002 #endif namespace animone::internal::xnu { bool EnumerateOpenProcesses(process_proc_t process_proc) { /* pre-allocate 256 pids */ std::vector<pid_t> pids(256); int returned_size_bytes = 0; for (;;) { returned_size_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids.data(), pids.size() * sizeof(pid_t)); if (returned_size_bytes <= 0) /* probably an error ? */ return false; /* break out of the loop if we have everything */ if ((pids.size() * sizeof(pid_t)) > returned_size_bytes) break; pids.resize(pids.size() * 2); } pids.resize(returned_size_bytes); for (const auto& pid : pids) { std::string result; GetProcessName(pid, result); if (!process_proc({.platform = ExecutablePlatform::Xnu, .pid = pid, .comm = result})) return false; } return true; } bool 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) { /* most processes probably don't even have that many files opened! */ std::vector<struct proc_fdinfo> fds(4); int returned_size_bytes = 0; for (;;) { returned_size_bytes = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds.data(), fds.size()); if (returned_size_bytes <= 0) /* probably an error ? */ return false; /* break out of the loop if we have everything */ if ((fds.size() * sizeof(struct proc_fdinfo)) > returned_size_bytes) break; fds.resize(fds.size() * 2); } fds.resize(returned_size_bytes / sizeof(struct proc_fdinfo)); for (const auto& fd : fds) { if (fd.proc_fdtype != PROX_FDTYPE_VNODE) continue; struct vnode_fdinfowithpath vnodeInfo; int sz = proc_pidfdinfo(pid, fd.proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE); if (sz != PROC_PIDFDVNODEPATHINFO_SIZE) return false; /* why would a media player open a file in write mode? */ if (vnodeInfo.pfi.fi_openflags & FWRITE) continue; if (!open_file_proc({pid, vnodeInfo.pvip.vip_path})) return false; } } return true; } static bool GetProcessNameFromProcPidPath(pid_t pid, std::string& result) { result.assign(PROC_PIDPATHINFO_MAXSIZE, '\0'); int ret = proc_pidpath(pid, result.data(), result.size()); if (ret <= 0) return false; /* find the last slash, if there's none, we're done here */ size_t last_slash = result.rfind('/'); if (last_slash == std::string::npos) return true; result.erase(0, last_slash + 1); return true; } static bool GetProcessNameFromProcName(pid_t pid, std::string& result) { result.assign(2 * MAXCOMLEN, '\0'); int size = proc_name(pid, result.data(), result.length()); /* if size is MAXCOMLEN or 2 * MAXCOMLEN, assume * this method won't work and our result is truncated */ if (size <= 0 || size == MAXCOMLEN || size == 2 * MAXCOMLEN) return false; result.resize(size); return true; } bool GetProcessName(pid_t pid, std::string& result) { if (GetProcessNameFromProcName(pid, result)) return true; if (GetProcessNameFromProcPidPath(pid, result)) return true; return false; } } // namespace animone::internal::xnu