1 #pragma once
2 
3 #include "dbus_types.hpp"
4 #include "dbus_watcher.hpp"
5 
6 #include <phosphor-logging/lg2.hpp>
7 #include <sdbusplus/bus.hpp>
8 #include <sdbusplus/bus/match.hpp>
9 
10 #include <filesystem>
11 #include <fstream>
12 
13 namespace openpower
14 {
15 namespace pels
16 {
17 
18 /**
19  * @class DataInterface
20  *
21  * A base class for gathering data about the system for use
22  * in PELs. Implemented this way to facilitate mocking.
23  */
24 class DataInterfaceBase
25 {
26   public:
27     DataInterfaceBase() = default;
28     virtual ~DataInterfaceBase() = default;
29     DataInterfaceBase(const DataInterfaceBase&) = default;
30     DataInterfaceBase& operator=(const DataInterfaceBase&) = default;
31     DataInterfaceBase(DataInterfaceBase&&) = default;
32     DataInterfaceBase& operator=(DataInterfaceBase&&) = default;
33 
34     /**
35      * @brief Returns the machine Type/Model
36      *
37      * @return string - The machine Type/Model string
38      */
39     virtual std::string getMachineTypeModel() const = 0;
40 
41     /**
42      * @brief Returns the machine serial number
43      *
44      * @return string - The machine serial number
45      */
46     virtual std::string getMachineSerialNumber() const = 0;
47 
48     /**
49      * @brief Says if the system is managed by a hardware
50      *        management console.
51      * @return bool - If the system is HMC managed
52      */
53     virtual bool isHMCManaged() const
54     {
55         return _hmcManaged;
56     }
57 
58     /**
59      * @brief Says if the host is up and running
60      *
61      * @return bool - If the host is running
62      */
63     virtual bool isHostUp() const
64     {
65         return _hostUp;
66     }
67 
68     using HostStateChangeFunc = std::function<void(bool)>;
69 
70     /**
71      * @brief Register a callback function that will get
72      *        called on all host on/off transitions.
73      *
74      * The void(bool) function will get passed the new
75      * value of the host state.
76      *
77      * @param[in] name - The subscription name
78      * @param[in] func - The function to run
79      */
80     void subscribeToHostStateChange(const std::string& name,
81                                     HostStateChangeFunc func)
82     {
83         _hostChangeCallbacks[name] = func;
84     }
85 
86     /**
87      * @brief Unsubscribe from host state changes.
88      *
89      * @param[in] name - The subscription name
90      */
91     void unsubscribeFromHostStateChange(const std::string& name)
92     {
93         _hostChangeCallbacks.erase(name);
94     }
95 
96     using FRUPresentFunc =
97         std::function<void(const std::string& /* locationCode */)>;
98 
99     /**
100      * @brief Register a callback function that will get
101      *        called when certain FRUs become present.
102      *
103      * The void(std::string) function will get passed the
104      * location code of the FRU.
105      *
106      * @param[in] name - The subscription name
107      * @param[in] func - The function to run
108      */
109     void subscribeToFruPresent(const std::string& name, FRUPresentFunc func)
110     {
111         _fruPresentCallbacks[name] = std::move(func);
112     }
113 
114     /**
115      * @brief Returns the BMC firmware version
116      *
117      * @return std::string - The BMC version
118      */
119     virtual std::string getBMCFWVersion() const
120     {
121         return _bmcFWVersion;
122     }
123 
124     /**
125      * @brief Returns the server firmware version
126      *
127      * @return std::string - The server firmware version
128      */
129     virtual std::string getServerFWVersion() const
130     {
131         return _serverFWVersion;
132     }
133 
134     /**
135      * @brief Returns the BMC FW version ID
136      *
137      * @return std::string - The BMC FW version ID
138      */
139     virtual std::string getBMCFWVersionID() const
140     {
141         return _bmcFWVersionID;
142     }
143 
144     /**
145      * @brief Returns the process name given its PID.
146      *
147      * @param[in] pid - The PID value as a string
148      *
149      * @return std::optional<std::string> - The name, or std::nullopt
150      */
151     std::optional<std::string> getProcessName(const std::string& pid) const
152     {
153         namespace fs = std::filesystem;
154 
155         fs::path path{"/proc"};
156         path /= fs::path{pid} / "exe";
157 
158         if (fs::exists(path))
159         {
160             return fs::read_symlink(path);
161         }
162 
163         return std::nullopt;
164     }
165 
166     /**
167      * @brief Returns the time the system was running.
168      *
169      * @return std::optional<uint64_t> - The System uptime or std::nullopt
170      */
171     std::optional<uint64_t> getUptimeInSeconds() const
172     {
173         std::ifstream versionFile{"/proc/uptime"};
174         std::string line{};
175 
176         std::getline(versionFile, line);
177         auto pos = line.find(" ");
178         if (pos == std::string::npos)
179         {
180             return std::nullopt;
181         }
182 
183         uint64_t seconds = atol(line.substr(0, pos).c_str());
184         if (seconds == 0)
185         {
186             return std::nullopt;
187         }
188 
189         return seconds;
190     }
191 
192     /**
193      * @brief Returns the time the system was running.
194      *
195      * @param[in] seconds - The number of seconds the system has been running
196      *
197      * @return std::string - days/hours/minutes/seconds
198      */
199     std::string getBMCUptime(uint64_t seconds) const
200     {
201         time_t t(seconds);
202         tm* p = gmtime(&t);
203 
204         std::string uptime = std::to_string(p->tm_year - 70) + "y " +
205                              std::to_string(p->tm_yday) + "d " +
206                              std::to_string(p->tm_hour) + "h " +
207                              std::to_string(p->tm_min) + "m " +
208                              std::to_string(p->tm_sec) + "s";
209 
210         return uptime;
211     }
212 
213     /**
214      * @brief Returns the system load average over the past 1 minute, 5 minutes
215      *        and 15 minutes.
216      *
217      * @return std::string - The system load average
218      */
219     std::string getBMCLoadAvg() const
220     {
221         std::string loadavg{};
222 
223         std::ifstream loadavgFile{"/proc/loadavg"};
224         std::string line;
225         std::getline(loadavgFile, line);
226 
227         size_t count = 3;
228         for (size_t i = 0; i < count; i++)
229         {
230             auto pos = line.find(" ");
231             if (pos == std::string::npos)
232             {
233                 return {};
234             }
235 
236             if (i != count - 1)
237             {
238                 loadavg.append(line.substr(0, pos + 1));
239             }
240             else
241             {
242                 loadavg.append(line.substr(0, pos));
243             }
244 
245             line = line.substr(pos + 1);
246         }
247 
248         return loadavg;
249     }
250 
251     /**
252      * @brief Returns the 'send event logs to host' setting.
253      *
254      * @return bool - If sending PELs to the host is enabled.
255      */
256     virtual bool getHostPELEnablement() const
257     {
258         return _sendPELsToHost;
259     }
260 
261     /**
262      * @brief Returns the BMC state
263      *
264      * @return std::string - The BMC state property value
265      */
266     virtual std::string getBMCState() const
267     {
268         return _bmcState;
269     }
270 
271     /**
272      * @brief Returns the Chassis state
273      *
274      * @return std::string - The chassis state property value
275      */
276     virtual std::string getChassisState() const
277     {
278         return _chassisState;
279     }
280 
281     /**
282      * @brief Returns the chassis requested power
283      *        transition value.
284      *
285      * @return std::string - The chassis transition property
286      */
287     virtual std::string getChassisTransition() const
288     {
289         return _chassisTransition;
290     }
291 
292     /**
293      * @brief Returns the Host state
294      *
295      * @return std::string - The Host state property value
296      */
297     virtual std::string getHostState() const
298     {
299         return _hostState;
300     }
301 
302     /**
303      * @brief Returns the Boot state
304      *
305      * @return std::string - The Boot state property value
306      */
307     virtual std::string getBootState() const
308     {
309         return _bootState;
310     }
311 
312     /**
313      * @brief Returns the motherboard CCIN
314      *
315      * @return std::string The motherboard CCIN
316      */
317     virtual std::string getMotherboardCCIN() const = 0;
318 
319     /**
320      * @brief Returns the system IM
321      *
322      * @return std::string The system IM
323      */
324     virtual std::vector<uint8_t> getSystemIMKeyword() const = 0;
325 
326     /**
327      * @brief Get the fields from the inventory necessary for doing
328      *        a callout on an inventory path.
329      *
330      * @param[in] inventoryPath - The item to get the data for
331      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
332      * @param[out] ccin - Filled in with the VINI/CC keyword
333      * @param[out] serialNumber - Filled in with the VINI/SN keyword
334      */
335     virtual void getHWCalloutFields(const std::string& inventoryPath,
336                                     std::string& fruPartNumber,
337                                     std::string& ccin,
338                                     std::string& serialNumber) const = 0;
339 
340     /**
341      * @brief Get the location code for an inventory item.
342      *
343      * @param[in] inventoryPath - The item to get the data for
344      *
345      * @return std::string - The location code
346      */
347     virtual std::string
348         getLocationCode(const std::string& inventoryPath) const = 0;
349 
350     /**
351      * @brief Get the list of system type names the system is called.
352      *
353      * @return std::vector<std::string> - The list of names
354      */
355     virtual std::vector<std::string> getSystemNames() const = 0;
356 
357     /**
358      * @brief Fills in the placeholder 'Ufcs' in the passed in location
359      *        code with the machine feature code and serial number, which
360      *        is needed to create a valid location code.
361      *
362      * @param[in] locationCode - Location code value starting with Ufcs-, and
363      *                           if that isn't present it will be added first.
364      *
365      * @param[in] node - The node number the location is on.
366      *
367      * @return std::string - The expanded location code
368      */
369     virtual std::string expandLocationCode(const std::string& locationCode,
370                                            uint16_t node) const = 0;
371 
372     /**
373      * @brief Returns the inventory paths for the FRU that the location
374      *        code represents.
375      *
376      * @param[in] locationCode - If an expanded location code, then the
377      *                           full location code.
378      *                           If not expanded, a location code value
379      *                           starting with Ufcs-, and if that isn't
380      *                           present it will be added first.
381      *
382      * @param[in] node - The node number the location is on.  Ignored if the
383      *                   expanded location code is passed in.
384      *
385      * @param[in] expanded - If the location code already has the relevent
386      *                       VPD fields embedded in it.
387      *
388      * @return std::vector<std::string> - The inventory D-Bus objects
389      */
390     virtual std::vector<std::string>
391         getInventoryFromLocCode(const std::string& LocationCode, uint16_t node,
392                                 bool expanded) const = 0;
393 
394     /**
395      * @brief Sets the Asserted property on the LED group passed in.
396      *
397      * @param[in] ledGroup - The LED group D-Bus path
398      * @param[in] value - The value to set it to
399      */
400     virtual void assertLEDGroup(const std::string& ledGroup,
401                                 bool value) const = 0;
402 
403     /**
404      * @brief Sets the Functional property on the OperationalStatus
405      *        interface on a D-Bus object.
406      *
407      * @param[in] objectPath - The D-Bus object path
408      * @param[in] functional - The value
409      */
410     virtual void setFunctional(const std::string& objectPath,
411                                bool functional) const = 0;
412 
413     /**
414      * @brief Sets the critical association on the D-Bus object.
415      *
416      * @param[in] objectPath - The D-Bus object path
417      */
418     virtual void
419         setCriticalAssociation(const std::string& objectPath) const = 0;
420 
421     /**
422      * @brief Returns the manufacturing QuiesceOnError property
423      *
424      * @return bool - Manufacturing QuiesceOnError property
425      */
426     virtual bool getQuiesceOnError() const = 0;
427 
428     /**
429      * @brief Split location code into base and connector segments
430      *
431      * A location code that ends in '-Tx', where 'x' is a number,
432      * represents a connector, such as a USB cable connector.
433      *
434      * This function splits the passed in location code into a
435      * base and connector segment.  e.g.:
436      *   P0-T1 -> ['P0', '-T1']
437      *   P0 -> ['P0', '']
438      *
439      * @param[in] locationCode - location code to split
440      * @return pair<string, string> - The base and connector segments
441      */
442     static std::pair<std::string, std::string>
443         extractConnectorFromLocCode(const std::string& locationCode);
444 
445     /**
446      * @brief Returns the dump status
447      *
448      * @return bool dump status
449      */
450     virtual std::vector<bool>
451         checkDumpStatus(const std::vector<std::string>& type) const = 0;
452 
453     /**
454      * @brief Create guard record
455      *
456      *  @param[in] binPath: phal devtree binary path used as key
457      *  @param[in] type: Guard type
458      *  @param[in] logPath: error log entry object path
459      */
460     virtual void createGuardRecord(const std::vector<uint8_t>& binPath,
461                                    const std::string& type,
462                                    const std::string& logPath) const = 0;
463 
464     /**
465      * @brief Create Progress SRC property on the boot progress
466      *        interface on a D-Bus object.
467      *
468      * @param[in] priSRC - Primary SRC value (e.g. BD8D1001)
469      * @param[in] srcStruct - Full SRC base structure
470      */
471     virtual void
472         createProgressSRC(const uint64_t& priSRC,
473                           const std::vector<uint8_t>& srcStruct) const = 0;
474 
475     /**
476      * @brief Get the list of unresolved OpenBMC event log ids that have an
477      * associated hardware isolation entry.
478      *
479      * @return std::vector<uint32_t> - The list of log ids
480      */
481     virtual std::vector<uint32_t> getLogIDWithHwIsolation() const = 0;
482 
483     /**
484      * @brief Returns the latest raw progress SRC from the State.Boot.Raw
485      *        D-Bus interface.
486      *
487      * @return std::vector<uint8_t> - The progress SRC bytes
488      */
489     virtual std::vector<uint8_t> getRawProgressSRC() const = 0;
490 
491   protected:
492     /**
493      * @brief Sets the host on/off state and runs any
494      *        callback functions (if there was a change).
495      */
496     void setHostUp(bool hostUp)
497     {
498         if (_hostUp != hostUp)
499         {
500             _hostUp = hostUp;
501 
502             for (auto& [name, func] : _hostChangeCallbacks)
503             {
504                 try
505                 {
506                     func(_hostUp);
507                 }
508                 catch (const std::exception& e)
509                 {
510                     lg2::error(
511                         "A host state change callback threw an exception");
512                 }
513             }
514         }
515     }
516 
517     /**
518      * @brief Runs the callback functions registered when
519      *        FRUs become present.
520      */
521     void setFruPresent(const std::string& locationCode)
522     {
523         for (const auto& [_, func] : _fruPresentCallbacks)
524         {
525             try
526             {
527                 func(locationCode);
528             }
529             catch (const std::exception& e)
530             {
531                 lg2::error("A FRU present callback threw an exception");
532             }
533         }
534     }
535 
536     /**
537      * @brief The hardware management console status.  Always kept
538      *        up to date.
539      */
540     bool _hmcManaged = false;
541 
542     /**
543      * @brief The host up status.  Always kept up to date.
544      */
545     bool _hostUp = false;
546 
547     /**
548      * @brief The map of host state change subscriber
549      *        names to callback functions.
550      */
551     std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks;
552 
553     /**
554      * @brief The map of FRU present subscriber
555      *        names to callback functions.
556      */
557     std::map<std::string, FRUPresentFunc> _fruPresentCallbacks;
558 
559     /**
560      * @brief The BMC firmware version string
561      */
562     std::string _bmcFWVersion;
563 
564     /**
565      * @brief The server firmware version string
566      */
567     std::string _serverFWVersion;
568 
569     /**
570      * @brief The BMC firmware version ID string
571      */
572     std::string _bmcFWVersionID;
573 
574     /**
575      * @brief If sending PELs is enabled.
576      *
577      * This is usually set to false in manufacturing test.
578      */
579     bool _sendPELsToHost = true;
580 
581     /**
582      * @brief The BMC state property
583      */
584     std::string _bmcState;
585 
586     /**
587      * @brief The Chassis current power state property
588      */
589     std::string _chassisState;
590 
591     /**
592      * @brief The Chassis requested power transition property
593      */
594     std::string _chassisTransition;
595 
596     /**
597      * @brief The host state property
598      */
599     std::string _hostState;
600 
601     /**
602      * @brief The boot state property
603      */
604     std::string _bootState;
605 };
606 
607 /**
608  * @class DataInterface
609  *
610  * Concrete implementation of DataInterfaceBase.
611  */
612 class DataInterface : public DataInterfaceBase
613 {
614   public:
615     DataInterface() = delete;
616     ~DataInterface() = default;
617     DataInterface(const DataInterface&) = default;
618     DataInterface& operator=(const DataInterface&) = default;
619     DataInterface(DataInterface&&) = default;
620     DataInterface& operator=(DataInterface&&) = default;
621 
622     /**
623      * @brief Constructor
624      *
625      * @param[in] bus - The sdbusplus bus object
626      */
627     explicit DataInterface(sdbusplus::bus_t& bus);
628 
629     /**
630      * @brief Finds the D-Bus service name that hosts the
631      *        passed in path and interface.
632      *
633      * @param[in] objectPath - The D-Bus object path
634      * @param[in] interface - The D-Bus interface
635      */
636     DBusService getService(const std::string& objectPath,
637                            const std::string& interface) const;
638 
639     /**
640      * @brief Wrapper for the 'GetAll' properties method call
641      *
642      * @param[in] service - The D-Bus service to call it on
643      * @param[in] objectPath - The D-Bus object path
644      * @param[in] interface - The interface to get the props on
645      *
646      * @return DBusPropertyMap - The property results
647      */
648     DBusPropertyMap getAllProperties(const std::string& service,
649                                      const std::string& objectPath,
650                                      const std::string& interface) const;
651     /**
652      * @brief Wrapper for the 'Get' properties method call
653      *
654      * @param[in] service - The D-Bus service to call it on
655      * @param[in] objectPath - The D-Bus object path
656      * @param[in] interface - The interface to get the property on
657      * @param[in] property - The property name
658      * @param[out] value - Filled in with the property value.
659      */
660     void getProperty(const std::string& service, const std::string& objectPath,
661                      const std::string& interface, const std::string& property,
662                      DBusValue& value) const;
663     /**
664      * @brief Returns the machine Type/Model
665      *
666      * @return string - The machine Type/Model string
667      */
668     std::string getMachineTypeModel() const override;
669 
670     /**
671      * @brief Returns the machine serial number
672      *
673      * @return string - The machine serial number
674      */
675     std::string getMachineSerialNumber() const override;
676 
677     /**
678      * @brief Returns the motherboard CCIN
679      *
680      * @return std::string The motherboard CCIN
681      */
682     std::string getMotherboardCCIN() const override;
683 
684     /**
685      * @brief Returns the system IM
686      *
687      * @return std::vector The system IM keyword in 4 byte vector
688      */
689     std::vector<uint8_t> getSystemIMKeyword() const override;
690 
691     /**
692      * @brief Get the fields from the inventory necessary for doing
693      *        a callout on an inventory path.
694      *
695      * @param[in] inventoryPath - The item to get the data for
696      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
697      * @param[out] ccin - Filled in with the VINI/CC keyword
698      * @param[out] serialNumber - Filled in with the VINI/SN keyword
699      */
700     void getHWCalloutFields(const std::string& inventoryPath,
701                             std::string& fruPartNumber, std::string& ccin,
702                             std::string& serialNumber) const override;
703 
704     /**
705      * @brief Get the location code for an inventory item.
706      *
707      * Throws an exception if the inventory item doesn't have the
708      * location code interface.
709      *
710      * @param[in] inventoryPath - The item to get the data for
711      *
712      * @return std::string - The location code
713      */
714     std::string
715         getLocationCode(const std::string& inventoryPath) const override;
716 
717     /**
718      * @brief Get the list of system type names the system is called.
719      *
720      * @return std::vector<std::string> - The list of names
721      */
722     std::vector<std::string> getSystemNames() const override;
723 
724     /**
725      * @brief Fills in the placeholder 'Ufcs' in the passed in location
726      *        code with the machine feature code and serial number, which
727      *        is needed to create a valid location code.
728      *
729      * @param[in] locationCode - Location code value starting with Ufcs-, and
730      *                           if that isn't present it will be added first.
731      *
732      * @param[in] node - The node number the location is one.
733      *
734      * @return std::string - The expanded location code
735      */
736     std::string expandLocationCode(const std::string& locationCode,
737                                    uint16_t node) const override;
738 
739     /**
740      * @brief Returns the inventory paths for the FRU that the location
741      *        code represents.
742      *
743      * @param[in] locationCode - If an expanded location code, then the
744      *                           full location code.
745      *                           If not expanded, a location code value
746      *                           starting with Ufcs-, and if that isn't
747      *                           present it will be added first.
748      *
749      * @param[in] node - The node number the location is on.  Ignored if the
750      *                   expanded location code is passed in.
751      *
752      * @param[in] expanded - If the location code already has the relevent
753      *                       VPD fields embedded in it.
754      *
755      * @return std::vector<std::string> - The inventory D-Bus objects
756      */
757     std::vector<std::string>
758         getInventoryFromLocCode(const std::string& locationCode, uint16_t node,
759                                 bool expanded) const override;
760 
761     /**
762      * @brief Sets the Asserted property on the LED group passed in.
763      *
764      * @param[in] ledGroup - The LED group D-Bus path
765      * @param[in] value - The value to set it to
766      */
767     void assertLEDGroup(const std::string& ledGroup, bool value) const override;
768 
769     /**
770      * @brief Sets the Functional property on the OperationalStatus
771      *        interface on a D-Bus object.
772      *
773      * @param[in] objectPath - The D-Bus object path
774      * @param[in] functional - The value
775      */
776     void setFunctional(const std::string& objectPath,
777                        bool functional) const override;
778 
779     /**
780      * @brief Sets the critical association on the D-Bus object.
781      *
782      * @param[in] objectPath - The D-Bus object path
783      */
784     void setCriticalAssociation(const std::string& objectPath) const override;
785 
786     /**
787      * @brief Returns the manufacturing QuiesceOnError property
788      *
789      * @return bool - Manufacturing QuiesceOnError property
790      */
791     bool getQuiesceOnError() const override;
792 
793     /**
794      * @brief Returns the dump status
795      *
796      * @param[in] type - The dump type to check for
797      *
798      * @return bool dump status
799      */
800     std::vector<bool>
801         checkDumpStatus(const std::vector<std::string>& type) const override;
802 
803     /**
804      * @brief Create guard record
805      *
806      *  @param[in] binPath: phal devtree binary path used as key
807      *  @param[in] type: Guard type
808      *  @param[in] logPath: error log entry object path
809      */
810     void createGuardRecord(const std::vector<uint8_t>& binPath,
811                            const std::string& type,
812                            const std::string& logPath) const override;
813 
814     /**
815      * @brief Create Progress SRC property on the boot progress
816      *        interface on a D-Bus object.
817      *
818      * @param[in] priSRC - Primary SRC value
819      * @param[in] srcStruct - Full SRC base structure
820      */
821     void
822         createProgressSRC(const uint64_t& priSRC,
823                           const std::vector<uint8_t>& srcStruct) const override;
824 
825     /**
826      * @brief Get the list of unresolved OpenBMC event log ids that have an
827      * associated hardware isolation entry.
828      *
829      * @return std::vector<uint32_t> - The list of log ids
830      */
831     std::vector<uint32_t> getLogIDWithHwIsolation() const override;
832 
833     /**
834      * @brief Returns the latest raw progress SRC from the State.Boot.Raw
835      *        D-Bus interface.
836      *
837      * @return std::vector<uint8_t>: The progress SRC bytes
838      */
839     std::vector<uint8_t> getRawProgressSRC() const override;
840 
841   private:
842     /**
843      * @brief Reads the BMC firmware version string and puts it into
844      *        _bmcFWVersion.
845      */
846     void readBMCFWVersion();
847 
848     /**
849      * @brief Reads the server firmware version string and puts it into
850      *        _serverFWVersion.
851      */
852     void readServerFWVersion();
853 
854     /**
855      * @brief Reads the BMC firmware version ID and puts it into
856      *        _bmcFWVersionID.
857      */
858     void readBMCFWVersionID();
859 
860     /**
861      * @brief Finds all D-Bus paths that contain any of the interfaces
862      *        passed in, by using GetSubTreePaths.
863      *
864      * @param[in] interfaces - The desired interfaces
865      *
866      * @return The D-Bus paths.
867      */
868     DBusPathList getPaths(const DBusInterfaceList& interfaces) const;
869 
870     /**
871      * @brief The interfacesAdded callback used on the inventory to
872      *        find the D-Bus object that has the motherboard interface.
873      *        When the motherboard is found, it then adds a PropertyWatcher
874      *        for the motherboard CCIN.
875      */
876     void motherboardIfaceAdded(sdbusplus::message_t& msg);
877 
878     /**
879      * @brief Start watching for the hotpluggable FRUs to become
880      *        present.
881      */
882     void startFruPlugWatch();
883 
884     /**
885      * @brief Create a D-Bus match object for the Present property
886      *        to change on the path passed in.
887      * @param[in] path - The path to watch.
888      */
889     void addHotplugWatch(const std::string& path);
890 
891     /**
892      * @brief Callback when an inventory interface was added.
893      *
894      * Only does something if it's one of the hotpluggable FRUs,
895      * in which case it will treat it as a hotplug if the
896      * Present property is true.
897      *
898      * @param[in] msg - The InterfacesAdded signal contents.
899      */
900     void inventoryIfaceAdded(sdbusplus::message_t& msg);
901 
902     /**
903      * @brief Callback when the Present property changes.
904      *
905      * If present, will run the registered callbacks.
906      *
907      * @param[in] msg - The PropertiesChanged signal contents.
908      */
909     void presenceChanged(sdbusplus::message_t& msg);
910 
911     /**
912      * @brief If the Present property is in the properties map
913      *        passed in and it is true, notify the subscribers.
914      *
915      * @param[in] path - The object path of the inventory item.
916      * @param[in] properties - The properties map
917      */
918     void notifyPresenceSubsribers(const std::string& path,
919                                   const DBusPropertyMap& properties);
920 
921     /**
922      * @brief Adds the Ufcs- prefix to the location code passed in
923      *        if necessary.
924      *
925      * Needed because the location codes that come back from the
926      * message registry and device callout JSON don't have it.
927      *
928      * @param[in] - The location code without a prefix, like P1-C1
929      *
930      * @return std::string - The location code with the prefix
931      */
932     static std::string addLocationCodePrefix(const std::string& locationCode);
933 
934     /**
935      * @brief The D-Bus property or interface watchers that have callbacks
936      *        registered that will set members in this class when
937      *        they change.
938      */
939     std::vector<std::unique_ptr<DBusWatcher>> _properties;
940 
941     std::unique_ptr<sdbusplus::bus::match_t> _invIaMatch;
942 
943     /**
944      * @brief The matches for watching for hotplugs.
945      *
946      * A map so we can check that we never get duplicates.
947      */
948     std::map<std::string, std::unique_ptr<sdbusplus::bus::match_t>>
949         _invPresentMatches;
950 
951     /**
952      * @brief The sdbusplus bus object for making D-Bus calls.
953      */
954     sdbusplus::bus_t& _bus;
955 };
956 
957 } // namespace pels
958 } // namespace openpower
959