1 /* 2 // Copyright (c) 2017 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #include "filesystem.hpp" 18 19 #include <Utils.hpp> 20 #include <boost/algorithm/string/predicate.hpp> 21 #include <fstream> 22 #include <regex> 23 #include <sdbusplus/asio/connection.hpp> 24 #include <sdbusplus/asio/object_server.hpp> 25 #include <sdbusplus/bus/match.hpp> 26 27 namespace fs = std::filesystem; 28 const static constexpr char* powerInterfaceName = 29 "xyz.openbmc_project.Chassis.Control.Power"; 30 const static constexpr char* powerObjectName = 31 "/xyz/openbmc_project/Chassis/Control/Power0"; 32 33 static bool powerStatusOn = false; 34 static bool biosHasPost = false; 35 static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr; 36 37 bool getSensorConfiguration( 38 const std::string& type, 39 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 40 ManagedObjectType& resp, bool useCache) 41 { 42 static ManagedObjectType managedObj; 43 44 if (!useCache) 45 { 46 managedObj.clear(); 47 sdbusplus::message::message getManagedObjects = 48 dbusConnection->new_method_call( 49 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager", 50 "GetManagedObjects"); 51 bool err = false; 52 try 53 { 54 sdbusplus::message::message reply = 55 dbusConnection->call(getManagedObjects); 56 reply.read(managedObj); 57 } 58 catch (const sdbusplus::exception::exception&) 59 { 60 err = true; 61 } 62 63 if (err) 64 { 65 std::cerr << "Error communicating to entity manager\n"; 66 return false; 67 } 68 } 69 for (const auto& pathPair : managedObj) 70 { 71 std::vector<boost::container::flat_map<std::string, BasicVariantType>> 72 sensorData; 73 bool correctType = false; 74 for (const auto& entry : pathPair.second) 75 { 76 if (boost::starts_with(entry.first, type)) 77 { 78 correctType = true; 79 break; 80 } 81 } 82 if (correctType) 83 { 84 resp.emplace(pathPair); 85 } 86 } 87 return true; 88 } 89 90 bool findFiles(const fs::path dirPath, const std::string& matchString, 91 std::vector<fs::path>& foundPaths, unsigned int symlinkDepth) 92 { 93 if (!fs::exists(dirPath)) 94 return false; 95 96 std::regex search(matchString); 97 std::smatch match; 98 for (auto& p : fs::recursive_directory_iterator(dirPath)) 99 { 100 std::string path = p.path().string(); 101 if (!is_directory(p)) 102 { 103 if (std::regex_search(path, match, search)) 104 foundPaths.emplace_back(p.path()); 105 } 106 else if (is_symlink(p) && symlinkDepth) 107 { 108 findFiles(p.path(), matchString, foundPaths, symlinkDepth - 1); 109 } 110 } 111 return true; 112 } 113 114 bool isPowerOn(void) 115 { 116 if (!powerMatch) 117 { 118 throw std::runtime_error("Power Match Not Created"); 119 } 120 return powerStatusOn; 121 } 122 123 bool hasBiosPost(void) 124 { 125 if (!powerMatch) 126 { 127 throw std::runtime_error("Power Match Not Created"); 128 } 129 return biosHasPost; 130 } 131 132 void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn) 133 { 134 // create a match for powergood changes, first time do a method call to 135 // cache the correct value 136 std::function<void(sdbusplus::message::message & message)> eventHandler = 137 [](sdbusplus::message::message& message) { 138 std::string objectName; 139 boost::container::flat_map<std::string, std::variant<int32_t, bool>> 140 values; 141 message.read(objectName, values); 142 auto findPgood = values.find("pgood"); 143 if (findPgood != values.end()) 144 { 145 powerStatusOn = std::get<int32_t>(findPgood->second); 146 } 147 auto findPostComplete = values.find("post_complete"); 148 if (findPostComplete != values.end()) 149 { 150 biosHasPost = std::get<bool>(findPostComplete->second); 151 } 152 }; 153 154 powerMatch = std::make_unique<sdbusplus::bus::match::match>( 155 static_cast<sdbusplus::bus::bus&>(*conn), 156 "type='signal',interface='org.freedesktop.DBus.Properties',path_" 157 "namespace='/xyz/openbmc_project/Chassis/Control/" 158 "Power0',arg0='xyz.openbmc_project.Chassis.Control.Power'", 159 eventHandler); 160 161 conn->async_method_call( 162 [](boost::system::error_code ec, const std::variant<int32_t>& pgood) { 163 if (ec) 164 { 165 // we commonly come up before power control, we'll capture the 166 // property change later 167 return; 168 } 169 powerStatusOn = std::get<int32_t>(pgood); 170 }, 171 powerInterfaceName, powerObjectName, "org.freedesktop.DBus.Properties", 172 "Get", powerInterfaceName, "pgood"); 173 174 conn->async_method_call( 175 [](boost::system::error_code ec, 176 const std::variant<int32_t>& postComplete) { 177 if (ec) 178 { 179 // we commonly come up before power control, we'll capture the 180 // property change later 181 return; 182 } 183 biosHasPost = std::get<int32_t>(postComplete); 184 }, 185 powerInterfaceName, powerObjectName, "org.freedesktop.DBus.Properties", 186 "Get", powerInterfaceName, "post_complete"); 187 } 188 189 // replaces limits if MinReading and MaxReading are found. 190 void findLimits(std::pair<double, double>& limits, 191 const SensorBaseConfiguration* data) 192 { 193 if (!data) 194 { 195 return; 196 } 197 auto maxFind = data->second.find("MaxReading"); 198 auto minFind = data->second.find("MinReading"); 199 200 if (minFind != data->second.end()) 201 { 202 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second); 203 } 204 if (maxFind != data->second.end()) 205 { 206 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second); 207 } 208 } 209 210 void createAssociation( 211 std::shared_ptr<sdbusplus::asio::dbus_interface>& association, 212 const std::string& path) 213 { 214 if (association) 215 { 216 std::filesystem::path p(path); 217 218 using Association = std::tuple<std::string, std::string, std::string>; 219 std::vector<Association> associations; 220 associations.push_back( 221 Association("inventory", "sensors", p.parent_path().string())); 222 association->register_property("associations", associations); 223 association->initialize(); 224 } 225 }