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 |