blob: 067858b608c7f0b731ebcbfa5f8628fd8bf03b6e [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
53void FanError::commit(const json& jsonFFDC)
54{
55 FFDCFiles ffdc;
56 auto ad = getAdditionalData();
57
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 {
74 SDBusPlus::callMethod(loggingService, loggingPath, loggingCreateIface,
75 "CreateWithFFDCFiles", _errorName, _severity, ad,
76 ffdc);
77 }
78 catch (const DBusError& e)
79 {
80 getLogger().log(
81 fmt::format("Call to create a {} error for fan {} failed: {}",
82 _errorName, _fanName, e.what()),
83 Logger::error);
84 }
85}
86
87std::map<std::string, std::string> FanError::getAdditionalData()
88{
89 std::map<std::string, std::string> ad;
90
91 ad.emplace("_PID", std::to_string(getpid()));
92 ad.emplace("CALLOUT_INVENTORY_PATH", _fanName);
93
94 if (!_sensorName.empty())
95 {
96 ad.emplace("FAN_SENSOR", _sensorName);
97 }
98
99 return ad;
100}
101
102std::unique_ptr<FFDCFile> FanError::makeLogFFDCFile()
103{
104 try
105 {
106 auto logFile = getLogger().saveToTempFile();
107 return std::make_unique<FFDCFile>(logFile);
108 }
109 catch (const std::exception& e)
110 {
111 log<level::ERR>(
112 fmt::format("Could not save log contents in FFDC. Error msg: {}",
113 e.what())
114 .c_str());
115 }
116 return nullptr;
117}
118
119std::unique_ptr<FFDCFile> FanError::makeJsonFFDCFile(const json& ffdcData)
120{
121 char tmpFile[] = "/tmp/fanffdc.XXXXXX";
122 auto fd = mkstemp(tmpFile);
123 if (fd != -1)
124 {
125 auto jsonString = ffdcData.dump();
126
127 auto rc = write(fd, jsonString.data(), jsonString.size());
128 close(fd);
129 if (rc != -1)
130 {
131 fs::path jsonFile{tmpFile};
132 return std::make_unique<FFDCFile>(jsonFile);
133 }
134 else
135 {
136 getLogger().log("Failed call to write JSON FFDC file");
137 }
138 }
139 else
140 {
141 auto e = errno;
142 getLogger().log(fmt::format("Failed called to mkstemp, errno = {}", e),
143 Logger::error);
144 }
145 return nullptr;
146}
147
148} // namespace phosphor::fan::monitor