blob: d8069e4976c88e68aca88f16adf72ccd1037b743 [file] [log] [blame]
Matt Spinlerbb449c12021-06-14 11:45:28 -06001#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
13namespace phosphor::fan::monitor
14{
15
16namespace util
17{
18
19namespace fs = std::filesystem;
20
21inline 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
42std::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
85std::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
117nlohmann::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