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