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