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