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