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      * @param[in] ffdc - A vector of tuples that allows one to pass in file
194      *                   descriptors for files that contain FFDC (First
195      *                   Failure Data Capture). These will be passed to any
196      *                   event logging extensions.
197      */
198     void create(const std::string& message, Severity severity,
199                 const std::map<std::string, std::string>& additionalData,
200                 const FFDCEntries& ffdc = FFDCEntries{});
201 
202     /** @brief Common wrapper for creating an Entry object
203      *
204      * @return true if quiesce on error setting is enabled, false otherwise
205      */
206     bool isQuiesceOnErrorEnabled();
207 
208     /** @brief Create boot block association and quiesce host if running
209      *
210      * @param[in] entryId - The ID of the phosphor logging error
211      */
212     void quiesceOnError(const uint32_t entryId);
213 
214     /** @brief Check if inventory callout present in input entry
215      *
216      * @param[in] entry - The error to check for callouts
217      *
218      * @return true if inventory item in associations, false otherwise
219      */
220     bool isCalloutPresent(const Entry& entry);
221 
222     /** @brief Check (and remove) entry being erased from blocking errors
223      *
224      * @param[in] entryId - The entry that is being erased
225      */
226     void checkAndRemoveBlockingError(uint32_t entryId);
227 
228     /** @brief Persistent map of Entry dbus objects and their ID */
229     std::map<uint32_t, std::unique_ptr<Entry>> entries;
230 
231   private:
232     /*
233      * @fn _commit()
234      * @brief commit() helper
235      * @param[in] transactionId - Unique identifier of the journal entries
236      *                            to be committed.
237      * @param[in] errMsg - The error exception message associated with the
238      *                     error log to be committed.
239      * @param[in] errLvl - level of the error
240      */
241     void _commit(uint64_t transactionId, std::string&& errMsg,
242                  Entry::Level errLvl);
243 
244     /** @brief Call metadata handler(s), if any. Handlers may create
245      *         associations.
246      *  @param[in] errorName - name of the error
247      *  @param[in] additionalData - list of metadata (in key=value format)
248      *  @param[out] objects - list of error's association objects
249      */
250     void processMetadata(const std::string& errorName,
251                          const std::vector<std::string>& additionalData,
252                          AssociationList& objects) const;
253 
254     /** @brief Reads the BMC code level
255      *
256      *  @return std::string - the version string
257      */
258     static std::string readFWVersion();
259 
260     /** @brief Call any create() functions provided by any extensions.
261      *  This is called right after an event log is created to allow
262      *  extensions to create their own log based on this one.
263      *
264      *  @param[in] entry - the new event log entry
265      *  @param[in] ffdc - A vector of FFDC file info
266      */
267     void doExtensionLogCreate(const Entry& entry, const FFDCEntries& ffdc);
268 
269     /** @brief Common wrapper for creating an Entry object
270      *
271      * @param[in] errMsg - The error exception message associated with the
272      *                     error log to be committed.
273      * @param[in] errLvl - level of the error
274      * @param[in] additionalData - The AdditionalData property for the error
275      * @param[in] ffdc - A vector of FFDC file info. Defaults to an empty
276      * vector.
277      */
278     void createEntry(std::string errMsg, Entry::Level errLvl,
279                      std::vector<std::string> additionalData,
280                      const FFDCEntries& ffdc = FFDCEntries{});
281 
282     /** @brief Notified on entry property changes
283      *
284      * If an entry is blocking, this callback will be registered to monitor for
285      * the entry having it's Resolved field set to true. If it is then remove
286      * the blocking object.
287      *
288      * @param[in] msg - sdbusplus dbusmessage
289      */
290     void onEntryResolve(sdbusplus::message_t& msg);
291 
292     /** @brief Remove block objects for any resolved entries  */
293     void findAndRemoveResolvedBlocks();
294 
295     /** @brief Quiesce host if it is running
296      *
297      * This is called when the user has requested the system be quiesced
298      * if a log with a callout is created
299      */
300     void checkAndQuiesceHost();
301 
302     /** @brief Persistent sdbusplus DBus bus connection. */
303     sdbusplus::bus_t& busLog;
304 
305     /** @brief List of error ids for high severity errors */
306     std::list<uint32_t> realErrors;
307 
308     /** @brief List of error ids for Info(and below) severity */
309     std::list<uint32_t> infoErrors;
310 
311     /** @brief Id of last error log entry */
312     uint32_t entryId;
313 
314     /** @brief The BMC firmware version */
315     const std::string fwVersion;
316 
317     /** @brief Array of blocking errors */
318     std::vector<std::unique_ptr<Block>> blockingErrors;
319 
320     /** @brief Map of entry id to call back object on properties changed */
321     std::map<uint32_t, std::unique_ptr<sdbusplus::bus::match_t>>
322         propChangedEntryCallback;
323 };
324 
325 } // namespace internal
326 
327 /** @class Manager
328  *  @brief Implementation for deleting all error log entries and
329  *         creating new logs.
330  *  @details A concrete implementation for the
331  *           xyz.openbmc_project.Collection.DeleteAll and
332  *           xyz.openbmc_project.Logging.Create interfaces.
333  */
334 class Manager : public details::ServerObject<DeleteAllIface, CreateIface>
335 {
336   public:
337     Manager() = delete;
338     Manager(const Manager&) = delete;
339     Manager& operator=(const Manager&) = delete;
340     Manager(Manager&&) = delete;
341     Manager& operator=(Manager&&) = delete;
342     virtual ~Manager() = default;
343 
344     /** @brief Constructor to put object onto bus at a dbus path.
345      *         Defer signal registration (pass true for deferSignal to the
346      *         base class) until after the properties are set.
347      *  @param[in] bus - Bus to attach to.
348      *  @param[in] path - Path to attach at.
349      *  @param[in] manager - Reference to internal manager object.
350      */
351     Manager(sdbusplus::bus_t& bus, const std::string& path,
352             internal::Manager& manager) :
353         details::ServerObject<DeleteAllIface, CreateIface>(
354             bus, path.c_str(),
355             details::ServerObject<DeleteAllIface,
356                                   CreateIface>::action::defer_emit),
357         manager(manager){};
358 
359     /** @brief Delete all d-bus objects.
360      */
361     void deleteAll() override
362     {
363         log<level::INFO>("Deleting all log entries");
364         auto numbersOfLogs = manager.eraseAll();
365         std::map<std::string, std::string> additionalData;
366         additionalData.emplace("NUM_LOGS", std::to_string(numbersOfLogs));
367         manager.create(LogsCleared::errName, Severity::Informational,
368                        additionalData);
369     }
370 
371     /** @brief D-Bus method call implementation to create an event log.
372      *
373      * @param[in] errMsg - The error exception message associated with the
374      *                     error log to be committed.
375      * @param[in] severity - Level of the error
376      * @param[in] additionalData - The AdditionalData property for the error
377      */
378     void create(std::string message, Severity severity,
379                 std::map<std::string, std::string> additionalData) override
380     {
381         manager.create(message, severity, additionalData);
382     }
383 
384     /** @brief D-Bus method call implementation to create an event log with FFDC
385      *
386      * The same as create(), but takes an extra FFDC argument.
387      *
388      * @param[in] errMsg - The error exception message associated with the
389      *                     error log to be committed.
390      * @param[in] severity - Level of the error
391      * @param[in] additionalData - The AdditionalData property for the error
392      * @param[in] ffdc - A vector of FFDC file info
393      */
394     void createWithFFDCFiles(
395         std::string message, Severity severity,
396         std::map<std::string, std::string> additionalData,
397         std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
398                                sdbusplus::message::unix_fd>>
399             ffdc) override
400     {
401         manager.create(message, severity, additionalData, ffdc);
402     }
403 
404   private:
405     /** @brief This is a reference to manager object */
406     internal::Manager& manager;
407 };
408 
409 } // namespace logging
410 } // namespace phosphor
411