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