1 #pragma once
2 
3 #include "elog_entry.hpp"
4 #include "xyz/openbmc_project/Collection/DeleteAll/server.hpp"
5 #include "xyz/openbmc_project/Logging/Create/server.hpp"
6 #include "xyz/openbmc_project/Logging/Entry/server.hpp"
7 #include "xyz/openbmc_project/Logging/Internal/Manager/server.hpp"
8 
9 #include <list>
10 #include <phosphor-logging/log.hpp>
11 #include <sdbusplus/bus.hpp>
12 
13 namespace phosphor
14 {
15 namespace logging
16 {
17 
18 extern const std::map<std::string, std::vector<std::string>> g_errMetaMap;
19 extern const std::map<std::string, level> g_errLevelMap;
20 
21 using CreateIface = sdbusplus::xyz::openbmc_project::Logging::server::Create;
22 using DeleteAllIface =
23     sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll;
24 
25 namespace details
26 {
27 template <typename... T>
28 using ServerObject = typename sdbusplus::server::object::object<T...>;
29 
30 using ManagerIface =
31     sdbusplus::xyz::openbmc_project::Logging::Internal::server::Manager;
32 
33 } // namespace details
34 
35 constexpr size_t ffdcFormatPos = 0;
36 constexpr size_t ffdcSubtypePos = 1;
37 constexpr size_t ffdcVersionPos = 2;
38 constexpr size_t ffdcFDPos = 3;
39 
40 using FFDCEntry = std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
41                              sdbusplus::message::unix_fd>;
42 
43 using FFDCEntries = std::vector<FFDCEntry>;
44 
45 namespace internal
46 {
47 
48 /** @class Manager
49  *  @brief OpenBMC logging manager implementation.
50  *  @details A concrete implementation for the
51  *  xyz.openbmc_project.Logging.Internal.Manager DBus API.
52  */
53 class Manager : public details::ServerObject<details::ManagerIface>
54 {
55   public:
56     Manager() = delete;
57     Manager(const Manager&) = delete;
58     Manager& operator=(const Manager&) = delete;
59     Manager(Manager&&) = delete;
60     Manager& operator=(Manager&&) = delete;
61     virtual ~Manager() = default;
62 
63     /** @brief Constructor to put object onto bus at a dbus path.
64      *  @param[in] bus - Bus to attach to.
65      *  @param[in] path - Path to attach at.
66      */
67     Manager(sdbusplus::bus::bus& bus, const char* objPath) :
68         details::ServerObject<details::ManagerIface>(bus, objPath), busLog(bus),
69         entryId(0), fwVersion(readFWVersion()){};
70 
71     /*
72      * @fn commit()
73      * @brief sd_bus Commit method implementation callback.
74      * @details Create an error/event log based on transaction id and
75      *          error message.
76      * @param[in] transactionId - Unique identifier of the journal entries
77      *                            to be committed.
78      * @param[in] errMsg - The error exception message associated with the
79      *                     error log to be committed.
80      */
81     void commit(uint64_t transactionId, std::string errMsg) override;
82 
83     /*
84      * @fn commit()
85      * @brief sd_bus CommitWithLvl method implementation callback.
86      * @details Create an error/event log based on transaction id and
87      *          error message.
88      * @param[in] transactionId - Unique identifier of the journal entries
89      *                            to be committed.
90      * @param[in] errMsg - The error exception message associated with the
91      *                     error log to be committed.
92      * @param[in] errLvl - level of the error
93      */
94     void commitWithLvl(uint64_t transactionId, std::string errMsg,
95                        uint32_t errLvl) override;
96 
97     /** @brief Erase specified entry d-bus object
98      *
99      * @param[in] entryId - unique identifier of the entry
100      */
101     void erase(uint32_t entryId);
102 
103     /** @brief Construct error d-bus objects from their persisted
104      *         representations.
105      */
106     void restore();
107 
108     /** @brief  Erase all error log entries
109      *
110      */
111     void eraseAll()
112     {
113         auto iter = entries.begin();
114         while (iter != entries.end())
115         {
116             auto e = iter->first;
117             ++iter;
118             erase(e);
119         }
120     }
121 
122     /** @brief Returns the count of high severity errors
123      *
124      *  @return int - count of real errors
125      */
126     int getRealErrSize();
127 
128     /** @brief Returns the count of Info errors
129      *
130      *  @return int - count of info errors
131      */
132     int getInfoErrSize();
133 
134     sdbusplus::bus::bus& getBus()
135     {
136         return busLog;
137     }
138 
139     /** @brief Creates an event log
140      *
141      *  This is an alternative to the _commit() API.  It doesn't use
142      *  the journal to look up event log metadata like _commit does.
143      *
144      * @param[in] errMsg - The error exception message associated with the
145      *                     error log to be committed.
146      * @param[in] severity - level of the error
147      * @param[in] additionalData - The AdditionalData property for the error
148      */
149     void create(
150         const std::string& message,
151         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
152         const std::map<std::string, std::string>& additionalData);
153 
154     /** @brief Creates an event log, and accepts FFDC files
155      *
156      * This is the same as create(), but also takes an FFDC argument.
157      *
158      * The FFDC argument is a vector of tuples that allows one to pass in file
159      * descriptors for files that contain FFDC (First Failure Data Capture).
160      * These will be passed to any event logging extensions.
161      *
162      * @param[in] errMsg - The error exception message associated with the
163      *                     error log to be committed.
164      * @param[in] severity - level of the error
165      * @param[in] additionalData - The AdditionalData property for the error
166      * @param[in] ffdc - A vector of FFDC file info
167      */
168     void createWithFFDC(
169         const std::string& message,
170         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
171         const std::map<std::string, std::string>& additionalData,
172         const FFDCEntries& ffdc);
173 
174     /** @brief Common wrapper for creating an Entry object
175      *
176      * @return true if quiesce on error setting is enabled, false otherwise
177      */
178     bool isQuiesceOnErrorEnabled();
179 
180     /** @brief Check if error has callout and if so, block boot
181      *
182      * @param[in] entry - The error to check for callouts
183      */
184     void checkQuiesceOnError(const Entry& entry);
185 
186   private:
187     /*
188      * @fn _commit()
189      * @brief commit() helper
190      * @param[in] transactionId - Unique identifier of the journal entries
191      *                            to be committed.
192      * @param[in] errMsg - The error exception message associated with the
193      *                     error log to be committed.
194      * @param[in] errLvl - level of the error
195      */
196     void _commit(uint64_t transactionId, std::string&& errMsg,
197                  Entry::Level errLvl);
198 
199     /** @brief Call metadata handler(s), if any. Handlers may create
200      *         associations.
201      *  @param[in] errorName - name of the error
202      *  @param[in] additionalData - list of metadata (in key=value format)
203      *  @param[out] objects - list of error's association objects
204      */
205     void processMetadata(const std::string& errorName,
206                          const std::vector<std::string>& additionalData,
207                          AssociationList& objects) const;
208 
209     /** @brief Synchronize unwritten journal messages to disk.
210      *  @details This is the same implementation as the systemd command
211      *  "journalctl --sync".
212      */
213     void journalSync();
214 
215     /** @brief Reads the BMC code level
216      *
217      *  @return std::string - the version string
218      */
219     static std::string readFWVersion();
220 
221     /** @brief Call any create() functions provided by any extensions.
222      *  This is called right after an event log is created to allow
223      *  extensions to create their own log based on this one.
224      *
225      *  @param[in] entry - the new event log entry
226      *  @param[in] ffdc - A vector of FFDC file info
227      */
228     void doExtensionLogCreate(const Entry& entry, const FFDCEntries& ffdc);
229 
230     /** @brief Common wrapper for creating an Entry object
231      *
232      * @param[in] errMsg - The error exception message associated with the
233      *                     error log to be committed.
234      * @param[in] errLvl - level of the error
235      * @param[in] additionalData - The AdditionalData property for the error
236      * @param[in] ffdc - A vector of FFDC file info. Defaults to an empty
237      * vector.
238      */
239     void createEntry(std::string errMsg, Entry::Level errLvl,
240                      std::vector<std::string> additionalData,
241                      const FFDCEntries& ffdc = FFDCEntries{});
242 
243     /** @brief Persistent sdbusplus DBus bus connection. */
244     sdbusplus::bus::bus& busLog;
245 
246     /** @brief Persistent map of Entry dbus objects and their ID */
247     std::map<uint32_t, std::unique_ptr<Entry>> entries;
248 
249     /** @brief List of error ids for high severity errors */
250     std::list<uint32_t> realErrors;
251 
252     /** @brief List of error ids for Info(and below) severity */
253     std::list<uint32_t> infoErrors;
254 
255     /** @brief Id of last error log entry */
256     uint32_t entryId;
257 
258     /** @brief The BMC firmware version */
259     const std::string fwVersion;
260 };
261 
262 } // namespace internal
263 
264 /** @class Manager
265  *  @brief Implementation for deleting all error log entries and
266  *         creating new logs.
267  *  @details A concrete implementation for the
268  *           xyz.openbmc_project.Collection.DeleteAll and
269  *           xyz.openbmc_project.Logging.Create interfaces.
270  */
271 class Manager : public details::ServerObject<DeleteAllIface, CreateIface>
272 {
273   public:
274     Manager() = delete;
275     Manager(const Manager&) = delete;
276     Manager& operator=(const Manager&) = delete;
277     Manager(Manager&&) = delete;
278     Manager& operator=(Manager&&) = delete;
279     virtual ~Manager() = default;
280 
281     /** @brief Constructor to put object onto bus at a dbus path.
282      *         Defer signal registration (pass true for deferSignal to the
283      *         base class) until after the properties are set.
284      *  @param[in] bus - Bus to attach to.
285      *  @param[in] path - Path to attach at.
286      *  @param[in] manager - Reference to internal manager object.
287      */
288     Manager(sdbusplus::bus::bus& bus, const std::string& path,
289             internal::Manager& manager) :
290         details::ServerObject<DeleteAllIface, CreateIface>(bus, path.c_str(),
291                                                            true),
292         manager(manager){};
293 
294     /** @brief Delete all d-bus objects.
295      */
296     void deleteAll()
297     {
298         manager.eraseAll();
299     }
300 
301     /** @brief D-Bus method call implementation to create an event log.
302      *
303      * @param[in] errMsg - The error exception message associated with the
304      *                     error log to be committed.
305      * @param[in] severity - Level of the error
306      * @param[in] additionalData - The AdditionalData property for the error
307      */
308     void create(
309         std::string message,
310         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
311         std::map<std::string, std::string> additionalData) override
312     {
313         manager.create(message, severity, additionalData);
314     }
315 
316     /** @brief D-Bus method call implementation to create an event log with FFDC
317      *
318      * The same as create(), but takes an extra FFDC argument.
319      *
320      * @param[in] errMsg - The error exception message associated with the
321      *                     error log to be committed.
322      * @param[in] severity - Level of the error
323      * @param[in] additionalData - The AdditionalData property for the error
324      * @param[in] ffdc - A vector of FFDC file info
325      */
326     void createWithFFDCFiles(
327         std::string message,
328         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
329         std::map<std::string, std::string> additionalData,
330         std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
331                                sdbusplus::message::unix_fd>>
332             ffdc) override
333     {
334         manager.createWithFFDC(message, severity, additionalData, ffdc);
335     }
336 
337   private:
338     /** @brief This is a reference to manager object */
339     internal::Manager& manager;
340 };
341 
342 } // namespace logging
343 } // namespace phosphor
344