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