1 #include "config.h"
2 
3 #include "utils.hpp"
4 
5 #include <fmt/format.h>
6 #include <fmt/printf.h>
7 #include <gpiod.h>
8 
9 #include <phosphor-logging/lg2.hpp>
10 
11 #include <filesystem>
12 
13 namespace phosphor
14 {
15 namespace state
16 {
17 namespace manager
18 {
19 namespace utils
20 {
21 
22 PHOSPHOR_LOG2_USING;
23 
24 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
25 constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
26 constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
27 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
28 
29 std::string getService(sdbusplus::bus_t& bus, std::string path,
30                        std::string interface)
31 {
32     auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
33                                       MAPPER_INTERFACE, "GetObject");
34 
35     mapper.append(path, std::vector<std::string>({interface}));
36 
37     std::vector<std::pair<std::string, std::vector<std::string>>>
38         mapperResponse;
39 
40     try
41     {
42         auto mapperResponseMsg = bus.call(mapper);
43 
44         mapperResponseMsg.read(mapperResponse);
45         if (mapperResponse.empty())
46         {
47             error(
48                 "Error no matching service with path {PATH} and interface {INTERFACE}",
49                 "PATH", path, "INTERFACE", interface);
50             throw std::runtime_error("Error no matching service");
51         }
52     }
53     catch (const sdbusplus::exception_t& e)
54     {
55         error("Error in mapper call with path {PATH}, interface "
56               "{INTERFACE}, and exception {ERROR}",
57               "PATH", path, "INTERFACE", interface, "ERROR", e);
58         throw;
59     }
60 
61     return mapperResponse.begin()->first;
62 }
63 
64 std::string getProperty(sdbusplus::bus_t& bus, const std::string& path,
65                         const std::string& interface,
66                         const std::string& propertyName)
67 {
68     std::variant<std::string> property;
69     std::string service = getService(bus, path, interface);
70 
71     auto method = bus.new_method_call(service.c_str(), path.c_str(),
72                                       PROPERTY_INTERFACE, "Get");
73 
74     method.append(interface, propertyName);
75 
76     try
77     {
78         auto reply = bus.call(method);
79         reply.read(property);
80     }
81     catch (const sdbusplus::exception_t& e)
82     {
83         error("Error in property Get, error {ERROR}, property {PROPERTY}",
84               "ERROR", e, "PROPERTY", propertyName);
85         throw;
86     }
87 
88     if (std::get<std::string>(property).empty())
89     {
90         error("Error reading property response for {PROPERTY}", "PROPERTY",
91               propertyName);
92         throw std::runtime_error("Error reading property response");
93     }
94 
95     return std::get<std::string>(property);
96 }
97 
98 void setProperty(sdbusplus::bus_t& bus, const std::string& path,
99                  const std::string& interface, const std::string& property,
100                  const std::string& value)
101 {
102     std::variant<std::string> variantValue = value;
103     std::string service = getService(bus, path, interface);
104 
105     auto method = bus.new_method_call(service.c_str(), path.c_str(),
106                                       PROPERTY_INTERFACE, "Set");
107 
108     method.append(interface, property, variantValue);
109     bus.call_noreply(method);
110 
111     return;
112 }
113 
114 int getGpioValue(const std::string& gpioName)
115 {
116     int gpioval = -1;
117     gpiod_line* line = gpiod_line_find(gpioName.c_str());
118 
119     if (nullptr != line)
120     {
121         // take ownership of gpio
122         if (0 != gpiod_line_request_input(line, "state-manager"))
123         {
124             error("Failed request for {GPIO_NAME} GPIO", "GPIO_NAME", gpioName);
125         }
126         else
127         {
128             // get gpio value
129             gpioval = gpiod_line_get_value(line);
130 
131             // release ownership of gpio
132             gpiod_line_close_chip(line);
133         }
134     }
135     return gpioval;
136 }
137 
138 void createError(
139     sdbusplus::bus_t& bus, const std::string& errorMsg,
140     sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level errLevel,
141     std::map<std::string, std::string> additionalData)
142 {
143     try
144     {
145         // Always add the _PID on for some extra logging debug
146         additionalData.emplace("_PID", std::to_string(getpid()));
147 
148         auto method = bus.new_method_call(
149             "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
150             "xyz.openbmc_project.Logging.Create", "Create");
151 
152         method.append(errorMsg, errLevel, additionalData);
153         auto resp = bus.call(method);
154     }
155     catch (const sdbusplus::exception_t& e)
156     {
157         error("sdbusplus D-Bus call exception, error {ERROR} trying to create "
158               "an error with {ERROR_MSG}",
159               "ERROR", e, "ERROR_MSG", errorMsg);
160 
161         throw std::runtime_error(
162             "Error in invoking D-Bus logging create interface");
163     }
164     catch (const std::exception& e)
165     {
166         error("D-bus call exception: {ERROR}", "ERROR", e);
167         throw e;
168     }
169 }
170 
171 void createBmcDump(sdbusplus::bus_t& bus)
172 {
173     auto method = bus.new_method_call(
174         "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump/bmc",
175         "xyz.openbmc_project.Dump.Create", "CreateDump");
176     method.append(
177         std::vector<
178             std::pair<std::string, std::variant<std::string, uint64_t>>>());
179     try
180     {
181         bus.call_noreply(method);
182     }
183     catch (const sdbusplus::exception_t& e)
184     {
185         error("Failed to create BMC dump, exception:{ERROR}", "ERROR", e);
186         // just continue, this is error path anyway so we're just collecting
187         // what we can
188     }
189 }
190 
191 bool checkACLoss(size_t& chassisId)
192 {
193     std::string chassisLostPowerFileFmt =
194         fmt::sprintf(CHASSIS_LOST_POWER_FILE, chassisId);
195 
196     std::filesystem::path chassisPowerLossFile{chassisLostPowerFileFmt};
197     if (std::filesystem::exists(chassisPowerLossFile))
198     {
199         return true;
200     }
201 
202     return false;
203 }
204 
205 } // namespace utils
206 } // namespace manager
207 } // namespace state
208 } // namespace phosphor
209