1 #include <phosphor-logging/elog-errors.hpp>
2 #include <phosphor-logging/log.hpp>
3 #include "xyz/openbmc_project/Common/error.hpp"
4 #include "settings.hpp"
5 #include "utils.hpp"
6 
7 namespace settings
8 {
9 
10 using namespace phosphor::logging;
11 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
12 
13 constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
14 constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper";
15 constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
16 
17 Objects::Objects(sdbusplus::bus::bus& bus,
18                  const std::vector<Interface>& filter):
19     bus(bus)
20 {
21     auto depth = 0;
22 
23     auto mapperCall = bus.new_method_call(mapperService,
24                                           mapperPath,
25                                           mapperIntf,
26                                           "GetSubTree");
27     mapperCall.append(root);
28     mapperCall.append(depth);
29     mapperCall.append(filter);
30     auto response = bus.call(mapperCall);
31     if (response.is_method_error())
32     {
33         log<level::ERR>("Error in mapper GetSubTree");
34         elog<InternalFailure>();
35     }
36 
37     using Interfaces = std::vector<Interface>;
38     using MapperResponse = std::map<Path, std::map<Service, Interfaces>>;
39     MapperResponse result;
40     response.read(result);
41     if (result.empty())
42     {
43         log<level::ERR>("Invalid response from mapper");
44         elog<InternalFailure>();
45     }
46 
47     for (auto& iter : result)
48     {
49         const auto& path = iter.first;
50         for (auto& interface : iter.second.begin()->second)
51         {
52             auto found = map.find(interface);
53             if (map.end() != found)
54             {
55                 auto& paths = found->second;
56                 paths.push_back(path);
57             }
58             else
59             {
60                 map.emplace(std::move(interface), std::vector<Path>({path}));
61             }
62         }
63     }
64 }
65 
66 Service Objects::service(const Path& path, const Interface& interface) const
67 {
68     using Interfaces = std::vector<Interface>;
69     auto mapperCall = bus.new_method_call(mapperService,
70                                           mapperPath,
71                                           mapperIntf,
72                                           "GetObject");
73     mapperCall.append(path);
74     mapperCall.append(Interfaces({interface}));
75 
76     auto response = bus.call(mapperCall);
77     if (response.is_method_error())
78     {
79         log<level::ERR>("Error in mapper GetObject");
80         elog<InternalFailure>();
81     }
82 
83     std::map<Service, Interfaces> result;
84     response.read(result);
85     if (result.empty())
86     {
87         log<level::ERR>("Invalid response from mapper");
88         elog<InternalFailure>();
89     }
90 
91     return result.begin()->first;
92 }
93 
94 namespace boot
95 {
96 
97 std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
98                                          const Interface& iface)
99 {
100     constexpr auto bootObjCount = 2;
101     constexpr auto oneTime = "one_time";
102     constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
103 
104     const std::vector<Path>& paths = objects.map.at(iface);
105     auto count = paths.size();
106     if (count != bootObjCount)
107     {
108         log<level::ERR>("Exactly two objects expected",
109                         entry("INTERFACE=%s", iface.c_str()),
110                         entry("COUNT=%d", count));
111         elog<InternalFailure>();
112     }
113     size_t index = 0;
114     if (std::string::npos == paths[0].rfind(oneTime))
115     {
116         index = 1;
117     }
118     const Path& oneTimeSetting = paths[index];
119     const Path& regularSetting = paths[!index];
120 
121     auto method =
122         objects.bus.new_method_call(
123             objects.service(oneTimeSetting, iface).c_str(),
124             oneTimeSetting.c_str(),
125             ipmi::PROP_INTF,
126             "Get");
127     method.append(enabledIntf, "Enabled");
128     auto reply = objects.bus.call(method);
129     if (reply.is_method_error())
130     {
131         log<level::ERR>("Error in getting Enabled property",
132                         entry("OBJECT=%s", oneTimeSetting.c_str()),
133                         entry("INTERFACE=%s", iface.c_str()));
134         elog<InternalFailure>();
135     }
136 
137     sdbusplus::message::variant<bool> enabled;
138     reply.read(enabled);
139     auto oneTimeEnabled = enabled.get<bool>();
140     const Path& setting = oneTimeEnabled ? oneTimeSetting : regularSetting;
141     return std::make_tuple(setting, oneTimeEnabled);
142 }
143 
144 } // namespace boot
145 
146 } // namespace settings
147