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::bus& bus,
20                  const std::vector<Interface>& filter) :
21     bus(bus)
22 {
23     auto depth = 0;
24 
25     auto mapperCall = bus.new_method_call(mapperService, mapperPath, 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 =
70         bus.new_method_call(mapperService, mapperPath, mapperIntf, "GetObject");
71     mapperCall.append(path);
72     mapperCall.append(Interfaces({interface}));
73 
74     auto response = bus.call(mapperCall);
75     if (response.is_method_error())
76     {
77         log<level::ERR>("Error in mapper GetObject");
78         elog<InternalFailure>();
79     }
80 
81     std::map<Service, Interfaces> result;
82     response.read(result);
83     if (result.empty())
84     {
85         log<level::ERR>("Invalid response from mapper");
86         elog<InternalFailure>();
87     }
88 
89     return result.begin()->first;
90 }
91 
92 namespace boot
93 {
94 
95 std::tuple<Path, OneTimeEnabled> setting(const Objects& objects,
96                                          const Interface& iface)
97 {
98     constexpr auto bootObjCount = 2;
99     constexpr auto oneTime = "one_time";
100     constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
101 
102     const std::vector<Path>& paths = objects.map.at(iface);
103     auto count = paths.size();
104     if (count != bootObjCount)
105     {
106         log<level::ERR>("Exactly two objects expected",
107                         entry("INTERFACE=%s", iface.c_str()),
108                         entry("COUNT=%d", count));
109         elog<InternalFailure>();
110     }
111     size_t index = 0;
112     if (std::string::npos == paths[0].rfind(oneTime))
113     {
114         index = 1;
115     }
116     const Path& oneTimeSetting = paths[index];
117     const Path& regularSetting = paths[!index];
118 
119     auto method = objects.bus.new_method_call(
120         objects.service(oneTimeSetting, iface).c_str(), oneTimeSetting.c_str(),
121         ipmi::PROP_INTF, "Get");
122     method.append(enabledIntf, "Enabled");
123     auto reply = objects.bus.call(method);
124     if (reply.is_method_error())
125     {
126         log<level::ERR>("Error in getting Enabled property",
127                         entry("OBJECT=%s", oneTimeSetting.c_str()),
128                         entry("INTERFACE=%s", iface.c_str()));
129         elog<InternalFailure>();
130     }
131 
132     std::variant<bool> enabled;
133     reply.read(enabled);
134     auto oneTimeEnabled = std::get<bool>(enabled);
135     const Path& setting = oneTimeEnabled ? oneTimeSetting : regularSetting;
136     return std::make_tuple(setting, oneTimeEnabled);
137 }
138 
139 } // namespace boot
140 
141 } // namespace settings
142