1 /**
2  * Copyright © 2024 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "compatible_system_types_finder.hpp"
18 
19 #include <phosphor-logging/lg2.hpp>
20 
21 #include <algorithm>
22 #include <exception>
23 #include <format>
24 #include <ranges>
25 #include <regex>
26 #include <stdexcept>
27 #include <utility>
28 #include <variant>
29 
30 namespace phosphor::power::util
31 {
32 
33 const std::string compatibleInterfaceService =
34     "xyz.openbmc_project.EntityManager";
35 
36 const std::string compatibleInterface =
37     "xyz.openbmc_project.Inventory.Decorator.Compatible";
38 
39 const std::string namesProperty = "Names";
40 
CompatibleSystemTypesFinder(sdbusplus::bus_t & bus,Callback callback)41 CompatibleSystemTypesFinder::CompatibleSystemTypesFinder(sdbusplus::bus_t& bus,
42                                                          Callback callback) :
43     callback{std::move(callback)}
44 {
45     interfaceFinder = std::make_unique<DBusInterfacesFinder>(
46         bus, compatibleInterfaceService,
47         std::vector<std::string>{compatibleInterface},
48         std::bind_front(&CompatibleSystemTypesFinder::interfaceFoundCallback,
49                         this));
50 }
51 
interfaceFoundCallback(const std::string & path,const std::string & interface,const DbusPropertyMap & properties)52 void CompatibleSystemTypesFinder::interfaceFoundCallback(
53     [[maybe_unused]] const std::string& path,
54     [[maybe_unused]] const std::string& interface,
55     const DbusPropertyMap& properties)
56 {
57     try
58     {
59         // Get the property containing the list of compatible names
60         auto it = properties.find(namesProperty);
61         if (it == properties.end())
62         {
63             throw std::runtime_error{
64                 std::format("{} property not found", namesProperty)};
65         }
66         auto names = std::get<std::vector<std::string>>(it->second);
67         if (!names.empty())
68         {
69             // If all the compatible names are system or chassis types
70             std::regex pattern{"\\.(system|chassis)\\.", std::regex::icase};
71             if (std::ranges::all_of(names, [&pattern](auto&& name) {
72                     return std::regex_search(name, pattern);
73                 }))
74             {
75                 // Call callback with compatible system type names
76                 callback(names);
77             }
78         }
79     }
80     catch (const std::exception& e)
81     {
82         lg2::error(
83             "Unable to obtain properties of Compatible interface: {ERROR}",
84             "ERROR", e);
85     }
86 }
87 
88 } // namespace phosphor::power::util
89