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     void 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     void 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     sdbusplus::bus::bus& getBus()
154     {
155         return busLog;
156     }
157 
158     /** @brief Creates an event log
159      *
160      *  This is an alternative to the _commit() API.  It doesn't use
161      *  the journal to look up event log metadata like _commit does.
162      *
163      * @param[in] errMsg - The error exception message associated with the
164      *                     error log to be committed.
165      * @param[in] severity - level of the error
166      * @param[in] additionalData - The AdditionalData property for the error
167      */
168     void create(
169         const std::string& message,
170         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
171         const std::map<std::string, std::string>& additionalData);
172 
173     /** @brief Creates an event log, and accepts FFDC files
174      *
175      * This is the same as create(), but also takes an FFDC argument.
176      *
177      * The FFDC argument is a vector of tuples that allows one to pass in file
178      * descriptors for files that contain FFDC (First Failure Data Capture).
179      * These will be passed to any event logging extensions.
180      *
181      * @param[in] errMsg - The error exception message associated with the
182      *                     error log to be committed.
183      * @param[in] severity - level of the error
184      * @param[in] additionalData - The AdditionalData property for the error
185      * @param[in] ffdc - A vector of FFDC file info
186      */
187     void createWithFFDC(
188         const std::string& message,
189         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
190         const std::map<std::string, std::string>& additionalData,
191         const FFDCEntries& ffdc);
192 
193     /** @brief Common wrapper for creating an Entry object
194      *
195      * @return true if quiesce on error setting is enabled, false otherwise
196      */
197     bool isQuiesceOnErrorEnabled();
198 
199     /** @brief Check if error has callout and if so, block boot
200      *
201      * @param[in] entry - The error to check for callouts
202      */
203     void checkQuiesceOnError(const Entry& entry);
204 
205     /** @brief Check if inventory callout present in input entry
206      *
207      * @param[in] entry - The error to check for callouts
208      *
209      * @return true if inventory item in associations, false otherwise
210      */
211     bool isCalloutPresent(const Entry& entry);
212 
213     /** @brief Check (and remove) entry being erased from blocking errors
214      *
215      * @param[in] entryId - The entry that is being erased
216      */
217     void checkAndRemoveBlockingError(uint32_t entryId);
218 
219   private:
220     /*
221      * @fn _commit()
222      * @brief commit() helper
223      * @param[in] transactionId - Unique identifier of the journal entries
224      *                            to be committed.
225      * @param[in] errMsg - The error exception message associated with the
226      *                     error log to be committed.
227      * @param[in] errLvl - level of the error
228      */
229     void _commit(uint64_t transactionId, std::string&& errMsg,
230                  Entry::Level errLvl);
231 
232     /** @brief Call metadata handler(s), if any. Handlers may create
233      *         associations.
234      *  @param[in] errorName - name of the error
235      *  @param[in] additionalData - list of metadata (in key=value format)
236      *  @param[out] objects - list of error's association objects
237      */
238     void processMetadata(const std::string& errorName,
239                          const std::vector<std::string>& additionalData,
240                          AssociationList& objects) const;
241 
242     /** @brief Synchronize unwritten journal messages to disk.
243      *  @details This is the same implementation as the systemd command
244      *  "journalctl --sync".
245      */
246     void journalSync();
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     void createEntry(std::string errMsg, Entry::Level errLvl,
273                      std::vector<std::string> additionalData,
274                      const FFDCEntries& ffdc = FFDCEntries{});
275 
276     /** @brief Notified on entry property changes
277      *
278      * If an entry is blocking, this callback will be registered to monitor for
279      * the entry having it's Resolved field set to true. If it is then remove
280      * the blocking object.
281      *
282      * @param[in] msg - sdbusplus dbusmessage
283      */
284     void onEntryResolve(sdbusplus::message::message& msg);
285 
286     /** @brief Remove block objects for any resolved entries  */
287     void findAndRemoveResolvedBlocks();
288 
289     /** @brief Persistent sdbusplus DBus bus connection. */
290     sdbusplus::bus::bus& busLog;
291 
292     /** @brief Persistent map of Entry dbus objects and their ID */
293     std::map<uint32_t, std::unique_ptr<Entry>> entries;
294 
295     /** @brief List of error ids for high severity errors */
296     std::list<uint32_t> realErrors;
297 
298     /** @brief List of error ids for Info(and below) severity */
299     std::list<uint32_t> infoErrors;
300 
301     /** @brief Id of last error log entry */
302     uint32_t entryId;
303 
304     /** @brief The BMC firmware version */
305     const std::string fwVersion;
306 
307     /** @brief Array of blocking errors */
308     std::vector<std::unique_ptr<Block>> blockingErrors;
309 
310     /** @brief Map of entry id to call back object on properties changed */
311     std::map<uint32_t, std::unique_ptr<sdbusplus::bus::match::match>>
312         propChangedEntryCallback;
313 };
314 
315 } // namespace internal
316 
317 /** @class Manager
318  *  @brief Implementation for deleting all error log entries and
319  *         creating new logs.
320  *  @details A concrete implementation for the
321  *           xyz.openbmc_project.Collection.DeleteAll and
322  *           xyz.openbmc_project.Logging.Create interfaces.
323  */
324 class Manager : public details::ServerObject<DeleteAllIface, CreateIface>
325 {
326   public:
327     Manager() = delete;
328     Manager(const Manager&) = delete;
329     Manager& operator=(const Manager&) = delete;
330     Manager(Manager&&) = delete;
331     Manager& operator=(Manager&&) = delete;
332     virtual ~Manager() = default;
333 
334     /** @brief Constructor to put object onto bus at a dbus path.
335      *         Defer signal registration (pass true for deferSignal to the
336      *         base class) until after the properties are set.
337      *  @param[in] bus - Bus to attach to.
338      *  @param[in] path - Path to attach at.
339      *  @param[in] manager - Reference to internal manager object.
340      */
341     Manager(sdbusplus::bus::bus& bus, const std::string& path,
342             internal::Manager& manager) :
343         details::ServerObject<DeleteAllIface, CreateIface>(bus, path.c_str(),
344                                                            true),
345         manager(manager){};
346 
347     /** @brief Delete all d-bus objects.
348      */
349     void deleteAll()
350     {
351         manager.eraseAll();
352     }
353 
354     /** @brief D-Bus method call implementation to create an event log.
355      *
356      * @param[in] errMsg - The error exception message associated with the
357      *                     error log to be committed.
358      * @param[in] severity - Level of the error
359      * @param[in] additionalData - The AdditionalData property for the error
360      */
361     void create(
362         std::string message,
363         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
364         std::map<std::string, std::string> additionalData) override
365     {
366         manager.create(message, severity, additionalData);
367     }
368 
369     /** @brief D-Bus method call implementation to create an event log with FFDC
370      *
371      * The same as create(), but takes an extra FFDC argument.
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      * @param[in] ffdc - A vector of FFDC file info
378      */
379     void createWithFFDCFiles(
380         std::string message,
381         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
382         std::map<std::string, std::string> additionalData,
383         std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
384                                sdbusplus::message::unix_fd>>
385             ffdc) override
386     {
387         manager.createWithFFDC(message, severity, additionalData, ffdc);
388     }
389 
390   private:
391     /** @brief This is a reference to manager object */
392     internal::Manager& manager;
393 };
394 
395 } // namespace logging
396 } // namespace phosphor
397