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