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