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