1 #include "hwmon_ffdc.hpp" 2 3 #include "logging.hpp" 4 5 #include <array> 6 #include <filesystem> 7 #include <format> 8 #include <fstream> 9 #include <string> 10 #include <vector> 11 12 namespace phosphor::fan::monitor 13 { 14 15 namespace util 16 { 17 18 namespace fs = std::filesystem; 19 20 inline std::vector<std::string> executeCommand(const std::string& command) 21 { 22 std::vector<std::string> output; 23 std::array<char, 128> buffer; 24 25 auto pipe_close = [](auto fd) { (void)pclose(fd); }; 26 27 std::unique_ptr<FILE, decltype(pipe_close)> pipe( 28 popen(command.c_str(), "r"), pipe_close); 29 if (!pipe) 30 { 31 getLogger().log( 32 std::format("popen() failed when running command: {}", command)); 33 return output; 34 } 35 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) 36 { 37 output.emplace_back(buffer.data()); 38 } 39 40 return output; 41 } 42 43 std::vector<std::string> getHwmonNameFFDC() 44 { 45 const fs::path hwmonBaseDir{"/sys/class/hwmon"}; 46 std::vector<std::string> hwmonNames; 47 48 if (!fs::exists(hwmonBaseDir)) 49 { 50 getLogger().log(std::format("Hwmon base directory {} doesn't exist", 51 hwmonBaseDir.native())); 52 return hwmonNames; 53 } 54 55 try 56 { 57 for (const auto& path : fs::directory_iterator(hwmonBaseDir)) 58 { 59 if (!path.is_directory()) 60 { 61 continue; 62 } 63 64 auto nameFile = path.path() / "name"; 65 if (fs::exists(nameFile)) 66 { 67 std::ifstream f{nameFile}; 68 if (f.good()) 69 { 70 std::string name; 71 f >> name; 72 hwmonNames.push_back(name); 73 } 74 } 75 } 76 } 77 catch (const std::exception& e) 78 { 79 getLogger().log( 80 std::format("Error traversing hwmon directories: {}", e.what())); 81 } 82 83 return hwmonNames; 84 } 85 86 std::vector<std::string> getDmesgFFDC() 87 { 88 std::vector<std::string> output; 89 auto dmesgOutput = executeCommand("dmesg"); 90 91 // Only pull in dmesg lines with interesting keywords. 92 // One example is: 93 // [ 16.390603] max31785: probe of 7-0052 failed with error -110 94 // using ' probe' to avoid 'modprobe' 95 std::vector<std::string> matches{" probe", "failed"}; 96 97 for (const auto& line : dmesgOutput) 98 { 99 for (const auto& m : matches) 100 { 101 if (line.find(m) != std::string::npos) 102 { 103 output.push_back(line); 104 if (output.back().back() == '\n') 105 { 106 output.back().pop_back(); 107 } 108 break; 109 } 110 } 111 } 112 113 return output; 114 } 115 116 } // namespace util 117 118 nlohmann::json collectHwmonFFDC() 119 { 120 nlohmann::json ffdc; 121 122 auto hwmonNames = util::getHwmonNameFFDC(); 123 if (!hwmonNames.empty()) 124 { 125 ffdc["hwmonNames"] = std::move(hwmonNames); 126 } 127 128 auto dmesg = util::getDmesgFFDC(); 129 if (!dmesg.empty()) 130 { 131 ffdc["dmesg"] = std::move(dmesg); 132 } 133 134 return ffdc; 135 } 136 137 } // namespace phosphor::fan::monitor 138