blob: bb98598a76e5d2a36d8f6633cfbccf827857b121 [file] [log] [blame]
Matt Spinlerf13b42e2020-10-26 15:29:49 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "fan_error.hpp"
17
18#include "logging.hpp"
19#include "sdbusplus.hpp"
20
21#include <nlohmann/json.hpp>
22#include <xyz/openbmc_project/Logging/Create/server.hpp>
23
24#include <filesystem>
25
26namespace phosphor::fan::monitor
27{
28
29using FFDCFormat =
30 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat;
31using FFDCFiles = std::vector<
32 std::tuple<FFDCFormat, uint8_t, uint8_t, sdbusplus::message::unix_fd>>;
33using json = nlohmann::json;
34
35const auto loggingService = "xyz.openbmc_project.Logging";
36const auto loggingPath = "/xyz/openbmc_project/logging";
37const auto loggingCreateIface = "xyz.openbmc_project.Logging.Create";
38
39namespace fs = std::filesystem;
40using namespace phosphor::fan::util;
41
42FFDCFile::FFDCFile(const fs::path& name) :
43 _fd(open(name.c_str(), O_RDONLY)), _name(name)
44{
45 if (_fd() == -1)
46 {
47 auto e = errno;
48 getLogger().log(fmt::format("Could not open FFDC file {}. errno {}",
49 _name.string(), e));
50 }
51}
52
Matt Spinlerf435eb12021-05-11 14:44:25 -050053void FanError::commit(const json& jsonFFDC, bool isPowerOffError)
Matt Spinlerf13b42e2020-10-26 15:29:49 -050054{
55 FFDCFiles ffdc;
Matt Spinlerf435eb12021-05-11 14:44:25 -050056 auto ad = getAdditionalData(isPowerOffError);
Matt Spinlerf13b42e2020-10-26 15:29:49 -050057
58 // Add the Logger contents as FFDC
59 auto logFile = makeLogFFDCFile();
60 if (logFile && (logFile->fd() != -1))
61 {
62 ffdc.emplace_back(FFDCFormat::Text, 0x01, 0x01, logFile->fd());
63 }
64
65 // Add the passed in JSON as FFDC
66 auto ffdcFile = makeJsonFFDCFile(jsonFFDC);
67 if (ffdcFile && (ffdcFile->fd() != -1))
68 {
69 ffdc.emplace_back(FFDCFormat::JSON, 0x01, 0x01, ffdcFile->fd());
70 }
71
72 try
73 {
Matt Spinlerf435eb12021-05-11 14:44:25 -050074 auto sev = _severity;
75
76 // If this is a power off, change severity to Critical
77 if (isPowerOffError)
78 {
79 using namespace sdbusplus::xyz::openbmc_project::Logging::server;
80 sev = convertForMessage(Entry::Level::Critical);
81 }
Matt Spinlerf13b42e2020-10-26 15:29:49 -050082 SDBusPlus::callMethod(loggingService, loggingPath, loggingCreateIface,
Matt Spinlerf435eb12021-05-11 14:44:25 -050083 "CreateWithFFDCFiles", _errorName, sev, ad, ffdc);
Matt Spinlerf13b42e2020-10-26 15:29:49 -050084 }
85 catch (const DBusError& e)
86 {
87 getLogger().log(
88 fmt::format("Call to create a {} error for fan {} failed: {}",
89 _errorName, _fanName, e.what()),
90 Logger::error);
91 }
92}
93
Matt Spinlerf435eb12021-05-11 14:44:25 -050094std::map<std::string, std::string>
95 FanError::getAdditionalData(bool isPowerOffError)
Matt Spinlerf13b42e2020-10-26 15:29:49 -050096{
97 std::map<std::string, std::string> ad;
98
99 ad.emplace("_PID", std::to_string(getpid()));
100 ad.emplace("CALLOUT_INVENTORY_PATH", _fanName);
101
102 if (!_sensorName.empty())
103 {
104 ad.emplace("FAN_SENSOR", _sensorName);
105 }
106
Matt Spinlerf435eb12021-05-11 14:44:25 -0500107 // If this is a power off, specify that it's a power
108 // fault and a system termination. This is used by some
109 // implementations for service reasons.
110 if (isPowerOffError)
111 {
112 ad.emplace("POWER_THERMAL_CRITICAL_FAULT", "TRUE");
113 ad.emplace("SEVERITY_DETAIL", "SYSTEM_TERM");
114 }
115
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500116 return ad;
117}
118
119std::unique_ptr<FFDCFile> FanError::makeLogFFDCFile()
120{
121 try
122 {
123 auto logFile = getLogger().saveToTempFile();
124 return std::make_unique<FFDCFile>(logFile);
125 }
126 catch (const std::exception& e)
127 {
128 log<level::ERR>(
129 fmt::format("Could not save log contents in FFDC. Error msg: {}",
130 e.what())
131 .c_str());
132 }
133 return nullptr;
134}
135
136std::unique_ptr<FFDCFile> FanError::makeJsonFFDCFile(const json& ffdcData)
137{
138 char tmpFile[] = "/tmp/fanffdc.XXXXXX";
139 auto fd = mkstemp(tmpFile);
140 if (fd != -1)
141 {
142 auto jsonString = ffdcData.dump();
143
144 auto rc = write(fd, jsonString.data(), jsonString.size());
145 close(fd);
146 if (rc != -1)
147 {
148 fs::path jsonFile{tmpFile};
149 return std::make_unique<FFDCFile>(jsonFile);
150 }
151 else
152 {
153 getLogger().log("Failed call to write JSON FFDC file");
154 }
155 }
156 else
157 {
158 auto e = errno;
159 getLogger().log(fmt::format("Failed called to mkstemp, errno = {}", e),
160 Logger::error);
161 }
162 return nullptr;
163}
164
165} // namespace phosphor::fan::monitor