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_t<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_t& 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     uint32_t 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     uint32_t 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         entryId = 0;
122     }
123 
124     /** @brief Returns the count of high severity errors
125      *
126      *  @return int - count of real errors
127      */
128     int getRealErrSize();
129 
130     /** @brief Returns the count of Info errors
131      *
132      *  @return int - count of info errors
133      */
134     int getInfoErrSize();
135 
136     /** @brief Returns the number of blocking errors
137      *
138      *  @return int - count of blocking errors
139      */
140     int getBlockingErrSize()
141     {
142         return blockingErrors.size();
143     }
144 
145     /** @brief Returns the number of property change callback objects
146      *
147      *  @return int - count of property callback entries
148      */
149     int getEntryCallbackSize()
150     {
151         return propChangedEntryCallback.size();
152     }
153 
154     /**
155      * @brief Returns the sdbusplus bus object
156      *
157      * @return sdbusplus::bus_t&
158      */
159     sdbusplus::bus_t& getBus()
160     {
161         return busLog;
162     }
163 
164     /**
165      * @brief Returns the ID of the last created entry
166      *
167      * @return uint32_t - The ID
168      */
169     uint32_t lastEntryID() const
170     {
171         return entryId;
172     }
173 
174     /** @brief Creates an event log
175      *
176      *  This is an alternative to the _commit() API.  It doesn't use
177      *  the journal to look up event log metadata like _commit does.
178      *
179      * @param[in] errMsg - The error exception message associated with the
180      *                     error log to be committed.
181      * @param[in] severity - level of the error
182      * @param[in] additionalData - The AdditionalData property for the error
183      */
184     void create(
185         const std::string& message,
186         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
187         const std::map<std::string, std::string>& additionalData);
188 
189     /** @brief Creates an event log, and accepts FFDC files
190      *
191      * This is the same as create(), but also takes an FFDC argument.
192      *
193      * The FFDC argument is a vector of tuples that allows one to pass in file
194      * descriptors for files that contain FFDC (First Failure Data Capture).
195      * These will be passed to any event logging extensions.
196      *
197      * @param[in] errMsg - The error exception message associated with the
198      *                     error log to be committed.
199      * @param[in] severity - level of the error
200      * @param[in] additionalData - The AdditionalData property for the error
201      * @param[in] ffdc - A vector of FFDC file info
202      */
203     void createWithFFDC(
204         const std::string& message,
205         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
206         const std::map<std::string, std::string>& additionalData,
207         const FFDCEntries& ffdc);
208 
209     /** @brief Common wrapper for creating an Entry object
210      *
211      * @return true if quiesce on error setting is enabled, false otherwise
212      */
213     bool isQuiesceOnErrorEnabled();
214 
215     /** @brief Create boot block association and quiesce host if running
216      *
217      * @param[in] entryId - The ID of the phosphor logging error
218      */
219     void quiesceOnError(const uint32_t entryId);
220 
221     /** @brief Check if inventory callout present in input entry
222      *
223      * @param[in] entry - The error to check for callouts
224      *
225      * @return true if inventory item in associations, false otherwise
226      */
227     bool isCalloutPresent(const Entry& entry);
228 
229     /** @brief Check (and remove) entry being erased from blocking errors
230      *
231      * @param[in] entryId - The entry that is being erased
232      */
233     void checkAndRemoveBlockingError(uint32_t entryId);
234 
235     /** @brief Persistent map of Entry dbus objects and their ID */
236     std::map<uint32_t, std::unique_ptr<Entry>> entries;
237 
238   private:
239     /*
240      * @fn _commit()
241      * @brief commit() helper
242      * @param[in] transactionId - Unique identifier of the journal entries
243      *                            to be committed.
244      * @param[in] errMsg - The error exception message associated with the
245      *                     error log to be committed.
246      * @param[in] errLvl - level of the error
247      */
248     void _commit(uint64_t transactionId, std::string&& errMsg,
249                  Entry::Level errLvl);
250 
251     /** @brief Call metadata handler(s), if any. Handlers may create
252      *         associations.
253      *  @param[in] errorName - name of the error
254      *  @param[in] additionalData - list of metadata (in key=value format)
255      *  @param[out] objects - list of error's association objects
256      */
257     void processMetadata(const std::string& errorName,
258                          const std::vector<std::string>& additionalData,
259                          AssociationList& objects) const;
260 
261     /** @brief Synchronize unwritten journal messages to disk.
262      *  @details This is the same implementation as the systemd command
263      *  "journalctl --sync".
264      */
265     void journalSync();
266 
267     /** @brief Reads the BMC code level
268      *
269      *  @return std::string - the version string
270      */
271     static std::string readFWVersion();
272 
273     /** @brief Call any create() functions provided by any extensions.
274      *  This is called right after an event log is created to allow
275      *  extensions to create their own log based on this one.
276      *
277      *  @param[in] entry - the new event log entry
278      *  @param[in] ffdc - A vector of FFDC file info
279      */
280     void doExtensionLogCreate(const Entry& entry, const FFDCEntries& ffdc);
281 
282     /** @brief Common wrapper for creating an Entry object
283      *
284      * @param[in] errMsg - The error exception message associated with the
285      *                     error log to be committed.
286      * @param[in] errLvl - level of the error
287      * @param[in] additionalData - The AdditionalData property for the error
288      * @param[in] ffdc - A vector of FFDC file info. Defaults to an empty
289      * vector.
290      */
291     void createEntry(std::string errMsg, Entry::Level errLvl,
292                      std::vector<std::string> additionalData,
293                      const FFDCEntries& ffdc = FFDCEntries{});
294 
295     /** @brief Notified on entry property changes
296      *
297      * If an entry is blocking, this callback will be registered to monitor for
298      * the entry having it's Resolved field set to true. If it is then remove
299      * the blocking object.
300      *
301      * @param[in] msg - sdbusplus dbusmessage
302      */
303     void onEntryResolve(sdbusplus::message_t& msg);
304 
305     /** @brief Remove block objects for any resolved entries  */
306     void findAndRemoveResolvedBlocks();
307 
308     /** @brief Quiesce host if it is running
309      *
310      * This is called when the user has requested the system be quiesced
311      * if a log with a callout is created
312      */
313     void checkAndQuiesceHost();
314 
315     /** @brief Persistent sdbusplus DBus bus connection. */
316     sdbusplus::bus_t& busLog;
317 
318     /** @brief List of error ids for high severity errors */
319     std::list<uint32_t> realErrors;
320 
321     /** @brief List of error ids for Info(and below) severity */
322     std::list<uint32_t> infoErrors;
323 
324     /** @brief Id of last error log entry */
325     uint32_t entryId;
326 
327     /** @brief The BMC firmware version */
328     const std::string fwVersion;
329 
330     /** @brief Array of blocking errors */
331     std::vector<std::unique_ptr<Block>> blockingErrors;
332 
333     /** @brief Map of entry id to call back object on properties changed */
334     std::map<uint32_t, std::unique_ptr<sdbusplus::bus::match_t>>
335         propChangedEntryCallback;
336 };
337 
338 } // namespace internal
339 
340 /** @class Manager
341  *  @brief Implementation for deleting all error log entries and
342  *         creating new logs.
343  *  @details A concrete implementation for the
344  *           xyz.openbmc_project.Collection.DeleteAll and
345  *           xyz.openbmc_project.Logging.Create interfaces.
346  */
347 class Manager : public details::ServerObject<DeleteAllIface, CreateIface>
348 {
349   public:
350     Manager() = delete;
351     Manager(const Manager&) = delete;
352     Manager& operator=(const Manager&) = delete;
353     Manager(Manager&&) = delete;
354     Manager& operator=(Manager&&) = delete;
355     virtual ~Manager() = default;
356 
357     /** @brief Constructor to put object onto bus at a dbus path.
358      *         Defer signal registration (pass true for deferSignal to the
359      *         base class) until after the properties are set.
360      *  @param[in] bus - Bus to attach to.
361      *  @param[in] path - Path to attach at.
362      *  @param[in] manager - Reference to internal manager object.
363      */
364     Manager(sdbusplus::bus_t& bus, const std::string& path,
365             internal::Manager& manager) :
366         details::ServerObject<DeleteAllIface, CreateIface>(
367             bus, path.c_str(),
368             details::ServerObject<DeleteAllIface,
369                                   CreateIface>::action::defer_emit),
370         manager(manager){};
371 
372     /** @brief Delete all d-bus objects.
373      */
374     void deleteAll() override
375     {
376         log<level::INFO>("Deleting all log entries");
377         manager.eraseAll();
378     }
379 
380     /** @brief D-Bus method call implementation to create an event log.
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      */
387     void create(
388         std::string message,
389         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
390         std::map<std::string, std::string> additionalData) override
391     {
392         manager.create(message, severity, additionalData);
393     }
394 
395     /** @brief D-Bus method call implementation to create an event log with FFDC
396      *
397      * The same as create(), but takes an extra FFDC argument.
398      *
399      * @param[in] errMsg - The error exception message associated with the
400      *                     error log to be committed.
401      * @param[in] severity - Level of the error
402      * @param[in] additionalData - The AdditionalData property for the error
403      * @param[in] ffdc - A vector of FFDC file info
404      */
405     void createWithFFDCFiles(
406         std::string message,
407         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
408         std::map<std::string, std::string> additionalData,
409         std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
410                                sdbusplus::message::unix_fd>>
411             ffdc) override
412     {
413         manager.createWithFFDC(message, severity, additionalData, ffdc);
414     }
415 
416   private:
417     /** @brief This is a reference to manager object */
418     internal::Manager& manager;
419 };
420 
421 } // namespace logging
422 } // namespace phosphor
423