1 #pragma once
2 
3 #include "config.h"
4 
5 #include "data_interface.hpp"
6 #include "event_logger.hpp"
7 #include "host_notifier.hpp"
8 #include "log_manager.hpp"
9 #include "paths.hpp"
10 #include "pel.hpp"
11 #include "registry.hpp"
12 #include "repository.hpp"
13 
14 #include <org/open_power/Logging/PEL/Entry/server.hpp>
15 #include <org/open_power/Logging/PEL/server.hpp>
16 #include <sdbusplus/server.hpp>
17 #include <sdeventplus/event.hpp>
18 #include <sdeventplus/source/event.hpp>
19 #include <xyz/openbmc_project/Logging/Create/server.hpp>
20 
21 namespace openpower
22 {
23 namespace pels
24 {
25 
26 using PELInterface = sdbusplus::server::object_t<
27     sdbusplus::org::open_power::Logging::server::PEL>;
28 
29 /**
30  * @brief PEL manager object
31  */
32 class Manager : public PELInterface
33 {
34   public:
35     Manager() = delete;
36     Manager(const Manager&) = default;
37     Manager& operator=(const Manager&) = default;
38     Manager(Manager&&) = default;
39     Manager& operator=(Manager&&) = default;
40 
41     /**
42      * @brief constructor
43      *
44      * @param[in] logManager - internal::Manager object
45      * @param[in] dataIface - The data interface object
46      * @param[in] creatorFunc - The function that EventLogger will
47      *                          use for creating event logs
48      */
49     Manager(phosphor::logging::internal::Manager& logManager,
50             std::unique_ptr<DataInterfaceBase> dataIface,
51             EventLogger::LogFunction creatorFunc) :
52         PELInterface(logManager.getBus(), OBJ_LOGGING),
53         _logManager(logManager), _eventLogger(std::move(creatorFunc)),
54         _repo(getPELRepoPath()),
55         _registry(getPELReadOnlyDataPath() / message::registryFileName),
56         _event(sdeventplus::Event::get_default()),
57         _dataIface(std::move(dataIface))
58     {
59         for (const auto& entry : _logManager.entries)
60         {
61             setEntryPath(entry.first);
62             setServiceProviderNotifyFlag(entry.first);
63             // Create PELEntry interface and setup properties with their values
64             createPELEntry(entry.first, true);
65         }
66 
67         _repo.for_each(
68             std::bind(&Manager::updateResolution, this, std::placeholders::_1));
69 
70         setupPELDeleteWatch();
71     }
72 
73     /**
74      * @brief constructor that enables host notification
75      *
76      * @param[in] logManager - internal::Manager object
77      * @param[in] dataIface - The data interface object
78      * @param[in] creatorFunc - The function that EventLogger will
79      *                          use for creating event logs
80      * @param[in] hostIface - The hostInterface object
81      */
82     Manager(phosphor::logging::internal::Manager& logManager,
83             std::unique_ptr<DataInterfaceBase> dataIface,
84             EventLogger::LogFunction creatorFunc,
85             std::unique_ptr<HostInterface> hostIface) :
86         Manager(logManager, std::move(dataIface), std::move(creatorFunc))
87     {
88         _hostNotifier = std::make_unique<HostNotifier>(
89             _repo, *(_dataIface.get()), std::move(hostIface));
90     }
91 
92     /**
93      * @brief Destructor
94      */
95     ~Manager();
96 
97     /**
98      * @brief Creates a PEL based on the OpenBMC event log contents.  If
99      *        a PEL was passed in via the RAWPEL specifier in the
100      *        additionalData parameter, use that instead.
101      *
102      * @param[in] message - the event log message property
103      * @param[in] obmcLogID - the corresponding OpenBMC event log id
104      * @param[in] timestamp - the Timestamp property
105      * @param[in] severity - the event log severity
106      * @param[in] additionalData - the AdditionalData property
107      * @param[in] associations - the Associations property
108      * @param[in] ffdc - A vector of FFDC file information
109      */
110     void create(const std::string& message, uint32_t obmcLogID,
111                 uint64_t timestamp, phosphor::logging::Entry::Level severity,
112                 const std::vector<std::string>& additionalData,
113                 const std::vector<std::string>& associations,
114                 const phosphor::logging::FFDCEntries& ffdc =
115                     phosphor::logging::FFDCEntries{});
116 
117     /**
118      * @brief Erase a PEL based on its OpenBMC event log ID
119      *
120      * @param[in] obmcLogID - the corresponding OpenBMC event log id
121      */
122     void erase(uint32_t obmcLogID);
123 
124     /** @brief Says if an OpenBMC event log may not be manually deleted at this
125      *         time because its corresponding PEL cannot be.
126      *
127      * There are PEL retention policies that can prohibit the manual deletion
128      * of PELs (and therefore OpenBMC event logs).
129      *
130      * @param[in] obmcLogID - the OpenBMC event log ID
131      * @return bool - true if prohibited
132      */
133     bool isDeleteProhibited(uint32_t obmcLogID);
134 
135     /**
136      * @brief Return a file descriptor to the raw PEL data
137      *
138      * Throws InvalidArgument if the PEL ID isn't found,
139      * and InternalFailure if anything else fails.
140      *
141      * @param[in] pelID - The PEL ID to get the data for
142      *
143      * @return unix_fd - File descriptor to the file that contains the PEL
144      */
145     sdbusplus::message::unix_fd getPEL(uint32_t pelID) override;
146 
147     /**
148      * @brief Returns data for the PEL corresponding to an OpenBMC
149      *        event log.
150      *
151      * @param[in] obmcLogID - The OpenBMC event log ID
152      *
153      * @return vector<uint8_t> - The raw PEL data
154      */
155     std::vector<uint8_t> getPELFromOBMCID(uint32_t obmcLogID) override;
156 
157     /**
158      * @brief The D-Bus method called when a host successfully processes
159      *        a PEL.
160      *
161      * This D-Bus method is called from the PLDM daemon when they get an
162      * 'Ack PEL' PLDM message from the host, which indicates the host
163      * firmware successfully sent it to the OS and this code doesn't need
164      * to send it to the host again.
165      *
166      * @param[in] pelID - The PEL ID
167      */
168     void hostAck(uint32_t pelID) override;
169 
170     /**
171      * @brief D-Bus method called when the host rejects a PEL.
172      *
173      * This D-Bus method is called from the PLDM daemon when they get an
174      * 'Ack PEL' PLDM message from the host with a payload that says
175      * something when wrong.
176      *
177      * The choices are either:
178      *  * Host Full - The host's staging area is full - try again later
179      *  * Malrformed PEL - The host received an invalid PEL
180      *
181      * @param[in] pelID - The PEL ID
182      * @param[in] reason - One of the above two reasons
183      */
184     void hostReject(uint32_t pelID, RejectionReason reason) override;
185 
186     /**
187      * @brief D-Bus method to create a PEL/OpenBMC event log and
188      *        return the created OpenBMC and PEL log IDs.
189      *
190      * The same as the CreateWithFFDCFiles method on the
191      * xyz.openbmc_project.Logging.Create interface, except for
192      * the return values.
193      *
194      * @param[in] message - The event log message property
195      * @param[in] severity - The event log severity
196      * @param[in] additionalData - The AdditionalData property
197      * @param[in] ffdc - A vector of FFDC file information
198      */
199     std::tuple<uint32_t, uint32_t> createPELWithFFDCFiles(
200         std::string message, phosphor::logging::Entry::Level severity,
201         std::map<std::string, std::string> additionalData,
202         std::vector<std::tuple<sdbusplus::xyz::openbmc_project::Logging::
203                                    server::Create::FFDCFormat,
204                                uint8_t, uint8_t, sdbusplus::message::unix_fd>>
205             fFDC) override;
206 
207     /**
208      * @brief D-Bus method to return the PEL in JSON format
209      *
210      * @param[in] obmcLogID - The OpenBMC entry log ID
211      *
212      * @return std::string - The fully parsed PEL in JSON
213      */
214     std::string getPELJSON(uint32_t obmcLogID) override;
215 
216     /**
217      * @brief Converts the ESEL field in an OpenBMC event log to a
218      *        vector of uint8_ts that just contains the PEL data.
219      *
220      * That data string looks like: "50 48 00 ab ..."
221      *
222      * Throws an exception on any failures.
223      *
224      * @param[in] esel - The ESEL string
225      *
226      * @return std::vector<uint8_t> - The contained PEL data
227      */
228     static std::vector<uint8_t> eselToRawData(const std::string& esel);
229 
230     /**
231      * @brief Generate resolution string from the PEL
232      *
233      * @param[in] pel - The PEL to use
234      */
235     std::string getResolution(const openpower::pels::PEL& pel) const;
236 
237     /**
238      * @brief Generate event ID from the PEL
239      *
240      * @param[in] pel - The PEL to use
241      */
242     std::string getEventId(const openpower::pels::PEL& pel) const;
243 
244     /** @brief Implementation for GetPELIdFromBMCLogId
245      *
246      *  Returns the PEL Id (aka Entry ID (EID)) based on the given
247      *  BMC event log id.
248      *
249      *  @param[in] bmcLogId - The BMC event log id of the PEL to retrieve
250      *                        the PEL id.
251      *
252      *  @return uint32_t - The Id of the PEL.
253      *                     Throw "InvalidArgument" if not found.
254      */
255     uint32_t getPELIdFromBMCLogId(uint32_t bmcLogId) override;
256 
257     /** @brief Implementation for GetBMCLogIdFromPELId
258      *
259      *  Returns the BMC event log id based on the given PEL id
260      *  (aka Entry ID (EID)).
261      *
262      *  @param[in] pelId - The PEL id to retrieve the BMC event log id.
263      *
264      *  @return uint32_t - The BMC event log id of the PEL.
265      *                     Throw "InvalidArgument" if not found.
266      */
267     uint32_t getBMCLogIdFromPELId(uint32_t pelId) override;
268 
269     /**
270      * @brief Update boot progress SRC based on severity 0x51, critical error
271      *
272      * @param[in] pel - The PEL to use
273      */
274     void updateProgressSRC(std::unique_ptr<openpower::pels::PEL>& pel) const;
275 
276     /**
277      * @brief Converts unprintable characters from the passed
278      *        in string to spaces so they won't crash D-Bus when
279      *        used as a property value.
280      *
281      * @param[in] field - The field to fix
282      *
283      * @return std::string - The string without non printable characters.
284      */
285     static std::string sanitizeFieldForDBus(std::string field);
286 
287   private:
288     /**
289      * @brief Adds a received raw PEL to the PEL repository
290      *
291      * @param[in] rawPelPath - The path to the file that contains the
292      *                         raw PEL.
293      * @param[in] obmcLogID - the corresponding OpenBMC event log id
294      */
295     void addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID);
296 
297     /**
298      * @brief Creates a PEL based on the OpenBMC event log contents.
299      *
300      * @param[in] message - The event log message property
301      * @param[in] obmcLogID - the corresponding OpenBMC event log id
302      * @param[in] timestamp - The timestamp property
303      * @param[in] severity - The event log severity
304      * @param[in] additionalData - The AdditionalData property
305      * @param[in] associations - The associations property
306      * @param[in] ffdc - A vector of FFDC file information
307      */
308     void createPEL(const std::string& message, uint32_t obmcLogID,
309                    uint64_t timestamp, phosphor::logging::Entry::Level severity,
310                    const std::vector<std::string>& additionalData,
311                    const std::vector<std::string>& associations,
312                    const phosphor::logging::FFDCEntries& ffdc);
313 
314     /**
315      * @brief Schedules a close of the file descriptor to occur from
316      *        the event loop.
317      *
318      * Uses sd_event_add_defer
319      *
320      * @param[in] fd - The file descriptor to close
321      */
322     void scheduleFDClose(int fd);
323 
324     /**
325      * @brief Closes the file descriptor passed in.
326      *
327      * This is called from the event loop to close FDs returned
328      * from getPEL().
329      *
330      * @param[in] fd - The file descriptor to close
331      * @param[in] source - The event source object used
332      */
333     void closeFD(int fd, sdeventplus::source::EventBase& source);
334 
335     /**
336      * @brief Adds a PEL to the repository given its data
337      *
338      * @param[in] pelData - The PEL to add as a vector of uint8_ts
339      * @param[in] obmcLogID - the OpenBMC event log ID
340      */
341     void addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID);
342 
343     /**
344      * @brief Adds the PEL stored in the ESEL field of the AdditionalData
345      *        property of an OpenBMC event log to the repository.
346      *
347      * @param[in] esel - The ESEL AdditionalData contents
348      * @param[in] obmcLogID - The OpenBMC event log ID
349      */
350     void addESELPEL(const std::string& esel, uint32_t obmcLogID);
351 
352     /**
353      * @brief Converts the D-Bus FFDC method argument into a data
354      *        structure understood by the PEL code.
355      *
356      * @param[in] ffdc - A vector of FFDC file information
357      *
358      * @return PelFFDC - The PEL FFDC data structure
359      */
360     PelFFDC convertToPelFFDC(const phosphor::logging::FFDCEntries& ffdc);
361 
362     /**
363      * @brief Schedules a PEL repository prune to occur from
364      *        the event loop.
365      *
366      * Uses sd_event_add_defer
367      */
368     void scheduleRepoPrune();
369 
370     /**
371      * @brief Prunes old PELs out of the repository to save space.
372      *
373      * This is called from the event loop.
374      *
375      * @param[in] source - The event source object used
376      */
377     void pruneRepo(sdeventplus::source::EventBase& source);
378 
379     /**
380      * @brief Sets up an inotify watch to watch for deleted PEL
381      *        files.  Calls pelFileDeleted() when that occurs.
382      */
383     void setupPELDeleteWatch();
384 
385     /**
386      * @brief Called when the inotify watch put on the repository directory
387      *        detects a PEL file was deleted.
388      *
389      * Will tell the Repository class about the deleted PEL, and then tell
390      * the log manager class to delete the corresponding OpenBMC event log.
391      */
392     void pelFileDeleted(sdeventplus::source::IO& io, int fd, uint32_t revents);
393 
394     /**
395      * @brief Check if the input PEL should cause a quiesce of the system
396      *
397      * If QuiesceOnHwError is enabled within phosphor-settings and the PEL
398      * from the host has a severity which is not SeverityType::nonError or
399      * recovered then execute the quiesce and boot block logic.
400      *
401      * @param[in] pel - The PEL to check
402      */
403     void checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel);
404 
405     /**
406      * @brief Update eventId D-bus property for this error log
407      *
408      * Update the eventId property of D-bus with SRC and hexwords from the
409      * PEL created
410      *
411      * @param[in] pel - The PEL to use
412      */
413     void updateEventId(std::unique_ptr<openpower::pels::PEL>& pel);
414 
415     /**
416      * @brief Sets the FilePath of the specified error log entry to the PEL file
417      *        path.
418      *
419      * @param[in] obmcLogID - The OpenBMC entry log ID
420      */
421     void setEntryPath(uint32_t obmcLogID);
422 
423     /**
424      * @brief Sets the serviceProviderNotify D-bus property of PEL.
425      *
426      * @param[in] obmcLogID - The OpenBMC entry log ID
427      */
428     void setServiceProviderNotifyFlag(uint32_t obmcLogID);
429 
430     /**
431      * @brief Update resolution D-bus property for this error log
432      *
433      * Update the resolution property of D-bus with callouts extracted from PEL
434      *
435      * @param[in] pel - The PEL to use
436      *
437      * @return bool - false for Repositor::for_each().
438      */
439     bool updateResolution(const openpower::pels::PEL& pel);
440 
441     /**
442      * @brief Check if the D-Bus severity property for the event log
443      *        needs to be updated based on the final PEL severity,
444      *        and update the property accordingly.
445      *
446      * @param[in] pel - The PEL to operate on.
447      */
448     void updateDBusSeverity(const openpower::pels::PEL& pel);
449 
450     /**
451      * @brief Create PELEntry Interface with supported properties
452      *
453      * Create PELEntry Interface and update all the properties which are
454      * supported
455      *
456      * @param[in] obmcLogID - The OpenBMC entry log ID
457      * @param[in] skipIaSignal - If The InterfacesAdded signal should be
458      *                           skipped after creating the interfaces.
459      */
460     void createPELEntry(uint32_t obmcLogID, bool skipIaSignal = false);
461 
462     /**
463      * @brief Schedules the delete of the OpenBMC event log for when
464      *        execution gets back to the event loop (uses sd_event_add_defer).
465      *
466      * @param[in] obmcLogID - The OpenBMC entry log ID
467      */
468     void scheduleObmcLogDelete(uint32_t obmcLogID);
469 
470     /**
471      * @brief SD event callback to delete an OpenBMC event log
472      *
473      * @param[in] obmcLogID - The OpenBMC entry log ID
474      */
475     void deleteObmcLog(sdeventplus::source::EventBase&, uint32_t obmcLogID);
476 
477     /**
478      * @brief Reference to phosphor-logging's Manager class
479      */
480     phosphor::logging::internal::Manager& _logManager;
481 
482     /**
483      * @brief Handles creating event logs/PELs from within
484      *        the PEL extension code
485      */
486     EventLogger _eventLogger;
487 
488     /**
489      * @brief The PEL repository object
490      */
491     Repository _repo;
492 
493     /**
494      * @brief The PEL message registry object
495      */
496     message::Registry _registry;
497 
498     /**
499      * @brief The Event object this class uses
500      */
501     sdeventplus::Event _event;
502 
503     /**
504      * @brief The API the PEL sections use to gather data
505      */
506     std::unique_ptr<DataInterfaceBase> _dataIface;
507 
508     /**
509      * @brief The map used to keep track of PEL entry pointer associated with
510      *        event log.
511      */
512     std::map<std::string,
513              std::unique_ptr<
514                  sdbusplus::org::open_power::Logging::PEL::server::Entry>>
515         _pelEntries;
516 
517     /**
518      * @brief The HostNotifier object used for telling the
519      *        host about new PELs
520      */
521     std::unique_ptr<HostNotifier> _hostNotifier;
522 
523     /**
524      * @brief The event source for closing a PEL file descriptor after
525      *        it has been returned from the getPEL D-Bus method.
526      */
527     std::unique_ptr<sdeventplus::source::Defer> _fdCloserEventSource;
528 
529     /**
530      * @brief The even source for removing old PELs when the repo is
531      *        running out of space to make room for new ones.
532      */
533     std::unique_ptr<sdeventplus::source::Defer> _repoPrunerEventSource;
534 
535     /**
536      * @brief The event source for deleting an OpenBMC event log.
537      *        Used when its corresponding PEL is invalid.
538      */
539     std::unique_ptr<sdeventplus::source::Defer> _obmcLogDeleteEventSource;
540 
541     /**
542      * @brief The even source for watching for deleted PEL files.
543      */
544     std::unique_ptr<sdeventplus::source::IO> _pelFileDeleteEventSource;
545 
546     /**
547      * @brief The file descriptor returned by inotify_init1() used
548      *        for watching for deleted PEL files.
549      */
550     int _pelFileDeleteFD = -1;
551 
552     /**
553      * @brief The file descriptor returned by inotify_add_watch().
554      */
555     int _pelFileDeleteWatchFD = -1;
556 };
557 
558 } // namespace pels
559 } // namespace openpower
560