blob: 77043f396a4beb956e587d6f5589c9956dc8d8cd [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
Patrick Williamsfc2b0782024-02-29 11:15:52 -060025 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);
Matt Spinlerbb449c12021-06-14 11:45:28 -060029 if (!pipe)
30 {
31 getLogger().log(
Patrick Williamsfbf47032023-07-17 12:27:34 -050032 std::format("popen() failed when running command: {}", command));
Matt Spinlerbb449c12021-06-14 11:45:28 -060033 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
43std::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 {
Patrick Williamsfbf47032023-07-17 12:27:34 -050050 getLogger().log(std::format("Hwmon base directory {} doesn't exist",
Matt Spinlerbb449c12021-06-14 11:45:28 -060051 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(
Patrick Williamsfbf47032023-07-17 12:27:34 -050080 std::format("Error traversing hwmon directories: {}", e.what()));
Matt Spinlerbb449c12021-06-14 11:45:28 -060081 }
82
83 return hwmonNames;
84}
85
86std::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
118nlohmann::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