blob: 15d8ed0a60905abf91b4e2fff6fc26ef94da5a37 [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()));
Matt Spinlerbb449c12021-06-14 11:45:28 -0600100
101 if (!_fanName.empty())
102 {
103 ad.emplace("CALLOUT_INVENTORY_PATH", _fanName);
104 }
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500105
106 if (!_sensorName.empty())
107 {
108 ad.emplace("FAN_SENSOR", _sensorName);
109 }
110
Matt Spinlerf435eb12021-05-11 14:44:25 -0500111 // If this is a power off, specify that it's a power
112 // fault and a system termination. This is used by some
113 // implementations for service reasons.
114 if (isPowerOffError)
115 {
Matt Spinlerf435eb12021-05-11 14:44:25 -0500116 ad.emplace("SEVERITY_DETAIL", "SYSTEM_TERM");
117 }
118
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500119 return ad;
120}
121
122std::unique_ptr<FFDCFile> FanError::makeLogFFDCFile()
123{
124 try
125 {
126 auto logFile = getLogger().saveToTempFile();
127 return std::make_unique<FFDCFile>(logFile);
128 }
129 catch (const std::exception& e)
130 {
131 log<level::ERR>(
132 fmt::format("Could not save log contents in FFDC. Error msg: {}",
133 e.what())
134 .c_str());
135 }
136 return nullptr;
137}
138
139std::unique_ptr<FFDCFile> FanError::makeJsonFFDCFile(const json& ffdcData)
140{
141 char tmpFile[] = "/tmp/fanffdc.XXXXXX";
142 auto fd = mkstemp(tmpFile);
143 if (fd != -1)
144 {
145 auto jsonString = ffdcData.dump();
146
147 auto rc = write(fd, jsonString.data(), jsonString.size());
148 close(fd);
149 if (rc != -1)
150 {
151 fs::path jsonFile{tmpFile};
152 return std::make_unique<FFDCFile>(jsonFile);
153 }
154 else
155 {
156 getLogger().log("Failed call to write JSON FFDC file");
157 }
158 }
159 else
160 {
161 auto e = errno;
162 getLogger().log(fmt::format("Failed called to mkstemp, errno = {}", e),
163 Logger::error);
164 }
165 return nullptr;
166}
167
168} // namespace phosphor::fan::monitor