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