Mercurial > minori
comparison dep/animia/src/fd/proc.cc @ 215:031a257ee019
dep/animia: fd/proc: use std::filesystem, etc. changes
i.e. don't use std::stoi so we don't get exceptions...
| author | Paper <mrpapersonic@gmail.com> |
|---|---|
| date | Sun, 07 Jan 2024 11:44:40 -0500 |
| parents | bc1ae1810855 |
| children | 0a5b6a088886 |
comparison
equal
deleted
inserted
replaced
| 214:8d35061e7505 | 215:031a257ee019 |
|---|---|
| 1 #include "animia/fd/proc.h" | 1 #include "animia/fd/proc.h" |
| 2 #include "animia.h" | 2 #include "animia.h" |
| 3 #include "animia/util.h" | 3 #include "animia/util.h" |
| 4 | 4 |
| 5 #include <algorithm> | |
| 6 #include <cstring> | |
| 7 #include <filesystem> | 5 #include <filesystem> |
| 8 #include <fstream> | 6 #include <fstream> |
| 9 #include <sstream> | 7 #include <sstream> |
| 10 #include <string> | 8 #include <string> |
| 11 #include <unordered_map> | |
| 12 #include <vector> | |
| 13 | 9 |
| 14 #include <dirent.h> | 10 #include <sys/stat.h> |
| 15 #include <fcntl.h> | 11 #include <fcntl.h> |
| 16 #include <sys/stat.h> | |
| 17 #include <unistd.h> | 12 #include <unistd.h> |
| 18 | 13 |
| 19 static constexpr std::string_view PROC_LOCATION = "/proc"; | 14 static constexpr std::string_view PROC_LOCATION = "/proc"; |
| 20 | 15 |
| 21 namespace animia::internal::proc { | 16 namespace animia::internal::proc { |
| 22 | 17 |
| 23 /* this uses dirent instead of std::filesystem; it would make a bit | 18 template<typename T = int> |
| 24 more sense to use the latter, but this is platform dependent already :) */ | 19 static T StringToInt(const std::string& str, T def = 0) { |
| 25 static std::vector<std::string> GetAllFilesInDir(const std::string& _dir) { | 20 std::istringstream s(str); |
| 26 std::vector<std::string> ret; | 21 s >> def; |
| 27 | 22 return def; |
| 28 DIR* dir = opendir(_dir.c_str()); | |
| 29 if (!dir) | |
| 30 return ret; | |
| 31 | |
| 32 struct dirent* dp; | |
| 33 while ((dp = readdir(dir)) != NULL) { | |
| 34 if (!(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))) | |
| 35 ret.push_back(_dir + "/" + dp->d_name); | |
| 36 } | |
| 37 | |
| 38 closedir(dir); | |
| 39 return ret; | |
| 40 } | |
| 41 | |
| 42 static std::string Basename(const std::string& path) { | |
| 43 return path.substr(path.find_last_of("/") + 1, path.length()); | |
| 44 } | 23 } |
| 45 | 24 |
| 46 static bool IsRegularFile(std::string link) { | 25 static bool IsRegularFile(std::string link) { |
| 47 struct stat sb; | 26 struct stat sb; |
| 48 if (stat(link.c_str(), &sb) == -1) | 27 if (stat(link.c_str(), &sb) == -1) |
| 49 return false; | 28 return false; |
| 29 | |
| 50 return S_ISREG(sb.st_mode); | 30 return S_ISREG(sb.st_mode); |
| 51 } | 31 } |
| 52 | 32 |
| 53 static bool AreFlagsOk(pid_t pid, int fd) { | 33 static bool AreFlagsOk(pid_t pid, int fd) { |
| 54 const std::string path = std::string(PROC_LOCATION) + "/" + std::to_string(pid) + "/fdinfo/" + std::to_string(fd); | 34 const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "fdinfo" / std::to_string(fd); |
| 55 | 35 |
| 56 std::ifstream file(path.c_str()); | 36 std::ifstream file(path); |
| 57 if (!file) | 37 if (!file) |
| 58 return false; | 38 return false; |
| 59 | 39 |
| 60 int flags = 0; | 40 int flags = 0; |
| 61 for (std::string line; std::getline(file, line); ) | 41 for (std::string line; std::getline(file, line); ) |
| 62 if (line.find("flags:", 0) == 0) | 42 if (line.find("flags:", 0) == 0) |
| 63 flags = std::stoi(line.substr(line.find_last_not_of("0123456789") + 1)); | 43 flags = StringToInt(line.substr(line.find_last_not_of("0123456789") + 1)); |
| 64 | 44 |
| 65 if (flags & O_WRONLY || flags & O_RDWR) | 45 if (flags & O_WRONLY || flags & O_RDWR) |
| 66 return false; | 46 return false; |
| 47 | |
| 67 return true; | 48 return true; |
| 68 } | 49 } |
| 69 | 50 |
| 70 static bool GetFilenameFromFd(std::string link, std::string& out) { | 51 static bool GetFilenameFromFd(std::string link, std::string& out) { |
| 71 /* gets around stupid linux limitation where /proc doesn't | 52 /* gets around stupid linux limitation where /proc doesn't |
| 72 * give actual size readings of the string | 53 * give actual size readings of the string |
| 73 */ | 54 */ |
| 74 constexpr size_t OUT_MAX = (1 << 15); // 32KiB | 55 constexpr size_t OUT_MAX = (1ul << 15); // 32KiB |
| 75 out.resize(1024); | 56 out.resize(32); |
| 76 | 57 |
| 77 for (ssize_t exe_used = 0; | 58 ssize_t exe_used = 0; |
| 78 out.length() < OUT_MAX && exe_used >= (ssize_t)(out.length() - 1); | 59 while (out.length() < OUT_MAX && exe_used >= static_cast<ssize_t>(out.length())) { |
| 79 out.resize(out.length() * 2)) { | 60 out.resize(out.length() * 2); |
| 61 | |
| 80 exe_used = readlink(link.c_str(), &out.front(), out.length()); | 62 exe_used = readlink(link.c_str(), &out.front(), out.length()); |
| 81 if (exe_used == (ssize_t)-1 || exe_used < (ssize_t)1) | 63 if (exe_used == (ssize_t)-1 || exe_used < (ssize_t)1) |
| 82 return false; // we got a bad result, i think | 64 return false; // we got a bad result. SAD! |
| 83 } | 65 } |
| 84 | 66 |
| 85 out.resize(out.find('\0')); | 67 out.resize(out.find('\0')); |
| 86 | 68 |
| 87 return true; | 69 return true; |
| 88 } | 70 } |
| 89 | 71 |
| 90 static std::string GetProcessName(pid_t pid) { | 72 static bool GetProcessName(pid_t pid, std::string& result) { |
| 91 std::string result; | 73 const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "comm"; |
| 92 | |
| 93 const std::string path = std::string(PROC_LOCATION) + "/" + std::to_string(pid) + "/comm"; | |
| 94 | 74 |
| 95 if (!util::ReadFile(path, result)) | 75 if (!util::ReadFile(path, result)) |
| 96 return ""; | 76 return false; |
| 97 | 77 |
| 98 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end()); | 78 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end()); |
| 99 | 79 return true; |
| 100 return result; | |
| 101 } | 80 } |
| 102 | 81 |
| 103 bool EnumerateOpenProcesses(process_proc_t process_proc) { | 82 bool EnumerateOpenProcesses(process_proc_t process_proc) { |
| 104 bool success = false; | 83 bool success = false; |
| 105 for (const auto& dir : GetAllFilesInDir(std::string(PROC_LOCATION))) { | 84 |
| 106 pid_t pid; | 85 for (const auto& dir : std::filesystem::directory_iterator{PROC_LOCATION}) { |
| 86 Process proc; | |
| 87 | |
| 107 try { | 88 try { |
| 108 pid = std::stoul(Basename(dir)); | 89 proc.pid = StringToInt(dir.path().stem()); |
| 109 success = true; | 90 success = true; |
| 110 } catch (std::invalid_argument) { | 91 } catch (std::invalid_argument const& ex) { |
| 111 continue; | 92 continue; |
| 112 } | 93 } |
| 113 if (!process_proc({pid, GetProcessName(pid)})) | 94 |
| 95 if (!GetProcessName(proc.pid, proc.name)) | |
| 96 continue; | |
| 97 | |
| 98 if (!process_proc(proc)) | |
| 114 return false; | 99 return false; |
| 115 } | 100 } |
| 101 | |
| 116 return success; | 102 return success; |
| 117 } | 103 } |
| 118 | 104 |
| 119 bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) { | 105 bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) { |
| 120 if (!open_file_proc) | 106 if (!open_file_proc) |
| 121 return false; | 107 return false; |
| 122 | 108 |
| 123 for (const auto& pid : pids) { | 109 for (const auto& pid : pids) { |
| 124 const std::string path = std::string(PROC_LOCATION) + "/" + std::to_string(pid) + "/fd"; | 110 const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "fd"; |
| 125 | 111 |
| 126 for (const auto& dir : GetAllFilesInDir(path)) { | 112 for (const auto& dir : std::filesystem::directory_iterator{path}) { |
| 127 if (!AreFlagsOk(pid, std::stoi(Basename(dir)))) | 113 if (!AreFlagsOk(pid, StringToInt(dir.path().stem()))) |
| 128 continue; | 114 continue; |
| 129 | 115 |
| 130 std::string name; | 116 std::string name; |
| 131 if (!GetFilenameFromFd(dir, name)) | 117 if (!GetFilenameFromFd(dir.path(), name)) |
| 132 continue; | 118 continue; |
| 133 | 119 |
| 134 if (!IsRegularFile(name)) | 120 if (!IsRegularFile(name)) |
| 135 continue; | 121 continue; |
| 136 | 122 |
