xref: /openbmc/pldm/libpldmresponder/platform_config.cpp (revision 3c99e773aba9a3622523479d0044f542e9e16e26)
1 #include "platform_config.hpp"
2 
3 #include <phosphor-logging/lg2.hpp>
4 #include <xyz/openbmc_project/Inventory/Decorator/Compatible/common.hpp>
5 
6 using InventoryDecoratorCompatible =
7     sdbusplus::common::xyz::openbmc_project::inventory::decorator::Compatible;
8 
9 PHOSPHOR_LOG2_USING;
10 
11 namespace pldm
12 {
13 namespace responder
14 {
15 
16 namespace platform_config
17 {
18 /** @brief callback function invoked when interfaces get added from
19  *      Entity manager
20  *
21  *  @param[in] msg - Data associated with subscribed signal
22  */
systemCompatibleCallback(sdbusplus::message_t & msg)23 void Handler::systemCompatibleCallback(sdbusplus::message_t& msg)
24 {
25     sdbusplus::message::object_path path;
26 
27     pldm::utils::InterfaceMap interfaceMap;
28 
29     msg.read(path, interfaceMap);
30 
31     if (!interfaceMap.contains(InventoryDecoratorCompatible::interface))
32     {
33         return;
34     }
35     // Get the "Name" property value of the
36     // "xyz.openbmc_project.Inventory.Decorator.Compatible" interface
37     const auto& properties =
38         interfaceMap.at(InventoryDecoratorCompatible::interface);
39 
40     if (!properties.contains(
41             InventoryDecoratorCompatible::property_names::names))
42     {
43         return;
44     }
45     auto names = std::get<pldm::utils::Interfaces>(
46         properties.at(InventoryDecoratorCompatible::property_names::names));
47 
48     if (!names.empty())
49     {
50         std::optional<std::string> sysType =
51             getSysSpecificJsonDir(sysDirPath, names);
52         if (sysType.has_value())
53         {
54             systemType = sysType.value();
55         }
56         if (sysTypeCallback)
57         {
58             sysTypeCallback(systemType, true);
59         }
60     }
61 
62     if (!systemType.empty())
63     {
64         systemCompatibleMatchCallBack.reset();
65     }
66 }
67 
68 /** @brief Method to get the system type information
69  *
70  *  @return - the system type information
71  */
getPlatformName()72 std::optional<std::filesystem::path> Handler::getPlatformName()
73 {
74     if (!systemType.empty())
75     {
76         return fs::path{systemType};
77     }
78 
79     namespace fs = std::filesystem;
80     static const std::string entityMangerService =
81         "xyz.openbmc_project.EntityManager";
82 
83     static constexpr auto searchpath = "/xyz/openbmc_project/";
84     int depth = 0;
85     std::vector<std::string> systemCompatible = {
86         InventoryDecoratorCompatible::interface};
87 
88     try
89     {
90         pldm::utils::GetSubTreeResponse response =
91             pldm::utils::DBusHandler().getSubtree(searchpath, depth,
92                                                   systemCompatible);
93         auto& bus = pldm::utils::DBusHandler::getBus();
94 
95         for (const auto& [objectPath, serviceMap] : response)
96         {
97             try
98             {
99                 auto record = std::find_if(
100                     serviceMap.begin(), serviceMap.end(),
101                     [](auto map) { return map.first == entityMangerService; });
102 
103                 if (record != serviceMap.end())
104                 {
105                     auto method = bus.new_method_call(
106                         entityMangerService.c_str(), objectPath.c_str(),
107                         "org.freedesktop.DBus.Properties", "Get");
108                     method.append(
109                         InventoryDecoratorCompatible::interface,
110                         InventoryDecoratorCompatible::property_names::names);
111                     auto propSystemList =
112                         bus.call(method, dbusTimeout).unpack<PropertyValue>();
113                     auto systemList =
114                         std::get<std::vector<std::string>>(propSystemList);
115 
116                     if (!systemList.empty())
117                     {
118                         std::optional<std::string> sysType =
119                             getSysSpecificJsonDir(sysDirPath, systemList);
120                         // once systemtype received,then resetting a callback
121                         systemCompatibleMatchCallBack.reset();
122                         if (sysType.has_value())
123                         {
124                             systemType = sysType.value();
125                         }
126                         return fs::path{systemType};
127                     }
128                 }
129             }
130             catch (const std::exception& e)
131             {
132                 error(
133                     "Failed to get Names property at '{PATH}' on interface '{INTERFACE}', error - {ERROR}",
134                     "PATH", objectPath, "INTERFACE",
135                     InventoryDecoratorCompatible::interface, "ERROR", e);
136             }
137         }
138     }
139     catch (const std::exception& e)
140     {
141         error(
142             "Failed to make a d-bus call to get platform name, error - {ERROR}",
143             "ERROR", e);
144     }
145     return std::nullopt;
146 }
147 
getSysSpecificJsonDir(const fs::path & dirPath,const std::vector<std::string> & dirNames)148 std::optional<std::string> Handler::getSysSpecificJsonDir(
149     const fs::path& dirPath, const std::vector<std::string>& dirNames)
150 {
151     // The current setup assumes that the BIOS and PDR configurations always
152     // come from the same system type. If, in the future, we need to use BIOS
153     // and PDR configurations from different system types, we should create
154     // separate system type folders for each and update the logic to support
155     // this.
156 
157     if (dirPath.empty())
158     {
159         return std::nullopt;
160     }
161 
162     for (const auto& compatibleName : dirNames)
163     {
164         for (const auto& dirEntry :
165              std::filesystem::directory_iterator{dirPath})
166         {
167             if (dirEntry.is_directory() &&
168                 (compatibleName == dirEntry.path().filename()))
169             {
170                 return compatibleName;
171             }
172         }
173     }
174 
175     return std::nullopt;
176 }
177 
registerSystemTypeCallback(SystemTypeCallback callback)178 void Handler::registerSystemTypeCallback(SystemTypeCallback callback)
179 {
180     sysTypeCallback = callback;
181 }
182 
183 } // namespace platform_config
184 
185 } // namespace responder
186 
187 } // namespace pldm
188