258
|
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
|