1 #pragma once
2 
3 #include "dbus_types.hpp"
4 #include "dbus_watcher.hpp"
5 
6 #include <filesystem>
7 #include <phosphor-logging/log.hpp>
8 #include <sdbusplus/bus.hpp>
9 #include <sdbusplus/bus/match.hpp>
10 
11 namespace openpower
12 {
13 namespace pels
14 {
15 
16 /**
17  * @class DataInterface
18  *
19  * A base class for gathering data about the system for use
20  * in PELs. Implemented this way to facilitate mocking.
21  */
22 class DataInterfaceBase
23 {
24   public:
25     DataInterfaceBase() = default;
26     virtual ~DataInterfaceBase() = default;
27     DataInterfaceBase(const DataInterfaceBase&) = default;
28     DataInterfaceBase& operator=(const DataInterfaceBase&) = default;
29     DataInterfaceBase(DataInterfaceBase&&) = default;
30     DataInterfaceBase& operator=(DataInterfaceBase&&) = default;
31 
32     /**
33      * @brief Returns the machine Type/Model
34      *
35      * @return string - The machine Type/Model string
36      */
37     virtual std::string getMachineTypeModel() const = 0;
38 
39     /**
40      * @brief Returns the machine serial number
41      *
42      * @return string - The machine serial number
43      */
44     virtual std::string getMachineSerialNumber() const = 0;
45 
46     /**
47      * @brief Says if the system is managed by a hardware
48      *        management console.
49      * @return bool - If the system is HMC managed
50      */
51     virtual bool isHMCManaged() const
52     {
53         return _hmcManaged;
54     }
55 
56     /**
57      * @brief Says if the host is up and running
58      *
59      * @return bool - If the host is running
60      */
61     virtual bool isHostUp() const
62     {
63         return _hostUp;
64     }
65 
66     using HostStateChangeFunc = std::function<void(bool)>;
67 
68     /**
69      * @brief Register a callback function that will get
70      *        called on all host on/off transitions.
71      *
72      * The void(bool) function will get passed the new
73      * value of the host state.
74      *
75      * @param[in] name - The subscription name
76      * @param[in] func - The function to run
77      */
78     void subscribeToHostStateChange(const std::string& name,
79                                     HostStateChangeFunc func)
80     {
81         _hostChangeCallbacks[name] = func;
82     }
83 
84     /**
85      * @brief Unsubscribe from host state changes.
86      *
87      * @param[in] name - The subscription name
88      */
89     void unsubscribeFromHostStateChange(const std::string& name)
90     {
91         _hostChangeCallbacks.erase(name);
92     }
93 
94     /**
95      * @brief Returns the BMC firmware version
96      *
97      * @return std::string - The BMC version
98      */
99     virtual std::string getBMCFWVersion() const
100     {
101         return _bmcFWVersion;
102     }
103 
104     /**
105      * @brief Returns the server firmware version
106      *
107      * @return std::string - The server firmware version
108      */
109     virtual std::string getServerFWVersion() const
110     {
111         return _serverFWVersion;
112     }
113 
114     /**
115      * @brief Returns the BMC FW version ID
116      *
117      * @return std::string - The BMC FW version ID
118      */
119     virtual std::string getBMCFWVersionID() const
120     {
121         return _bmcFWVersionID;
122     }
123 
124     /**
125      * @brief Returns the process name given its PID.
126      *
127      * @param[in] pid - The PID value as a string
128      *
129      * @return std::optional<std::string> - The name, or std::nullopt
130      */
131     std::optional<std::string> getProcessName(const std::string& pid) const
132     {
133         namespace fs = std::filesystem;
134 
135         fs::path path{"/proc"};
136         path /= fs::path{pid} / "exe";
137 
138         if (fs::exists(path))
139         {
140             return fs::read_symlink(path);
141         }
142 
143         return std::nullopt;
144     }
145 
146     /**
147      * @brief Returns the 'send event logs to host' setting.
148      *
149      * @return bool - If sending PELs to the host is enabled.
150      */
151     virtual bool getHostPELEnablement() const
152     {
153         return _sendPELsToHost;
154     }
155 
156     /**
157      * @brief Returns the BMC state
158      *
159      * @return std::string - The BMC state property value
160      */
161     virtual std::string getBMCState() const
162     {
163         return _bmcState;
164     }
165 
166     /**
167      * @brief Returns the Chassis state
168      *
169      * @return std::string - The chassis state property value
170      */
171     virtual std::string getChassisState() const
172     {
173         return _chassisState;
174     }
175 
176     /**
177      * @brief Returns the chassis requested power
178      *        transition value.
179      *
180      * @return std::string - The chassis transition property
181      */
182     virtual std::string getChassisTransition() const
183     {
184         return _chassisTransition;
185     }
186 
187     /**
188      * @brief Returns the Host state
189      *
190      * @return std::string - The Host state property value
191      */
192     virtual std::string getHostState() const
193     {
194         return _hostState;
195     }
196 
197     /**
198      * @brief Returns the Boot state
199      *
200      * @return std::string - The Boot state property value
201      */
202     virtual std::string getBootState() const
203     {
204         return _bootState;
205     }
206 
207     /**
208      * @brief Returns the motherboard CCIN
209      *
210      * @return std::string The motherboard CCIN
211      */
212     virtual std::string getMotherboardCCIN() const = 0;
213 
214     /**
215      * @brief Returns the system IM
216      *
217      * @return std::string The system IM
218      */
219     virtual std::vector<uint8_t> getSystemIMKeyword() const = 0;
220 
221     /**
222      * @brief Get the fields from the inventory necessary for doing
223      *        a callout on an inventory path.
224      *
225      * @param[in] inventoryPath - The item to get the data for
226      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
227      * @param[out] ccin - Filled in with the VINI/CC keyword
228      * @param[out] serialNumber - Filled in with the VINI/SN keyword
229      */
230     virtual void getHWCalloutFields(const std::string& inventoryPath,
231                                     std::string& fruPartNumber,
232                                     std::string& ccin,
233                                     std::string& serialNumber) const = 0;
234 
235     /**
236      * @brief Get the location code for an inventory item.
237      *
238      * @param[in] inventoryPath - The item to get the data for
239      *
240      * @return std::string - The location code
241      */
242     virtual std::string
243         getLocationCode(const std::string& inventoryPath) const = 0;
244 
245     /**
246      * @brief Get the list of system type names the system is called.
247      *
248      * @return std::vector<std::string> - The list of names
249      */
250     virtual std::vector<std::string> getSystemNames() const = 0;
251 
252     /**
253      * @brief Fills in the placeholder 'Ufcs' in the passed in location
254      *        code with the machine feature code and serial number, which
255      *        is needed to create a valid location code.
256      *
257      * @param[in] locationCode - Location code value starting with Ufcs-, and
258      *                           if that isn't present it will be added first.
259      *
260      * @param[in] node - The node number the location is on.
261      *
262      * @return std::string - The expanded location code
263      */
264     virtual std::string expandLocationCode(const std::string& locationCode,
265                                            uint16_t node) const = 0;
266 
267     /**
268      * @brief Returns the inventory path for the FRU that the location
269      *        code represents.
270      *
271      * @param[in] locationCode - If an expanded location code, then the
272      *                           full location code.
273      *                           If not expanded, a location code value
274      *                           starting with Ufcs-, and if that isn't
275      *                           present it will be added first.
276      *
277      * @param[in] node - The node number the location is on.  Ignored if the
278      *                   expanded location code is passed in.
279      *
280      * @param[in] expanded - If the location code already has the relevent
281      *                       VPD fields embedded in it.
282      *
283      * @return std::string - The inventory D-Bus object
284      */
285     virtual std::string getInventoryFromLocCode(const std::string& LocationCode,
286                                                 uint16_t node,
287                                                 bool expanded) const = 0;
288 
289     /**
290      * @brief Sets the Asserted property on the LED group passed in.
291      *
292      * @param[in] ledGroup - The LED group D-Bus path
293      * @param[in] value - The value to set it to
294      */
295     virtual void assertLEDGroup(const std::string& ledGroup,
296                                 bool value) const = 0;
297 
298     /**
299      * @brief Sets the Functional property on the OperationalStatus
300      *        interface on a D-Bus object.
301      *
302      * @param[in] objectPath - The D-Bus object path
303      * @param[in] functional - The value
304      */
305     virtual void setFunctional(const std::string& objectPath,
306                                bool functional) const = 0;
307 
308     /**
309      * @brief Sets the critical association on the D-Bus object.
310      *
311      * @param[in] objectPath - The D-Bus object path
312      */
313     virtual void
314         setCriticalAssociation(const std::string& objectPath) const = 0;
315 
316     /**
317      * @brief Returns the manufacturing QuiesceOnError property
318      *
319      * @return bool - Manufacturing QuiesceOnError property
320      */
321     virtual bool getQuiesceOnError() const = 0;
322 
323     /**
324      * @brief Split location code into base and connector segments
325      *
326      * A location code that ends in '-Tx', where 'x' is a number,
327      * represents a connector, such as a USB cable connector.
328      *
329      * This function splits the passed in location code into a
330      * base and connector segment.  e.g.:
331      *   P0-T1 -> ['P0', '-T1']
332      *   P0 -> ['P0', '']
333      *
334      * @param[in] locationCode - location code to split
335      * @return pair<string, string> - The base and connector segments
336      */
337     static std::pair<std::string, std::string>
338         extractConnectorFromLocCode(const std::string& locationCode);
339 
340     /**
341      * @brief Returns the dump status
342      *
343      * @return bool dump status
344      */
345     virtual std::vector<bool>
346         checkDumpStatus(const std::vector<std::string>& type) const = 0;
347 
348   protected:
349     /**
350      * @brief Sets the host on/off state and runs any
351      *        callback functions (if there was a change).
352      */
353     void setHostUp(bool hostUp)
354     {
355         if (_hostUp != hostUp)
356         {
357             _hostUp = hostUp;
358 
359             for (auto& [name, func] : _hostChangeCallbacks)
360             {
361                 try
362                 {
363                     func(_hostUp);
364                 }
365                 catch (const std::exception& e)
366                 {
367                     using namespace phosphor::logging;
368                     log<level::ERR>("A host state change callback threw "
369                                     "an exception");
370                 }
371             }
372         }
373     }
374 
375     /**
376      * @brief The hardware management console status.  Always kept
377      *        up to date.
378      */
379     bool _hmcManaged = false;
380 
381     /**
382      * @brief The host up status.  Always kept up to date.
383      */
384     bool _hostUp = false;
385 
386     /**
387      * @brief The map of host state change subscriber
388      *        names to callback functions.
389      */
390     std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks;
391 
392     /**
393      * @brief The BMC firmware version string
394      */
395     std::string _bmcFWVersion;
396 
397     /**
398      * @brief The server firmware version string
399      */
400     std::string _serverFWVersion;
401 
402     /**
403      * @brief The BMC firmware version ID string
404      */
405     std::string _bmcFWVersionID;
406 
407     /**
408      * @brief If sending PELs is enabled.
409      *
410      * This is usually set to false in manufacturing test.
411      */
412     bool _sendPELsToHost = true;
413 
414     /**
415      * @brief The BMC state property
416      */
417     std::string _bmcState;
418 
419     /**
420      * @brief The Chassis current power state property
421      */
422     std::string _chassisState;
423 
424     /**
425      * @brief The Chassis requested power transition property
426      */
427     std::string _chassisTransition;
428 
429     /**
430      * @brief The host state property
431      */
432     std::string _hostState;
433 
434     /**
435      * @brief The boot state property
436      */
437     std::string _bootState;
438 };
439 
440 /**
441  * @class DataInterface
442  *
443  * Concrete implementation of DataInterfaceBase.
444  */
445 class DataInterface : public DataInterfaceBase
446 {
447   public:
448     DataInterface() = delete;
449     ~DataInterface() = default;
450     DataInterface(const DataInterface&) = default;
451     DataInterface& operator=(const DataInterface&) = default;
452     DataInterface(DataInterface&&) = default;
453     DataInterface& operator=(DataInterface&&) = default;
454 
455     /**
456      * @brief Constructor
457      *
458      * @param[in] bus - The sdbusplus bus object
459      */
460     explicit DataInterface(sdbusplus::bus::bus& bus);
461 
462     /**
463      * @brief Finds the D-Bus service name that hosts the
464      *        passed in path and interface.
465      *
466      * @param[in] objectPath - The D-Bus object path
467      * @param[in] interface - The D-Bus interface
468      */
469     DBusService getService(const std::string& objectPath,
470                            const std::string& interface) const;
471 
472     /**
473      * @brief Wrapper for the 'GetAll' properties method call
474      *
475      * @param[in] service - The D-Bus service to call it on
476      * @param[in] objectPath - The D-Bus object path
477      * @param[in] interface - The interface to get the props on
478      *
479      * @return DBusPropertyMap - The property results
480      */
481     DBusPropertyMap getAllProperties(const std::string& service,
482                                      const std::string& objectPath,
483                                      const std::string& interface) const;
484     /**
485      * @brief Wrapper for the 'Get' properties method call
486      *
487      * @param[in] service - The D-Bus service to call it on
488      * @param[in] objectPath - The D-Bus object path
489      * @param[in] interface - The interface to get the property on
490      * @param[in] property - The property name
491      * @param[out] value - Filled in with the property value.
492      */
493     void getProperty(const std::string& service, const std::string& objectPath,
494                      const std::string& interface, const std::string& property,
495                      DBusValue& value) const;
496     /**
497      * @brief Returns the machine Type/Model
498      *
499      * @return string - The machine Type/Model string
500      */
501     std::string getMachineTypeModel() const override;
502 
503     /**
504      * @brief Returns the machine serial number
505      *
506      * @return string - The machine serial number
507      */
508     std::string getMachineSerialNumber() const override;
509 
510     /**
511      * @brief Returns the motherboard CCIN
512      *
513      * @return std::string The motherboard CCIN
514      */
515     std::string getMotherboardCCIN() const override;
516 
517     /**
518      * @brief Returns the system IM
519      *
520      * @return std::vector The system IM keyword in 4 byte vector
521      */
522     std::vector<uint8_t> getSystemIMKeyword() const override;
523 
524     /**
525      * @brief Get the fields from the inventory necessary for doing
526      *        a callout on an inventory path.
527      *
528      * @param[in] inventoryPath - The item to get the data for
529      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
530      * @param[out] ccin - Filled in with the VINI/CC keyword
531      * @param[out] serialNumber - Filled in with the VINI/SN keyword
532      */
533     void getHWCalloutFields(const std::string& inventoryPath,
534                             std::string& fruPartNumber, std::string& ccin,
535                             std::string& serialNumber) const override;
536 
537     /**
538      * @brief Get the location code for an inventory item.
539      *
540      * Throws an exception if the inventory item doesn't have the
541      * location code interface.
542      *
543      * @param[in] inventoryPath - The item to get the data for
544      *
545      * @return std::string - The location code
546      */
547     std::string
548         getLocationCode(const std::string& inventoryPath) const override;
549 
550     /**
551      * @brief Get the list of system type names the system is called.
552      *
553      * @return std::vector<std::string> - The list of names
554      */
555     std::vector<std::string> getSystemNames() const override;
556 
557     /**
558      * @brief Fills in the placeholder 'Ufcs' in the passed in location
559      *        code with the machine feature code and serial number, which
560      *        is needed to create a valid location code.
561      *
562      * @param[in] locationCode - Location code value starting with Ufcs-, and
563      *                           if that isn't present it will be added first.
564      *
565      * @param[in] node - The node number the location is one.
566      *
567      * @return std::string - The expanded location code
568      */
569     std::string expandLocationCode(const std::string& locationCode,
570                                    uint16_t node) const override;
571 
572     /**
573      * @brief Returns the inventory path for the FRU that the location
574      *        code represents.
575      *
576      * @param[in] locationCode - If an expanded location code, then the
577      *                           full location code.
578      *                           If not expanded, a location code value
579      *                           starting with Ufcs-, and if that isn't
580      *                           present it will be added first.
581      *
582      * @param[in] node - The node number the location is on.  Ignored if the
583      *                   expanded location code is passed in.
584      *
585      * @param[in] expanded - If the location code already has the relevent
586      *                       VPD fields embedded in it.
587      *
588      * @return std::string - The inventory D-Bus object
589      */
590     std::string getInventoryFromLocCode(const std::string& locationCode,
591                                         uint16_t node,
592                                         bool expanded) const override;
593 
594     /**
595      * @brief Sets the Asserted property on the LED group passed in.
596      *
597      * @param[in] ledGroup - The LED group D-Bus path
598      * @param[in] value - The value to set it to
599      */
600     void assertLEDGroup(const std::string& ledGroup, bool value) const override;
601 
602     /**
603      * @brief Sets the Functional property on the OperationalStatus
604      *        interface on a D-Bus object.
605      *
606      * @param[in] objectPath - The D-Bus object path
607      * @param[in] functional - The value
608      */
609     void setFunctional(const std::string& objectPath,
610                        bool functional) const override;
611 
612     /**
613      * @brief Sets the critical association on the D-Bus object.
614      *
615      * @param[in] objectPath - The D-Bus object path
616      */
617     void setCriticalAssociation(const std::string& objectPath) const override;
618 
619     /**
620      * @brief Returns the manufacturing QuiesceOnError property
621      *
622      * @return bool - Manufacturing QuiesceOnError property
623      */
624     bool getQuiesceOnError() const override;
625 
626     /**
627      * @brief Returns the dump status
628      *
629      * @param[in] type - The dump type to check for
630      *
631      * @return bool dump status
632      */
633     std::vector<bool>
634         checkDumpStatus(const std::vector<std::string>& type) const override;
635 
636   private:
637     /**
638      * @brief Reads the BMC firmware version string and puts it into
639      *        _bmcFWVersion.
640      */
641     void readBMCFWVersion();
642 
643     /**
644      * @brief Reads the server firmware version string and puts it into
645      *        _serverFWVersion.
646      */
647     void readServerFWVersion();
648 
649     /**
650      * @brief Reads the BMC firmware version ID and puts it into
651      *        _bmcFWVersionID.
652      */
653     void readBMCFWVersionID();
654 
655     /**
656      * @brief Finds all D-Bus paths that contain any of the interfaces
657      *        passed in, by using GetSubTreePaths.
658      *
659      * @param[in] interfaces - The desired interfaces
660      *
661      * @return The D-Bus paths.
662      */
663     DBusPathList getPaths(const DBusInterfaceList& interfaces) const;
664 
665     /**
666      * @brief The interfacesAdded callback used on the inventory to
667      *        find the D-Bus object that has the motherboard interface.
668      *        When the motherboard is found, it then adds a PropertyWatcher
669      *        for the motherboard CCIN.
670      */
671     void motherboardIfaceAdded(sdbusplus::message::message& msg);
672 
673     /**
674      * @brief Adds the Ufcs- prefix to the location code passed in
675      *        if necessary.
676      *
677      * Needed because the location codes that come back from the
678      * message registry and device callout JSON don't have it.
679      *
680      * @param[in] - The location code without a prefix, like P1-C1
681      *
682      * @return std::string - The location code with the prefix
683      */
684     static std::string addLocationCodePrefix(const std::string& locationCode);
685 
686     /**
687      * @brief The D-Bus property or interface watchers that have callbacks
688      *        registered that will set members in this class when
689      *        they change.
690      */
691     std::vector<std::unique_ptr<DBusWatcher>> _properties;
692 
693     /**
694      * @brief The sdbusplus bus object for making D-Bus calls.
695      */
696     sdbusplus::bus::bus& _bus;
697 
698     /**
699      * @brief The interfacesAdded match object used to wait for inventory
700      *        interfaces to show up, so that the object with the motherboard
701      *        interface can be found.  After it is found, this object is
702      *        deleted.
703      */
704     std::unique_ptr<sdbusplus::bus::match_t> _inventoryIfacesAddedMatch;
705 };
706 
707 } // namespace pels
708 } // namespace openpower
709