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