1 #include "utils.hpp" 2 3 #include <fmt/core.h> 4 #include <systemd/sd-event.h> 5 #include <unistd.h> 6 7 #include <phosphor-logging/elog-errors.hpp> 8 #include <sdbusplus/bus.hpp> 9 #include <xyz/openbmc_project/Common/error.hpp> 10 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp> 11 #include <xyz/openbmc_project/State/Host/server.hpp> 12 13 #include <string> 14 namespace open_power 15 { 16 namespace occ 17 { 18 namespace utils 19 { 20 // For throwing exceptions 21 using namespace phosphor::logging; 22 using InternalFailure = 23 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 24 25 using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server:: 26 Progress::ProgressStages; 27 constexpr auto HOST_STATE_OBJ_PATH = "/xyz/openbmc_project/state/host0"; 28 29 const std::string getService(const std::string& path, 30 const std::string& interface) 31 { 32 33 using InterfaceList = std::vector<std::string>; 34 std::map<std::string, std::vector<std::string>> mapperResponse; 35 36 auto& bus = getBus(); 37 38 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH, 39 MAPPER_IFACE, "GetObject"); 40 mapper.append(path, InterfaceList({interface})); 41 42 auto mapperResponseMsg = bus.call(mapper); 43 mapperResponseMsg.read(mapperResponse); 44 if (mapperResponse.empty()) 45 { 46 log<level::ERR>("ERROR reading mapper response", 47 entry("PATH=%s", path.c_str()), 48 entry("INTERFACE=%s", interface.c_str())); 49 50 elog<InternalFailure>(); 51 } 52 53 // the value here will be the service name 54 return mapperResponse.cbegin()->first; 55 } 56 57 const PropertyValue getProperty(const std::string& objectPath, 58 const std::string& interface, 59 const std::string& propertyName) 60 { 61 PropertyValue value{}; 62 63 auto& bus = getBus(); 64 auto service = getService(objectPath, interface); 65 if (service.empty()) 66 { 67 return value; 68 } 69 70 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(), 71 DBUS_PROPERTY_IFACE, "Get"); 72 method.append(interface, propertyName); 73 74 auto reply = bus.call(method); 75 reply.read(value); 76 77 return value; 78 } 79 80 /** 81 * @brief Sets a given object's property value 82 * 83 * @param[in] objectPath - Name of the object containing the property 84 * @param[in] interface - Interface name containing the property 85 * @param[in] propertyName - Property name 86 * @param[in] value - Property value 87 */ 88 void setProperty(const std::string& objectPath, const std::string& interface, 89 const std::string& propertyName, PropertyValue&& value) 90 { 91 using namespace std::literals::string_literals; 92 PropertyValue varValue(std::forward<PropertyValue>(value)); 93 94 try 95 { 96 auto& bus = getBus(); 97 auto service = getService(objectPath, interface); 98 if (service.empty()) 99 { 100 return; 101 } 102 103 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(), 104 DBUS_PROPERTY_IFACE, "Set"); 105 method.append(interface, propertyName, varValue); 106 107 auto reply = bus.call(method); 108 if (reply.is_method_error()) 109 { 110 log<level::ERR>( 111 fmt::format("util::setProperty: Failed to set property {}", 112 propertyName) 113 .c_str()); 114 } 115 } 116 catch (const std::exception& e) 117 { 118 auto error = errno; 119 log<level::ERR>( 120 fmt::format("setProperty: failed to Set {}, errno={}, what={}", 121 propertyName.c_str(), error, e.what()) 122 .c_str()); 123 } 124 } 125 126 std::vector<std::string> 127 getSubtreePaths(const std::vector<std::string>& interfaces, 128 const std::string& path) 129 { 130 std::vector<std::string> paths; 131 132 auto& bus = getBus(); 133 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH, 134 MAPPER_IFACE, "GetSubTreePaths"); 135 method.append(path, 0, interfaces); 136 137 auto reply = bus.call(method); 138 reply.read(paths); 139 140 return paths; 141 } 142 143 // Get the service and object path for an interface 144 std::string getServiceUsingSubTree(const std::string& interface, 145 std::string& path) 146 { 147 using Path = std::string; 148 using Intf = std::string; 149 using Serv = std::string; 150 using Intfs = std::vector<Intf>; 151 using Objects = std::map<Path, std::map<Serv, Intfs>>; 152 Serv service; 153 Objects rspObjects; 154 155 auto& bus = getBus(); 156 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH, 157 MAPPER_IFACE, "GetSubTree"); 158 method.append(path, 0, std::vector{interface}); 159 160 auto mapperResponseMsg = bus.call(method); 161 mapperResponseMsg.read(rspObjects); 162 if (rspObjects.empty()) 163 { 164 log<level::ERR>( 165 fmt::format( 166 "util::getServiceUsingSubTree: Failed getSubTree({},0,{})", 167 path.c_str(), interface) 168 .c_str()); 169 } 170 else 171 { 172 path = rspObjects.begin()->first; 173 if (!rspObjects.begin()->second.empty()) 174 { 175 service = rspObjects.begin()->second.begin()->first; 176 } 177 else 178 { 179 log<level::ERR>( 180 fmt::format( 181 "getServiceUsingSubTree: service not found for interface {} (path={})", 182 interface, path.c_str()) 183 .c_str()); 184 } 185 } 186 187 return service; 188 } 189 190 std::string getStateValue(const std::string& intf, const std::string& objPath, 191 const std::string& state) 192 { 193 std::string stateVal; 194 try 195 { 196 auto& bus = getBus(); 197 auto service = getService(objPath, intf); 198 if (service.empty()) 199 { 200 throw std::runtime_error("getStateValue: Failed to get service"); 201 } 202 203 auto method = 204 bus.new_method_call(service.c_str(), objPath.c_str(), 205 "org.freedesktop.DBus.Properties", "Get"); 206 207 method.append(intf, state); 208 209 auto reply = bus.call(method); 210 211 std::variant<std::string> propertyVal; 212 213 reply.read(propertyVal); 214 215 stateVal = std::get<std::string>(propertyVal); 216 } 217 catch (const sdbusplus::exception_t& e) 218 { 219 log<level::ERR>(fmt::format("D-Bus call exception, OBJPATH({}), " 220 "INTERFACE({}), PROPERTY({}) EXCEPTION({})", 221 objPath, intf, state, e.what()) 222 .c_str()); 223 throw std::runtime_error("Failed to get host state property"); 224 } 225 catch (const std::bad_variant_access& e) 226 { 227 log<level::ERR>( 228 fmt::format("Exception raised while read host state({}) property " 229 "value, OBJPATH({}), INTERFACE({}), EXCEPTION({})", 230 state, objPath, intf, e.what()) 231 .c_str()); 232 throw std::runtime_error("Failed to get host state property"); 233 } 234 235 return stateVal; 236 } 237 238 BootProgress getBootProgress() 239 { 240 BootProgress bootProgessStage; 241 constexpr auto bootProgressInterface = 242 "xyz.openbmc_project.State.Boot.Progress"; 243 std::string value = getStateValue(bootProgressInterface, 244 HOST_STATE_OBJ_PATH, "BootProgress"); 245 bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server:: 246 Progress::convertProgressStagesFromString(value); 247 return bootProgessStage; 248 } 249 250 bool isHostRunning() 251 { 252 BootProgress bootProgressStatus = getBootProgress(); 253 if ((bootProgressStatus == BootProgress::SystemInitComplete) || 254 (bootProgressStatus == BootProgress::SystemSetup) || 255 (bootProgressStatus == BootProgress::OSStart) || 256 (bootProgressStatus == BootProgress::OSRunning)) 257 { 258 return true; 259 } 260 return false; 261 } 262 263 } // namespace utils 264 } // namespace occ 265 } // namespace open_power 266