comparison dep/animone/src/fd/proc.cc @ 258:862d0d8619f6

*: HUUUGE changes animia has been renamed to animone, so instead of thinking of a health condition, you think of a beautiful flower :) I've also edited some of the code for animone, but I have no idea if it even works or not because I don't have a mac or windows machine lying around. whoops! ... anyway, all of the changes divergent from Anisthesia are now licensed under BSD. it's possible that I could even rewrite most of the code to where I don't even have to keep the MIT license, but that's thinking too far into the future I've been slacking off on implementing the anime seasons page, mostly out of laziness. I think I'd have to create another db file specifically for the seasons anyway, this code is being pushed *primarily* because the hard drive it's on is failing! yay :)
author Paper <paper@paper.us.eu.org>
date Mon, 01 Apr 2024 02:43:44 -0400
parents
children 0718f538c5f9
comparison
equal deleted inserted replaced
257:699a20c57dc8 258:862d0d8619f6
1 #include "animone/fd/proc.h"
2 #include "animone.h"
3 #include "animone/util.h"
4
5 #include <filesystem>
6 #include <fstream>
7 #include <sstream>
8 #include <string>
9
10 #include <fcntl.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13
14 static constexpr std::string_view PROC_LOCATION = "/proc";
15
16 namespace animone::internal::proc {
17
18 static bool IsRegularFile(std::string link) {
19 struct stat sb;
20 if (stat(link.c_str(), &sb) == -1)
21 return false;
22
23 return S_ISREG(sb.st_mode);
24 }
25
26 static bool AreFlagsOk(pid_t pid, int fd) {
27 const std::filesystem::path path =
28 std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "fdinfo" / std::to_string(fd);
29
30 std::ifstream file(path);
31 if (!file)
32 return false;
33
34 int flags = 0;
35 for (std::string line; std::getline(file, line);)
36 if (line.find("flags:", 0) == 0)
37 flags = util::StringToInt(line.substr(line.find_last_not_of("0123456789") + 1));
38
39 if (flags & O_WRONLY || flags & O_RDWR)
40 return false;
41
42 return true;
43 }
44
45 static bool GetFilenameFromFd(std::string link, std::string& out) {
46 /* /proc is a "virtual filesystem", so we have to guess the path size. yippee! */
47 constexpr size_t OUT_MAX = (1ul << 15); // 32KiB
48 out.resize(32);
49
50 ssize_t exe_used = 0;
51 do {
52 out.resize(out.length() * 2);
53
54 exe_used = readlink(link.c_str(), &out.front(), out.length());
55 if (exe_used == (ssize_t)-1 || exe_used < (ssize_t)1)
56 return false; // we got a bad result. SAD!
57 } while (out.length() < OUT_MAX && exe_used >= static_cast<ssize_t>(out.length()));
58
59 out.resize(out.find('\0'));
60
61 return true;
62 }
63
64 static bool IsSystemFile(const std::string& path) {
65 static constexpr std::array<std::string_view, 9> invalid_paths = {"/boot", "/dev", "/bin", "/usr", "/opt",
66 "/proc", "/var", "/etc", "/dev"};
67
68 for (const auto& invalid_path : invalid_paths) {
69 if (!path.rfind(invalid_path, 0)) {
70 return true;
71 }
72 }
73
74 return false;
75 }
76
77 bool GetProcessName(pid_t pid, std::string& result) {
78 const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "comm";
79
80 if (!util::ReadFile(path, result))
81 return false;
82
83 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
84 return true;
85 }
86
87 bool EnumerateOpenProcesses(process_proc_t process_proc) {
88 bool success = false;
89
90 for (const auto& dir : std::filesystem::directory_iterator{PROC_LOCATION}) {
91 Process proc;
92
93 try {
94 proc.pid = util::StringToInt(dir.path().stem());
95 success = true;
96 } catch (std::invalid_argument const& ex) {
97 continue;
98 }
99
100 if (!GetProcessName(proc.pid, proc.name))
101 continue;
102
103 if (!process_proc(proc))
104 return false;
105 }
106
107 return success;
108 }
109
110 bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) {
111 if (!open_file_proc)
112 return false;
113
114 for (const auto& pid : pids) {
115 const std::filesystem::path path = std::filesystem::path(PROC_LOCATION) / std::to_string(pid) / "fd";
116
117 for (const auto& dir : std::filesystem::directory_iterator{path}) {
118 if (!AreFlagsOk(pid, util::StringToInt(dir.path().stem())))
119 continue;
120
121 std::string name;
122 if (!GetFilenameFromFd(dir.path(), name))
123 continue;
124
125 if (!IsRegularFile(name))
126 continue;
127
128 if (IsSystemFile(name))
129 continue;
130
131 if (!open_file_proc({pid, name}))
132 return false;
133 }
134 }
135 return true;
136 }
137
138 } // namespace animia::internal::proc