comparison dep/animia/src/platform/linux/fd.cc @ 137:69db40272acd

dep/animia: [WIP] huge refactor this WILL NOT compile, because lots of code has been changed and every API in the original codebase has been removed. note that this api setup is not exactly permanent...
author Paper <mrpapersonic@gmail.com>
date Fri, 10 Nov 2023 13:52:47 -0500
parents
children
comparison
equal deleted inserted replaced
136:7d3ad9529c4c 137:69db40272acd
1 #include <algorithm>
2 #include <fcntl.h>
3 #include <filesystem>
4 #include <fstream>
5 #include <iostream>
6 #include <sstream>
7 #include <string>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <unordered_map>
11 #include <vector>
12 #include <cstring>
13 #include <dirent.h>
14
15 #define PROC_LOCATION "/proc"
16
17 namespace Animia { namespace Linux {
18
19 std::vector<std::string> get_all_files_in_dir(const std::string& _dir) {
20 std::vector<std::string> ret;
21
22 DIR* dir = opendir(_dir.c_str());
23 if (!dir)
24 return ret;
25
26 struct dirent* dp;
27 while ((dp = readdir(dir)) != NULL) {
28 if (!(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")))
29 ret.push_back(_dir + "/" + dp->d_name);
30 }
31
32 closedir(dir);
33 return ret;
34 }
35
36 std::string basename(const std::string& path) {
37 return path.substr(path.find_last_of("/") + 1, path.length());
38 }
39
40 std::string stem(const std::string& path) {
41 std::string bn = basename(path);
42 return bn.substr(0, path.find_last_of("."));
43 }
44
45 std::vector<int> get_all_pids() {
46 std::vector<int> ret;
47
48 for (const auto& dir : get_all_files_in_dir(PROC_LOCATION)) {
49 int pid;
50 try {
51 pid = std::stoi(basename(dir));
52 } catch (std::invalid_argument) {
53 continue;
54 }
55 ret.push_back(pid);
56 }
57
58 return ret;
59 }
60
61 std::string get_process_name(int pid) {
62 std::string path = PROC_LOCATION "/" + std::to_string(pid) + "/comm";
63 std::ifstream t(path);
64 std::stringstream buf;
65 buf << t.rdbuf();
66
67 std::string str = buf.str();
68 str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
69 return str;
70 }
71
72 static bool is_regular_file(std::string link) {
73 struct stat sb;
74 if (stat(link.c_str(), &sb) == -1)
75 return false;
76 return S_ISREG(sb.st_mode);
77 }
78
79 static bool are_flags_ok(int pid, int fd) {
80 std::string path = PROC_LOCATION "/" + std::to_string(pid) + "/fdinfo/" + std::to_string(fd);
81 std::ifstream t(path);
82 std::stringstream buffer;
83 buffer << t.rdbuf();
84 std::string raw;
85 int flags = 0;
86 while (std::getline(buffer, raw)) {
87 if (raw.rfind("flags:", 0) == 0) {
88 flags = std::stoi(raw.substr(raw.find_last_not_of("0123456789") + 1));
89 }
90 }
91 if (flags & O_WRONLY || flags & O_RDWR)
92 return false;
93 return true;
94 }
95
96 static std::string get_name_from_fd(std::string link) {
97 size_t exe_size = 1024;
98 ssize_t exe_used;
99 std::string ret;
100 while (1) {
101 ret = std::string(exe_size, '\0');
102 exe_used = readlink(link.c_str(), &ret.front(), ret.length());
103 if (exe_used == (ssize_t)-1)
104 return NULL;
105
106 if (exe_used < (ssize_t)1) {
107 errno = ENOENT;
108 return NULL;
109 }
110
111 if (exe_used < (ssize_t)(exe_size - 1))
112 break;
113
114 exe_size += 1024;
115 }
116
117 return ret.c_str();
118 }
119
120 std::vector<std::string> get_open_files(int pid) {
121 std::vector<std::string> ret;
122 std::string path = PROC_LOCATION "/" + std::to_string(pid) + "/fd";
123
124 for (const auto& dir : get_all_files_in_dir(path)) {
125 if (!are_flags_ok(pid, std::stoi(basename(dir))))
126 continue;
127
128 std::string buf = get_name_from_fd(dir);
129
130 if (!is_regular_file(buf))
131 continue;
132
133 ret.push_back(buf);
134 }
135 return ret;
136 }
137
138 std::unordered_map<int, std::vector<std::string>> get_all_open_files() {
139 std::unordered_map<int, std::vector<std::string>> map;
140 std::vector<int> pids = get_all_pids();
141 for (int i : pids)
142 map[i] = get_open_files(i);
143 return map;
144 }
145
146 } // namespace Linux
147 } // namespace Animia