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