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