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