Mercurial > minori
comparison dep/animia/src/linux.cpp @ 56:6ff7aabeb9d7
deps: add animia for open files detection
| author | Paper <mrpapersonic@gmail.com> |
|---|---|
| date | Thu, 28 Sep 2023 12:35:21 -0400 |
| parents | |
| children | 4c6dd5999b39 |
comparison
equal
deleted
inserted
replaced
| 54:466ac9870df9 | 56:6ff7aabeb9d7 |
|---|---|
| 1 #include <string> | |
| 2 #include <vector> | |
| 3 #include <fstream> | |
| 4 #include <filesystem> | |
| 5 #include <unordered_map> | |
| 6 #include <iostream> | |
| 7 #include <sstream> | |
| 8 #include <unistd.h> | |
| 9 #include <sys/stat.h> | |
| 10 #include <fcntl.h> | |
| 11 #include <algorithm> | |
| 12 | |
| 13 #define PROC_LOCATION "/proc" | |
| 14 | |
| 15 namespace Animia::Linux { | |
| 16 | |
| 17 std::vector<int> get_all_pids() { | |
| 18 std::vector<int> ret; | |
| 19 for (const auto& dir : std::filesystem::directory_iterator(PROC_LOCATION)) { | |
| 20 int pid; | |
| 21 try { | |
| 22 pid = std::stoi(dir.path().stem()); | |
| 23 } catch (std::invalid_argument) { | |
| 24 continue; | |
| 25 } | |
| 26 ret.push_back(pid); | |
| 27 } | |
| 28 return ret; | |
| 29 } | |
| 30 | |
| 31 std::string get_process_name(int pid) { | |
| 32 std::string path = PROC_LOCATION "/" + std::to_string(pid) + "/comm"; | |
| 33 std::ifstream t(path); | |
| 34 std::stringstream buf; | |
| 35 buf << t.rdbuf(); | |
| 36 std::string str = buf.str(); | |
| 37 str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); | |
| 38 return str; | |
| 39 } | |
| 40 | |
| 41 static bool is_regular_file(std::string link) { | |
| 42 struct stat sb; | |
| 43 if (stat(link.c_str(), &sb) == -1) | |
| 44 return false; | |
| 45 return S_ISREG(sb.st_mode); | |
| 46 } | |
| 47 | |
| 48 static bool are_flags_ok(int pid, int fd) { | |
| 49 std::string path = PROC_LOCATION "/" + std::to_string(pid) + "/fdinfo/" + std::to_string(fd); | |
| 50 std::ifstream t(path); | |
| 51 std::stringstream buffer; | |
| 52 buffer << t.rdbuf(); | |
| 53 std::string raw; | |
| 54 int flags = 0; | |
| 55 while (std::getline(buffer, raw)) { | |
| 56 if (raw.rfind("flags:", 0) == 0) { | |
| 57 flags = std::stoi(raw.substr(raw.find_last_not_of("0123456789") + 1)); | |
| 58 } | |
| 59 } | |
| 60 if (flags & O_WRONLY || flags & O_RDWR) | |
| 61 return false; | |
| 62 return true; | |
| 63 } | |
| 64 | |
| 65 static int get_size_of_link(std::string link) { | |
| 66 struct stat sb; | |
| 67 if (lstat(link.c_str(), &sb) == -1) | |
| 68 return -1; | |
| 69 return sb.st_size + 1; | |
| 70 } | |
| 71 | |
| 72 std::vector<std::string> get_open_files(int pid) { | |
| 73 std::vector<std::string> ret; | |
| 74 std::string path = PROC_LOCATION "/" + std::to_string(pid) + "/fd"; | |
| 75 try { | |
| 76 for (const auto& dir : std::filesystem::directory_iterator(path)) { | |
| 77 if (!are_flags_ok(pid, std::stoi(dir.path().stem()))) | |
| 78 continue; | |
| 79 /* get filename size */ | |
| 80 int size = get_size_of_link(dir.path().string()); | |
| 81 /* allocate buffer */ | |
| 82 char* buf = (char*)calloc(size, sizeof(char)); | |
| 83 //std::string buf('\0', size); | |
| 84 /* read filename to buffer */ | |
| 85 int r = readlink(dir.path().c_str(), buf, size); | |
| 86 | |
| 87 if (r < 0) | |
| 88 continue; | |
| 89 if (!is_regular_file(buf)) | |
| 90 continue; | |
| 91 ret.push_back(buf); | |
| 92 free(buf); | |
| 93 } | |
| 94 } catch (std::filesystem::filesystem_error const& ex) { | |
| 95 if (ex.code().value() != 13) // 13 == permissions error, common with /proc, ignore | |
| 96 throw; | |
| 97 } | |
| 98 return ret; | |
| 99 } | |
| 100 | |
| 101 std::unordered_map<int, std::vector<std::string>> get_all_open_files() { | |
| 102 std::unordered_map<int, std::vector<std::string>> map; | |
| 103 std::vector<int> pids = get_all_pids(); | |
| 104 for (int i: pids) | |
| 105 map[i] = get_open_files(i); | |
| 106 return map; | |
| 107 } | |
| 108 | |
| 109 } |
