Mercurial > minori
view dep/animone/src/fd/proc.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/win32.cc: support for linux's /proc filesystem * * plan 9 caused this monstrocity... */ #include "animone/fd/proc.h" #include "animone.h" #include "animone/util.h" #include <filesystem> #include <fstream> #include <sstream> #include <string> #include <algorithm> #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> static constexpr std::string_view PROC_LOCATION = "/proc"; namespace animone::internal::proc { struct Fdinfo { bool Parse(std::istream& istr); std::unordered_map<std::string, std::string> data; }; bool Fdinfo::Parse(std::istream& istr) { /* shift to the start of the stream */ istr.seekg(0); for (std::string line; std::getline(istr, line); ) { if (line.empty()) /* huh? */ continue; std::size_t colon = line.find(':'); if (colon == std::string::npos) return false; std::string key = line.substr(0, colon); std::string value = line.substr(colon + 1); util::TrimLeft(value, " "); data[key] = value; } return true; } static bool IsRegularFile(const std::string& link) { struct stat sb; if (stat(link.c_str(), &sb) == -1) return false; return S_ISREG(sb.st_mode); } static bool AreFlagsOk(pid_t pid, int fd) { const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "fdinfo" / std::to_string(fd); std::ifstream file(path); if (!file) return false; Fdinfo fdinfo; if (!fdinfo.Parse(file)) return false; if (fdinfo.data.find("flags") == fdinfo.data.end()) return false; /* check if the file was opened in a write mode */ try { const long long accflags = std::stoll(fdinfo.data["flags"]) & O_ACCMODE; if (accflags == O_WRONLY || accflags == O_RDWR) return false; } catch (const std::exception& ex) { return false; /* huh ? */ } return true; } static bool GetFilenameFromFd(std::string link, std::string& out) { /* /proc is a "virtual filesystem", so we have to guess the path size. yippee! */ constexpr size_t OUT_MAX = (1ul << 15); // 32KiB out.resize(32); ssize_t exe_used = 0; do { out.resize(out.length() * 2); exe_used = readlink(link.c_str(), &out.front(), out.length()); if (exe_used == (ssize_t)-1 || exe_used < (ssize_t)1) return false; // we got a bad result. SAD! } while (out.length() < OUT_MAX && exe_used >= static_cast<ssize_t>(out.length())); out.resize(out.find('\0')); return true; } static bool IsSystemFile(const std::string& path) { static constexpr std::array<std::string_view, 9> invalid_paths = {"/boot", "/dev", "/bin", "/usr", "/opt", "/proc", "/var", "/etc", "/dev"}; for (const auto& invalid_path : invalid_paths) if (!path.rfind(invalid_path, 0)) return true; return false; } bool GetProcessName(pid_t pid, std::string& result) { const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "comm"; if (!util::ReadFile(path, result)) return false; result.erase(std::remove(result.begin(), result.end(), '\n'), result.cend()); return true; } bool EnumerateOpenProcesses(process_proc_t process_proc) { bool success = false; for (const auto& dir : std::filesystem::directory_iterator{PROC_LOCATION}) { Process proc; proc.platform = ExecutablePlatform::Posix; try { proc.pid = util::StringToInt(dir.path().stem()); success = true; } catch (std::invalid_argument const& ex) { continue; } if (!GetProcessName(proc.pid, proc.comm)) continue; if (!process_proc(proc)) return false; } return success; } 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) { const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "fd"; for (const auto& dir : std::filesystem::directory_iterator{path}) { if (!AreFlagsOk(pid, util::StringToInt(dir.path().stem()))) continue; std::string name; if (!GetFilenameFromFd(dir.path(), name)) continue; if (!IsRegularFile(name)) continue; if (IsSystemFile(name)) continue; if (!open_file_proc({pid, name})) return false; } } return true; } } // namespace animia::internal::proc