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 <phosphor-logging/log.hpp>
11 #include <sdbusplus/bus.hpp>
12 
13 #include <list>
14 
15 namespace phosphor
16 {
17 namespace logging
18 {
19 
20 extern const std::map<std::string, std::vector<std::string>> g_errMetaMap;
21 extern const std::map<std::string, level> g_errLevelMap;
22 
23 using CreateIface = sdbusplus::xyz::openbmc_project::Logging::server::Create;
24 using DeleteAllIface =
25     sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll;
26 
27 namespace details
28 {
29 template <typename... T>
30 using ServerObject = typename sdbusplus::server::object_t<T...>;
31 
32 using ManagerIface =
33     sdbusplus::xyz::openbmc_project::Logging::Internal::server::Manager;
34 
35 } // namespace details
36 
37 constexpr size_t ffdcFormatPos = 0;
38 constexpr size_t ffdcSubtypePos = 1;
39 constexpr size_t ffdcVersionPos = 2;
40 constexpr size_t ffdcFDPos = 3;
41 
42 using FFDCEntry = std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
43                              sdbusplus::message::unix_fd>;
44 
45 using FFDCEntries = std::vector<FFDCEntry>;
46 
47 namespace internal
48 {
49 
50 /** @class Manager
51  *  @brief OpenBMC logging manager implementation.
52  *  @details A concrete implementation for the
53  *  xyz.openbmc_project.Logging.Internal.Manager DBus API.
54  */
55 class Manager : public details::ServerObject<details::ManagerIface>
56 {
57   public:
58     Manager() = delete;
59     Manager(const Manager&) = delete;
60     Manager& operator=(const Manager&) = delete;
61     Manager(Manager&&) = delete;
62     Manager& operator=(Manager&&) = delete;
63     virtual ~Manager() = default;
64 
65     /** @brief Constructor to put object onto bus at a dbus path.
66      *  @param[in] bus - Bus to attach to.
67      *  @param[in] path - Path to attach at.
68      */
69     Manager(sdbusplus::bus_t& bus, const char* objPath) :
70         details::ServerObject<details::ManagerIface>(bus, objPath), busLog(bus),
71         entryId(0), fwVersion(readFWVersion()){};
72 
73     /*
74      * @fn commit()
75      * @brief sd_bus Commit method implementation callback.
76      * @details Create an error/event log based on transaction id and
77      *          error message.
78      * @param[in] transactionId - Unique identifier of the journal entries
79      *                            to be committed.
80      * @param[in] errMsg - The error exception message associated with the
81      *                     error log to be committed.
82      */
83     uint32_t commit(uint64_t transactionId, std::string errMsg) override;
84 
85     /*
86      * @fn commit()
87      * @brief sd_bus CommitWithLvl method implementation callback.
88      * @details Create an error/event log based on transaction id and
89      *          error message.
90      * @param[in] transactionId - Unique identifier of the journal entries
91      *                            to be committed.
92      * @param[in] errMsg - The error exception message associated with the
93      *                     error log to be committed.
94      * @param[in] errLvl - level of the error
95      */
96     uint32_t commitWithLvl(uint64_t transactionId, std::string errMsg,
97                            uint32_t errLvl) override;
98 
99     /** @brief Erase specified entry d-bus object
100      *
101      * @param[in] entryId - unique identifier of the entry
102      */
103     void erase(uint32_t entryId);
104 
105     /** @brief Construct error d-bus objects from their persisted
106      *         representations.
107      */
108     void restore();
109 
110     /** @brief  Erase all error log entries
111      *
112      */
113     void eraseAll()
114     {
115         auto iter = entries.begin();
116         while (iter != entries.end())
117         {
118             auto e = iter->first;
119             ++iter;
120             erase(e);
121         }
122         entryId = 0;
123     }
124 
125     /** @brief Returns the count of high severity errors
126      *
127      *  @return int - count of real errors
128      */
129     int getRealErrSize();
130 
131     /** @brief Returns the count of Info errors
132      *
133      *  @return int - count of info errors
134      */
135     int getInfoErrSize();
136 
137     /** @brief Returns the number of blocking errors
138      *
139      *  @return int - count of blocking errors
140      */
141     int getBlockingErrSize()
142     {
143         return blockingErrors.size();
144     }
145 
146     /** @brief Returns the number of property change callback objects
147      *
148      *  @return int - count of property callback entries
149      */
150     int getEntryCallbackSize()
151     {
152         return propChangedEntryCallback.size();
153     }
154 
155     /**
156      * @brief Returns the sdbusplus bus object
157      *
158      * @return sdbusplus::bus_t&
159      */
160     sdbusplus::bus_t& getBus()
161     {
162         return busLog;
163     }
164 
165     /**
166      * @brief Returns the ID of the last created entry
167      *
168      * @return uint32_t - The ID
169      */
170     uint32_t lastEntryID() const
171     {
172         return entryId;
173     }
174 
175     /** @brief Creates an event log
176      *
177      *  This is an alternative to the _commit() API.  It doesn't use
178      *  the journal to look up event log metadata like _commit does.
179      *
180      * @param[in] errMsg - The error exception message associated with the
181      *                     error log to be committed.
182      * @param[in] severity - level of the error
183      * @param[in] additionalData - The AdditionalData property for the error
184      */
185     void create(
186         const std::string& message,
187         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
188         const std::map<std::string, std::string>& additionalData);
189 
190     /** @brief Creates an event log, and accepts FFDC files
191      *
192      * This is the same as create(), but also takes an FFDC argument.
193      *
194      * The FFDC argument is a vector of tuples that allows one to pass in file
195      * descriptors for files that contain FFDC (First Failure Data Capture).
196      * These will be passed to any event logging extensions.
197      *
198      * @param[in] errMsg - The error exception message associated with the
199      *                     error log to be committed.
200      * @param[in] severity - level of the error
201      * @param[in] additionalData - The AdditionalData property for the error
202      * @param[in] ffdc - A vector of FFDC file info
203      */
204     void createWithFFDC(
205         const std::string& message,
206         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
207         const std::map<std::string, std::string>& additionalData,
208         const FFDCEntries& ffdc);
209 
210     /** @brief Common wrapper for creating an Entry object
211      *
212      * @return true if quiesce on error setting is enabled, false otherwise
213      */
214     bool isQuiesceOnErrorEnabled();
215 
216     /** @brief Create boot block association and quiesce host if running
217      *
218      * @param[in] entryId - The ID of the phosphor logging error
219      */
220     void quiesceOnError(const uint32_t entryId);
221 
222     /** @brief Check if inventory callout present in input entry
223      *
224      * @param[in] entry - The error to check for callouts
225      *
226      * @return true if inventory item in associations, false otherwise
227      */
228     bool isCalloutPresent(const Entry& entry);
229 
230     /** @brief Check (and remove) entry being erased from blocking errors
231      *
232      * @param[in] entryId - The entry that is being erased
233      */
234     void checkAndRemoveBlockingError(uint32_t entryId);
235 
236     /** @brief Persistent map of Entry dbus objects and their ID */
237     std::map<uint32_t, std::unique_ptr<Entry>> entries;
238 
239   private:
240     /*
241      * @fn _commit()
242      * @brief commit() helper
243      * @param[in] transactionId - Unique identifier of the journal entries
244      *                            to be committed.
245      * @param[in] errMsg - The error exception message associated with the
246      *                     error log to be committed.
247      * @param[in] errLvl - level of the error
248      */
249     void _commit(uint64_t transactionId, std::string&& errMsg,
250                  Entry::Level errLvl);
251 
252     /** @brief Call metadata handler(s), if any. Handlers may create
253      *         associations.
254      *  @param[in] errorName - name of the error
255      *  @param[in] additionalData - list of metadata (in key=value format)
256      *  @param[out] objects - list of error's association objects
257      */
258     void processMetadata(const std::string& errorName,
259                          const std::vector<std::string>& additionalData,
260                          AssociationList& objects) const;
261 
262     /** @brief Synchronize unwritten journal messages to disk.
263      *  @details This is the same implementation as the systemd command
264      *  "journalctl --sync".
265      */
266     void journalSync();
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         manager.eraseAll();
379     }
380 
381     /** @brief D-Bus method call implementation to create an event log.
382      *
383      * @param[in] errMsg - The error exception message associated with the
384      *                     error log to be committed.
385      * @param[in] severity - Level of the error
386      * @param[in] additionalData - The AdditionalData property for the error
387      */
388     void create(
389         std::string message,
390         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
391         std::map<std::string, std::string> additionalData) override
392     {
393         manager.create(message, severity, additionalData);
394     }
395 
396     /** @brief D-Bus method call implementation to create an event log with FFDC
397      *
398      * The same as create(), but takes an extra FFDC argument.
399      *
400      * @param[in] errMsg - The error exception message associated with the
401      *                     error log to be committed.
402      * @param[in] severity - Level of the error
403      * @param[in] additionalData - The AdditionalData property for the error
404      * @param[in] ffdc - A vector of FFDC file info
405      */
406     void createWithFFDCFiles(
407         std::string message,
408         sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
409         std::map<std::string, std::string> additionalData,
410         std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
411                                sdbusplus::message::unix_fd>>
412             ffdc) override
413     {
414         manager.createWithFFDC(message, severity, additionalData, ffdc);
415     }
416 
417   private:
418     /** @brief This is a reference to manager object */
419     internal::Manager& manager;
420 };
421 
422 } // namespace logging
423 } // namespace phosphor
424