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