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