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