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> 126 getSubtreePaths(const std::vector<std::string>& interfaces, 127 const std::string& path) 128 { 129 std::vector<std::string> paths; 130 131 auto& bus = getBus(); 132 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH, 133 MAPPER_IFACE, "GetSubTreePaths"); 134 method.append(path, 0, interfaces); 135 136 auto reply = bus.call(method); 137 reply.read(paths); 138 139 return paths; 140 } 141 142 // Get the service and object path for an interface 143 std::string getServiceUsingSubTree(const std::string& interface, 144 std::string& path) 145 { 146 using Path = std::string; 147 using Intf = std::string; 148 using Serv = std::string; 149 using Intfs = std::vector<Intf>; 150 using Objects = std::map<Path, std::map<Serv, Intfs>>; 151 Serv service; 152 Objects rspObjects; 153 154 auto& bus = getBus(); 155 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH, 156 MAPPER_IFACE, "GetSubTree"); 157 method.append(path, 0, std::vector{interface}); 158 159 auto mapperResponseMsg = bus.call(method); 160 mapperResponseMsg.read(rspObjects); 161 if (rspObjects.empty()) 162 { 163 log<level::ERR>( 164 std::format( 165 "util::getServiceUsingSubTree: Failed getSubTree({},0,{})", 166 path.c_str(), interface) 167 .c_str()); 168 } 169 else 170 { 171 path = rspObjects.begin()->first; 172 if (!rspObjects.begin()->second.empty()) 173 { 174 service = rspObjects.begin()->second.begin()->first; 175 } 176 else 177 { 178 log<level::ERR>( 179 std::format( 180 "getServiceUsingSubTree: service not found for interface {} (path={})", 181 interface, path.c_str()) 182 .c_str()); 183 } 184 } 185 186 return service; 187 } 188 189 std::string getStateValue(const std::string& intf, const std::string& objPath, 190 const std::string& state) 191 { 192 std::string stateVal; 193 try 194 { 195 auto& bus = getBus(); 196 auto service = getService(objPath, intf); 197 if (service.empty()) 198 { 199 throw std::runtime_error("getStateValue: Failed to get service"); 200 } 201 202 auto method = bus.new_method_call(service.c_str(), objPath.c_str(), 203 "org.freedesktop.DBus.Properties", 204 "Get"); 205 206 method.append(intf, state); 207 208 auto reply = bus.call(method); 209 210 std::variant<std::string> propertyVal; 211 212 reply.read(propertyVal); 213 214 stateVal = std::get<std::string>(propertyVal); 215 } 216 catch (const sdbusplus::exception_t& e) 217 { 218 log<level::ERR>(std::format("D-Bus call exception, OBJPATH({}), " 219 "INTERFACE({}), PROPERTY({}) EXCEPTION({})", 220 objPath, intf, state, e.what()) 221 .c_str()); 222 throw std::runtime_error("Failed to get host state property"); 223 } 224 catch (const std::bad_variant_access& e) 225 { 226 log<level::ERR>( 227 std::format("Exception raised while read host state({}) property " 228 "value, OBJPATH({}), INTERFACE({}), EXCEPTION({})", 229 state, objPath, intf, e.what()) 230 .c_str()); 231 throw std::runtime_error("Failed to get host state property"); 232 } 233 234 return stateVal; 235 } 236 237 BootProgress getBootProgress() 238 { 239 BootProgress bootProgessStage; 240 constexpr auto bootProgressInterface = 241 "xyz.openbmc_project.State.Boot.Progress"; 242 std::string value = getStateValue(bootProgressInterface, 243 HOST_STATE_OBJ_PATH, "BootProgress"); 244 bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server:: 245 Progress::convertProgressStagesFromString(value); 246 return bootProgessStage; 247 } 248 249 bool isHostRunning() 250 { 251 BootProgress bootProgressStatus = getBootProgress(); 252 if ((bootProgressStatus == BootProgress::SystemInitComplete) || 253 (bootProgressStatus == BootProgress::SystemSetup) || 254 (bootProgressStatus == BootProgress::OSStart) || 255 (bootProgressStatus == BootProgress::OSRunning)) 256 { 257 return true; 258 } 259 return false; 260 } 261 262 } // namespace utils 263 } // namespace occ 264 } // namespace open_power 265