16714a25aSJames Feist /* 26714a25aSJames Feist // Copyright (c) 2017 Intel Corporation 36714a25aSJames Feist // 46714a25aSJames Feist // Licensed under the Apache License, Version 2.0 (the "License"); 56714a25aSJames Feist // you may not use this file except in compliance with the License. 66714a25aSJames Feist // You may obtain a copy of the License at 76714a25aSJames Feist // 86714a25aSJames Feist // http://www.apache.org/licenses/LICENSE-2.0 96714a25aSJames Feist // 106714a25aSJames Feist // Unless required by applicable law or agreed to in writing, software 116714a25aSJames Feist // distributed under the License is distributed on an "AS IS" BASIS, 126714a25aSJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136714a25aSJames Feist // See the License for the specific language governing permissions and 146714a25aSJames Feist // limitations under the License. 156714a25aSJames Feist */ 166714a25aSJames Feist 171263c3daSBruce Lee #include "dbus-sensor_config.h" 181263c3daSBruce Lee 198a57ec09SEd Tanous #include <Utils.hpp> 206714a25aSJames Feist #include <boost/algorithm/string/predicate.hpp> 2196e97db7SPatrick Venture #include <boost/container/flat_map.hpp> 2238fb5983SJames Feist #include <sdbusplus/asio/connection.hpp> 2338fb5983SJames Feist #include <sdbusplus/asio/object_server.hpp> 2438fb5983SJames Feist #include <sdbusplus/bus/match.hpp> 2538fb5983SJames Feist 2624f02f24SJames Feist #include <filesystem> 276714a25aSJames Feist #include <fstream> 2896e97db7SPatrick Venture #include <memory> 296714a25aSJames Feist #include <regex> 3096e97db7SPatrick Venture #include <stdexcept> 3196e97db7SPatrick Venture #include <string> 3296e97db7SPatrick Venture #include <utility> 3396e97db7SPatrick Venture #include <variant> 3496e97db7SPatrick Venture #include <vector> 356714a25aSJames Feist 36cf3bce6eSJames Feist namespace fs = std::filesystem; 376714a25aSJames Feist 386ef20407SJames Feist static bool powerStatusOn = false; 39fc94b215SJames Feist static bool biosHasPost = false; 401263c3daSBruce Lee static bool manufacturingMode = false; 4158295adaSJames Feist 426ef20407SJames Feist static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr; 4352497fd0SJames Feist static std::unique_ptr<sdbusplus::bus::match::match> postMatch = nullptr; 4471d31b2eSJames Feist 45100c20bfSJason Ling /** 46100c20bfSJason Ling * return the contents of a file 47100c20bfSJason Ling * @param[in] hwmonFile - the path to the file to read 48100c20bfSJason Ling * @return the contents of the file as a string or nullopt if the file could not 49100c20bfSJason Ling * be opened. 50100c20bfSJason Ling */ 51100c20bfSJason Ling 52100c20bfSJason Ling std::optional<std::string> openAndRead(const std::string& hwmonFile) 53100c20bfSJason Ling { 54100c20bfSJason Ling std::string fileVal; 55100c20bfSJason Ling std::ifstream fileStream(hwmonFile); 56100c20bfSJason Ling if (!fileStream.is_open()) 57100c20bfSJason Ling { 58100c20bfSJason Ling return std::nullopt; 59100c20bfSJason Ling } 60100c20bfSJason Ling std::getline(fileStream, fileVal); 61100c20bfSJason Ling return fileVal; 62100c20bfSJason Ling } 63100c20bfSJason Ling 64100c20bfSJason Ling /** 65100c20bfSJason Ling * given a hwmon temperature base name if valid return the full path else 66100c20bfSJason Ling * nullopt 67100c20bfSJason Ling * @param[in] directory - the hwmon sysfs directory 68100c20bfSJason Ling * @param[in] permitSet - a set of labels or hwmon basenames to permit. If this 69100c20bfSJason Ling * is empty then *everything* is permitted. 70100c20bfSJason Ling * @return a string to the full path of the file to create a temp sensor with or 71100c20bfSJason Ling * nullopt to indicate that no sensor should be created for this basename. 72100c20bfSJason Ling */ 73100c20bfSJason Ling std::optional<std::string> 74100c20bfSJason Ling getFullHwmonFilePath(const std::string& directory, 75100c20bfSJason Ling const std::string& hwmonBaseName, 76100c20bfSJason Ling const std::set<std::string>& permitSet) 77100c20bfSJason Ling { 78100c20bfSJason Ling std::optional<std::string> result; 79100c20bfSJason Ling std::string filename; 80100c20bfSJason Ling if (permitSet.empty()) 81100c20bfSJason Ling { 82100c20bfSJason Ling result = directory + "/" + hwmonBaseName + "_input"; 83100c20bfSJason Ling return result; 84100c20bfSJason Ling } 85100c20bfSJason Ling filename = directory + "/" + hwmonBaseName + "_label"; 86100c20bfSJason Ling auto searchVal = openAndRead(filename); 87100c20bfSJason Ling if (!searchVal) 88100c20bfSJason Ling { 89100c20bfSJason Ling /* if the hwmon temp doesn't have a corresponding label file 90100c20bfSJason Ling * then use the hwmon temperature base name 91100c20bfSJason Ling */ 92100c20bfSJason Ling searchVal = hwmonBaseName; 93100c20bfSJason Ling } 94100c20bfSJason Ling if (permitSet.find(*searchVal) != permitSet.end()) 95100c20bfSJason Ling { 96100c20bfSJason Ling result = directory + "/" + hwmonBaseName + "_input"; 97100c20bfSJason Ling } 98100c20bfSJason Ling return result; 99100c20bfSJason Ling } 100100c20bfSJason Ling 101100c20bfSJason Ling /** 102100c20bfSJason Ling * retrieve a set of basenames and labels to allow sensor creation for. 103100c20bfSJason Ling * @param[in] config - a map representing the configuration for a specific 104100c20bfSJason Ling * device 105100c20bfSJason Ling * @return a set of basenames and labels to allow sensor creation for. An empty 106100c20bfSJason Ling * set indicates that everything is permitted. 107100c20bfSJason Ling */ 108100c20bfSJason Ling std::set<std::string> getPermitSet(const SensorBaseConfigMap& config) 109100c20bfSJason Ling { 110100c20bfSJason Ling auto permitAttribute = config.find("Labels"); 111100c20bfSJason Ling std::set<std::string> permitSet; 112100c20bfSJason Ling if (permitAttribute != config.end()) 113100c20bfSJason Ling { 114100c20bfSJason Ling try 115100c20bfSJason Ling { 116100c20bfSJason Ling auto val = 117100c20bfSJason Ling std::get<std::vector<std::string>>(permitAttribute->second); 118100c20bfSJason Ling 119100c20bfSJason Ling permitSet.insert(std::make_move_iterator(val.begin()), 120100c20bfSJason Ling std::make_move_iterator(val.end())); 121100c20bfSJason Ling } 122100c20bfSJason Ling catch (const std::bad_variant_access& err) 123100c20bfSJason Ling { 124100c20bfSJason Ling std::cerr << err.what() 125100c20bfSJason Ling << ":PermitList does not contain a list, wrong " 126100c20bfSJason Ling "variant type.\n"; 127100c20bfSJason Ling } 128100c20bfSJason Ling } 129100c20bfSJason Ling return permitSet; 130100c20bfSJason Ling } 131100c20bfSJason Ling 1326714a25aSJames Feist bool getSensorConfiguration( 1336714a25aSJames Feist const std::string& type, 1346714a25aSJames Feist const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 1358a57ec09SEd Tanous ManagedObjectType& resp) 1368a57ec09SEd Tanous { 1378a57ec09SEd Tanous return getSensorConfiguration(type, dbusConnection, resp, false); 1388a57ec09SEd Tanous } 1398a57ec09SEd Tanous 1408a57ec09SEd Tanous bool getSensorConfiguration( 1418a57ec09SEd Tanous const std::string& type, 1428a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 1436714a25aSJames Feist ManagedObjectType& resp, bool useCache) 1446714a25aSJames Feist { 1456714a25aSJames Feist static ManagedObjectType managedObj; 1466714a25aSJames Feist 1476714a25aSJames Feist if (!useCache) 1486714a25aSJames Feist { 1496714a25aSJames Feist managedObj.clear(); 1506714a25aSJames Feist sdbusplus::message::message getManagedObjects = 1516714a25aSJames Feist dbusConnection->new_method_call( 1529ced0a38SJae Hyun Yoo entityManagerName, "/", "org.freedesktop.DBus.ObjectManager", 1536714a25aSJames Feist "GetManagedObjects"); 1546714a25aSJames Feist bool err = false; 1556714a25aSJames Feist try 1566714a25aSJames Feist { 1576714a25aSJames Feist sdbusplus::message::message reply = 1586714a25aSJames Feist dbusConnection->call(getManagedObjects); 1596714a25aSJames Feist reply.read(managedObj); 1606714a25aSJames Feist } 1615747fab1SJason Ling catch (const sdbusplus::exception::exception& e) 1626714a25aSJames Feist { 1635747fab1SJason Ling std::cerr << "While calling GetManagedObjects on service:" 1645747fab1SJason Ling << entityManagerName << " exception name:" << e.name() 1655747fab1SJason Ling << "and description:" << e.description() 1665747fab1SJason Ling << " was thrown\n"; 1676714a25aSJames Feist err = true; 1686714a25aSJames Feist } 1696714a25aSJames Feist 1706714a25aSJames Feist if (err) 1716714a25aSJames Feist { 1726714a25aSJames Feist std::cerr << "Error communicating to entity manager\n"; 1736714a25aSJames Feist return false; 1746714a25aSJames Feist } 1756714a25aSJames Feist } 1766714a25aSJames Feist for (const auto& pathPair : managedObj) 1776714a25aSJames Feist { 1786714a25aSJames Feist bool correctType = false; 1796714a25aSJames Feist for (const auto& entry : pathPair.second) 1806714a25aSJames Feist { 1816714a25aSJames Feist if (boost::starts_with(entry.first, type)) 1826714a25aSJames Feist { 1836714a25aSJames Feist correctType = true; 1846714a25aSJames Feist break; 1856714a25aSJames Feist } 1866714a25aSJames Feist } 1876714a25aSJames Feist if (correctType) 1886714a25aSJames Feist { 1896714a25aSJames Feist resp.emplace(pathPair); 1906714a25aSJames Feist } 1916714a25aSJames Feist } 1926714a25aSJames Feist return true; 1936714a25aSJames Feist } 1946714a25aSJames Feist 1956a4e9738SLei YU bool findFiles(const fs::path& dirPath, std::string_view matchString, 1968a57ec09SEd Tanous std::vector<fs::path>& foundPaths, int symlinkDepth) 1976714a25aSJames Feist { 1986a4e9738SLei YU std::error_code ec; 1996a4e9738SLei YU if (!fs::exists(dirPath, ec)) 2008a57ec09SEd Tanous { 2016714a25aSJames Feist return false; 2028a57ec09SEd Tanous } 2036714a25aSJames Feist 2046a4e9738SLei YU std::vector<std::regex> matchPieces; 2056a4e9738SLei YU 2066a4e9738SLei YU size_t pos = 0; 2076a4e9738SLei YU std::string token; 2086a4e9738SLei YU // Generate the regex expressions list from the match we were given 2096a4e9738SLei YU while ((pos = matchString.find('/')) != std::string::npos) 2106a4e9738SLei YU { 2116a4e9738SLei YU token = matchString.substr(0, pos); 2126a4e9738SLei YU matchPieces.emplace_back(token); 2136a4e9738SLei YU matchString.remove_prefix(pos + 1); 2146a4e9738SLei YU } 2156a4e9738SLei YU matchPieces.emplace_back(std::string{matchString}); 2166a4e9738SLei YU 2176a4e9738SLei YU // Check if the match string contains directories, and skip the match of 2186a4e9738SLei YU // subdirectory if not 2196a4e9738SLei YU if (matchPieces.size() <= 1) 2206a4e9738SLei YU { 2216a4e9738SLei YU std::regex search(std::string{matchString}); 2226714a25aSJames Feist std::smatch match; 2238a57ec09SEd Tanous for (auto p = fs::recursive_directory_iterator( 2248a57ec09SEd Tanous dirPath, fs::directory_options::follow_directory_symlink); 2258a57ec09SEd Tanous p != fs::recursive_directory_iterator(); ++p) 2266714a25aSJames Feist { 2278a57ec09SEd Tanous std::string path = p->path().string(); 2288a57ec09SEd Tanous if (!is_directory(*p)) 2296714a25aSJames Feist { 2306714a25aSJames Feist if (std::regex_search(path, match, search)) 2316714a25aSJames Feist { 2328a57ec09SEd Tanous foundPaths.emplace_back(p->path()); 2338a57ec09SEd Tanous } 2348a57ec09SEd Tanous } 2358a57ec09SEd Tanous if (p.depth() >= symlinkDepth) 2368a57ec09SEd Tanous { 2378a57ec09SEd Tanous p.disable_recursion_pending(); 2386714a25aSJames Feist } 2396714a25aSJames Feist } 2406714a25aSJames Feist return true; 2416714a25aSJames Feist } 2426714a25aSJames Feist 2436a4e9738SLei YU // The match string contains directories, verify each level of sub 2446a4e9738SLei YU // directories 2456a4e9738SLei YU for (auto p = fs::recursive_directory_iterator( 2466a4e9738SLei YU dirPath, fs::directory_options::follow_directory_symlink); 2476a4e9738SLei YU p != fs::recursive_directory_iterator(); ++p) 2486a4e9738SLei YU { 2496a4e9738SLei YU std::vector<std::regex>::iterator matchPiece = matchPieces.begin(); 2506a4e9738SLei YU fs::path::iterator pathIt = p->path().begin(); 2516a4e9738SLei YU for (const fs::path& dir : dirPath) 2526a4e9738SLei YU { 2536a4e9738SLei YU if (dir.empty()) 2546a4e9738SLei YU { 2556a4e9738SLei YU // When the path ends with '/', it gets am empty path 2566a4e9738SLei YU // skip such case. 2576a4e9738SLei YU break; 2586a4e9738SLei YU } 2596a4e9738SLei YU pathIt++; 2606a4e9738SLei YU } 2616a4e9738SLei YU 2626a4e9738SLei YU while (pathIt != p->path().end()) 2636a4e9738SLei YU { 2646a4e9738SLei YU // Found a path deeper than match. 2656a4e9738SLei YU if (matchPiece == matchPieces.end()) 2666a4e9738SLei YU { 2676a4e9738SLei YU p.disable_recursion_pending(); 2686a4e9738SLei YU break; 2696a4e9738SLei YU } 2706a4e9738SLei YU std::smatch match; 2716a4e9738SLei YU std::string component = pathIt->string(); 2726a4e9738SLei YU std::regex regexPiece(*matchPiece); 2736a4e9738SLei YU if (!std::regex_match(component, match, regexPiece)) 2746a4e9738SLei YU { 2756a4e9738SLei YU // path prefix doesn't match, no need to iterate further 2766a4e9738SLei YU p.disable_recursion_pending(); 2776a4e9738SLei YU break; 2786a4e9738SLei YU } 2796a4e9738SLei YU matchPiece++; 2806a4e9738SLei YU pathIt++; 2816a4e9738SLei YU } 2826a4e9738SLei YU 2836a4e9738SLei YU if (!is_directory(*p)) 2846a4e9738SLei YU { 2856a4e9738SLei YU if (matchPiece == matchPieces.end()) 2866a4e9738SLei YU { 2876a4e9738SLei YU foundPaths.emplace_back(p->path()); 2886a4e9738SLei YU } 2896a4e9738SLei YU } 2906a4e9738SLei YU 2916a4e9738SLei YU if (p.depth() >= symlinkDepth) 2926a4e9738SLei YU { 2936a4e9738SLei YU p.disable_recursion_pending(); 2946a4e9738SLei YU } 2956a4e9738SLei YU } 2966a4e9738SLei YU return true; 2976a4e9738SLei YU } 2986a4e9738SLei YU 29971d31b2eSJames Feist bool isPowerOn(void) 3006714a25aSJames Feist { 30171d31b2eSJames Feist if (!powerMatch) 3026714a25aSJames Feist { 30371d31b2eSJames Feist throw std::runtime_error("Power Match Not Created"); 30471d31b2eSJames Feist } 3056714a25aSJames Feist return powerStatusOn; 3066714a25aSJames Feist } 3076714a25aSJames Feist 308fc94b215SJames Feist bool hasBiosPost(void) 309fc94b215SJames Feist { 31052497fd0SJames Feist if (!postMatch) 311fc94b215SJames Feist { 31252497fd0SJames Feist throw std::runtime_error("Post Match Not Created"); 313fc94b215SJames Feist } 314fc94b215SJames Feist return biosHasPost; 315fc94b215SJames Feist } 316fc94b215SJames Feist 317c7a1ae6bSKonstantin Aladyshev bool readingStateGood(const PowerState& powerState) 318c7a1ae6bSKonstantin Aladyshev { 319c7a1ae6bSKonstantin Aladyshev if (powerState == PowerState::on && !isPowerOn()) 320c7a1ae6bSKonstantin Aladyshev { 321c7a1ae6bSKonstantin Aladyshev return false; 322c7a1ae6bSKonstantin Aladyshev } 323c7a1ae6bSKonstantin Aladyshev if (powerState == PowerState::biosPost && (!hasBiosPost() || !isPowerOn())) 324c7a1ae6bSKonstantin Aladyshev { 325c7a1ae6bSKonstantin Aladyshev return false; 326c7a1ae6bSKonstantin Aladyshev } 327c7a1ae6bSKonstantin Aladyshev 328c7a1ae6bSKonstantin Aladyshev return true; 329c7a1ae6bSKonstantin Aladyshev } 330c7a1ae6bSKonstantin Aladyshev 3318aeffd91SJames Feist static void 3328aeffd91SJames Feist getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn, 3338aeffd91SJames Feist size_t retries = 2) 3348aeffd91SJames Feist { 3358aeffd91SJames Feist conn->async_method_call( 3368aeffd91SJames Feist [conn, retries](boost::system::error_code ec, 3378aeffd91SJames Feist const std::variant<std::string>& state) { 3388aeffd91SJames Feist if (ec) 3398aeffd91SJames Feist { 340*2049bd26SEd Tanous if (retries != 0U) 3418aeffd91SJames Feist { 3428aeffd91SJames Feist auto timer = std::make_shared<boost::asio::steady_timer>( 3438aeffd91SJames Feist conn->get_io_context()); 3448aeffd91SJames Feist timer->expires_after(std::chrono::seconds(15)); 3458aeffd91SJames Feist timer->async_wait( 3468aeffd91SJames Feist [timer, conn, retries](boost::system::error_code) { 3478aeffd91SJames Feist getPowerStatus(conn, retries - 1); 3488aeffd91SJames Feist }); 3498aeffd91SJames Feist return; 3508aeffd91SJames Feist } 3518aeffd91SJames Feist 3528aeffd91SJames Feist // we commonly come up before power control, we'll capture the 3538aeffd91SJames Feist // property change later 354bb67932aSEd Tanous std::cerr << "error getting power status " << ec.message() << "\n"; 3558aeffd91SJames Feist return; 3568aeffd91SJames Feist } 3578aeffd91SJames Feist powerStatusOn = 358585d3a07SThu Ba Nguyen boost::ends_with(std::get<std::string>(state), ".Running"); 3598aeffd91SJames Feist }, 3608aeffd91SJames Feist power::busname, power::path, properties::interface, properties::get, 3618aeffd91SJames Feist power::interface, power::property); 3628aeffd91SJames Feist } 3638aeffd91SJames Feist 3648aeffd91SJames Feist static void 3658aeffd91SJames Feist getPostStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn, 3668aeffd91SJames Feist size_t retries = 2) 3678aeffd91SJames Feist { 3688aeffd91SJames Feist conn->async_method_call( 3698aeffd91SJames Feist [conn, retries](boost::system::error_code ec, 3708aeffd91SJames Feist const std::variant<std::string>& state) { 3718aeffd91SJames Feist if (ec) 3728aeffd91SJames Feist { 373*2049bd26SEd Tanous if (retries != 0U) 3748aeffd91SJames Feist { 3758aeffd91SJames Feist auto timer = std::make_shared<boost::asio::steady_timer>( 3768aeffd91SJames Feist conn->get_io_context()); 3778aeffd91SJames Feist timer->expires_after(std::chrono::seconds(15)); 3788aeffd91SJames Feist timer->async_wait( 3798aeffd91SJames Feist [timer, conn, retries](boost::system::error_code) { 3808aeffd91SJames Feist getPostStatus(conn, retries - 1); 3818aeffd91SJames Feist }); 3828aeffd91SJames Feist return; 3838aeffd91SJames Feist } 3848aeffd91SJames Feist // we commonly come up before power control, we'll capture the 3858aeffd91SJames Feist // property change later 386bb67932aSEd Tanous std::cerr << "error getting post status " << ec.message() << "\n"; 3878aeffd91SJames Feist return; 3888aeffd91SJames Feist } 389*2049bd26SEd Tanous const auto& value = std::get<std::string>(state); 39050107246SAndrei Kartashev biosHasPost = (value != "Inactive") && 39150107246SAndrei Kartashev (value != "xyz.openbmc_project.State.OperatingSystem." 39250107246SAndrei Kartashev "Status.OSStatus.Inactive"); 3938aeffd91SJames Feist }, 3948aeffd91SJames Feist post::busname, post::path, properties::interface, properties::get, 3958aeffd91SJames Feist post::interface, post::property); 3968aeffd91SJames Feist } 3978aeffd91SJames Feist 39871d31b2eSJames Feist void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn) 39971d31b2eSJames Feist { 40043d32fefSJames Feist static boost::asio::steady_timer timer(conn->get_io_context()); 4016714a25aSJames Feist // create a match for powergood changes, first time do a method call to 40271d31b2eSJames Feist // cache the correct value 40352497fd0SJames Feist if (powerMatch) 4046714a25aSJames Feist { 40552497fd0SJames Feist return; 4066714a25aSJames Feist } 4076714a25aSJames Feist 4086714a25aSJames Feist powerMatch = std::make_unique<sdbusplus::bus::match::match>( 4096714a25aSJames Feist static_cast<sdbusplus::bus::bus&>(*conn), 41052497fd0SJames Feist "type='signal',interface='" + std::string(properties::interface) + 41152497fd0SJames Feist "',path='" + std::string(power::path) + "',arg0='" + 41252497fd0SJames Feist std::string(power::interface) + "'", 41352497fd0SJames Feist [](sdbusplus::message::message& message) { 41452497fd0SJames Feist std::string objectName; 41552497fd0SJames Feist boost::container::flat_map<std::string, std::variant<std::string>> 41652497fd0SJames Feist values; 41752497fd0SJames Feist message.read(objectName, values); 41852497fd0SJames Feist auto findState = values.find(power::property); 41952497fd0SJames Feist if (findState != values.end()) 4206714a25aSJames Feist { 421bb67932aSEd Tanous bool on = boost::ends_with(std::get<std::string>(findState->second), 422bb67932aSEd Tanous ".Running"); 42343d32fefSJames Feist if (!on) 42443d32fefSJames Feist { 42543d32fefSJames Feist timer.cancel(); 42643d32fefSJames Feist powerStatusOn = false; 42743d32fefSJames Feist return; 42843d32fefSJames Feist } 42943d32fefSJames Feist // on comes too quickly 43043d32fefSJames Feist timer.expires_after(std::chrono::seconds(10)); 43143d32fefSJames Feist timer.async_wait([](boost::system::error_code ec) { 43243d32fefSJames Feist if (ec == boost::asio::error::operation_aborted) 43343d32fefSJames Feist { 43443d32fefSJames Feist return; 43543d32fefSJames Feist } 4368a57ec09SEd Tanous if (ec) 43743d32fefSJames Feist { 43843d32fefSJames Feist std::cerr << "Timer error " << ec.message() << "\n"; 43943d32fefSJames Feist return; 44043d32fefSJames Feist } 44143d32fefSJames Feist powerStatusOn = true; 44243d32fefSJames Feist }); 4436714a25aSJames Feist } 44452497fd0SJames Feist }); 44552497fd0SJames Feist 44652497fd0SJames Feist postMatch = std::make_unique<sdbusplus::bus::match::match>( 44752497fd0SJames Feist static_cast<sdbusplus::bus::bus&>(*conn), 44852497fd0SJames Feist "type='signal',interface='" + std::string(properties::interface) + 44952497fd0SJames Feist "',path='" + std::string(post::path) + "',arg0='" + 45052497fd0SJames Feist std::string(post::interface) + "'", 45152497fd0SJames Feist [](sdbusplus::message::message& message) { 45252497fd0SJames Feist std::string objectName; 45352497fd0SJames Feist boost::container::flat_map<std::string, std::variant<std::string>> 45452497fd0SJames Feist values; 45552497fd0SJames Feist message.read(objectName, values); 45652497fd0SJames Feist auto findState = values.find(post::property); 45752497fd0SJames Feist if (findState != values.end()) 45852497fd0SJames Feist { 45950107246SAndrei Kartashev auto& value = std::get<std::string>(findState->second); 460bb67932aSEd Tanous biosHasPost = (value != "Inactive") && 46150107246SAndrei Kartashev (value != "xyz.openbmc_project.State.OperatingSystem." 46250107246SAndrei Kartashev "Status.OSStatus.Inactive"); 46352497fd0SJames Feist } 46452497fd0SJames Feist }); 465fc94b215SJames Feist 4668aeffd91SJames Feist getPowerStatus(conn); 4678aeffd91SJames Feist getPostStatus(conn); 4686714a25aSJames Feist } 46987d713abSJames Feist 47087d713abSJames Feist // replaces limits if MinReading and MaxReading are found. 47187d713abSJames Feist void findLimits(std::pair<double, double>& limits, 47287d713abSJames Feist const SensorBaseConfiguration* data) 47387d713abSJames Feist { 474*2049bd26SEd Tanous if (data == nullptr) 47587d713abSJames Feist { 47687d713abSJames Feist return; 47787d713abSJames Feist } 47887d713abSJames Feist auto maxFind = data->second.find("MaxReading"); 47987d713abSJames Feist auto minFind = data->second.find("MinReading"); 48087d713abSJames Feist 48187d713abSJames Feist if (minFind != data->second.end()) 48287d713abSJames Feist { 4833eb82629SJames Feist limits.first = std::visit(VariantToDoubleVisitor(), minFind->second); 48487d713abSJames Feist } 48587d713abSJames Feist if (maxFind != data->second.end()) 48687d713abSJames Feist { 4873eb82629SJames Feist limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second); 48887d713abSJames Feist } 48987d713abSJames Feist } 49082bac4c7SJames Feist 49182bac4c7SJames Feist void createAssociation( 49282bac4c7SJames Feist std::shared_ptr<sdbusplus::asio::dbus_interface>& association, 49382bac4c7SJames Feist const std::string& path) 49482bac4c7SJames Feist { 49582bac4c7SJames Feist if (association) 49682bac4c7SJames Feist { 4976a4e9738SLei YU fs::path p(path); 498d2543f81SJames Feist 49982bac4c7SJames Feist std::vector<Association> associations; 5008a57ec09SEd Tanous associations.emplace_back("chassis", "all_sensors", 5018a57ec09SEd Tanous p.parent_path().string()); 5022adc95cbSJames Feist association->register_property("Associations", associations); 50382bac4c7SJames Feist association->initialize(); 50482bac4c7SJames Feist } 50582bac4c7SJames Feist } 5065580f2f7SCheng C Yang 5075580f2f7SCheng C Yang void setInventoryAssociation( 5088a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::dbus_interface>& association, 509c82213ccSAppaRao Puli const std::string& path, 510c82213ccSAppaRao Puli const std::vector<std::string>& chassisPaths = std::vector<std::string>()) 5115580f2f7SCheng C Yang { 5125580f2f7SCheng C Yang if (association) 5135580f2f7SCheng C Yang { 5146a4e9738SLei YU fs::path p(path); 5155580f2f7SCheng C Yang std::vector<Association> associations; 516c82213ccSAppaRao Puli std::string objPath(p.parent_path().string()); 517c82213ccSAppaRao Puli 5188a57ec09SEd Tanous associations.emplace_back("inventory", "sensors", objPath); 5198a57ec09SEd Tanous associations.emplace_back("chassis", "all_sensors", objPath); 520c82213ccSAppaRao Puli 521c82213ccSAppaRao Puli for (const std::string& chassisPath : chassisPaths) 522c82213ccSAppaRao Puli { 5238a57ec09SEd Tanous associations.emplace_back("chassis", "all_sensors", chassisPath); 524c82213ccSAppaRao Puli } 525c82213ccSAppaRao Puli 5262adc95cbSJames Feist association->register_property("Associations", associations); 5275580f2f7SCheng C Yang association->initialize(); 5285580f2f7SCheng C Yang } 5295580f2f7SCheng C Yang } 5305580f2f7SCheng C Yang 5315580f2f7SCheng C Yang void createInventoryAssoc( 5328a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::connection>& conn, 5338a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::dbus_interface>& association, 5345580f2f7SCheng C Yang const std::string& path) 5355580f2f7SCheng C Yang { 5365580f2f7SCheng C Yang if (!association) 5375580f2f7SCheng C Yang { 5385580f2f7SCheng C Yang return; 5395580f2f7SCheng C Yang } 540c82213ccSAppaRao Puli 5415580f2f7SCheng C Yang conn->async_method_call( 5425580f2f7SCheng C Yang [association, path](const boost::system::error_code ec, 543c82213ccSAppaRao Puli const std::vector<std::string>& invSysObjPaths) { 5445580f2f7SCheng C Yang if (ec) 5455580f2f7SCheng C Yang { 546c82213ccSAppaRao Puli // In case of error, set the default associations and 547c82213ccSAppaRao Puli // initialize the association Interface. 548c82213ccSAppaRao Puli setInventoryAssociation(association, path); 5495580f2f7SCheng C Yang return; 5505580f2f7SCheng C Yang } 551c82213ccSAppaRao Puli setInventoryAssociation(association, path, invSysObjPaths); 5525580f2f7SCheng C Yang }, 5535580f2f7SCheng C Yang mapper::busName, mapper::path, mapper::interface, "GetSubTreePaths", 5545580f2f7SCheng C Yang "/xyz/openbmc_project/inventory/system", 2, 5555580f2f7SCheng C Yang std::array<std::string, 1>{ 5565580f2f7SCheng C Yang "xyz.openbmc_project.Inventory.Item.System"}); 5575580f2f7SCheng C Yang } 55863f38669SZbigniew Kurzynski 55963f38669SZbigniew Kurzynski std::optional<double> readFile(const std::string& thresholdFile, 56063f38669SZbigniew Kurzynski const double& scaleFactor) 56163f38669SZbigniew Kurzynski { 56263f38669SZbigniew Kurzynski std::string line; 56363f38669SZbigniew Kurzynski std::ifstream labelFile(thresholdFile); 56463f38669SZbigniew Kurzynski if (labelFile.good()) 56563f38669SZbigniew Kurzynski { 56663f38669SZbigniew Kurzynski std::getline(labelFile, line); 56763f38669SZbigniew Kurzynski labelFile.close(); 56863f38669SZbigniew Kurzynski 56963f38669SZbigniew Kurzynski try 57063f38669SZbigniew Kurzynski { 57163f38669SZbigniew Kurzynski return std::stod(line) / scaleFactor; 57263f38669SZbigniew Kurzynski } 57363f38669SZbigniew Kurzynski catch (const std::invalid_argument&) 57463f38669SZbigniew Kurzynski { 57563f38669SZbigniew Kurzynski return std::nullopt; 57663f38669SZbigniew Kurzynski } 57763f38669SZbigniew Kurzynski } 57863f38669SZbigniew Kurzynski return std::nullopt; 57963f38669SZbigniew Kurzynski } 58063f38669SZbigniew Kurzynski 58163f38669SZbigniew Kurzynski std::optional<std::tuple<std::string, std::string, std::string>> 5826a4e9738SLei YU splitFileName(const fs::path& filePath) 58363f38669SZbigniew Kurzynski { 58463f38669SZbigniew Kurzynski if (filePath.has_filename()) 58563f38669SZbigniew Kurzynski { 58663f38669SZbigniew Kurzynski const auto fileName = filePath.filename().string(); 58763f38669SZbigniew Kurzynski 588dd648008SZbigniew Kurzynski size_t numberPos = std::strcspn(fileName.c_str(), "1234567890"); 589dd648008SZbigniew Kurzynski size_t itemPos = std::strcspn(fileName.c_str(), "_"); 590dd648008SZbigniew Kurzynski 591dd648008SZbigniew Kurzynski if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos) 59263f38669SZbigniew Kurzynski { 593dd648008SZbigniew Kurzynski return std::make_optional( 594dd648008SZbigniew Kurzynski std::make_tuple(fileName.substr(0, numberPos), 595dd648008SZbigniew Kurzynski fileName.substr(numberPos, itemPos - numberPos), 596dd648008SZbigniew Kurzynski fileName.substr(itemPos + 1, fileName.size()))); 59763f38669SZbigniew Kurzynski } 59863f38669SZbigniew Kurzynski } 59963f38669SZbigniew Kurzynski return std::nullopt; 60063f38669SZbigniew Kurzynski } 6011263c3daSBruce Lee 60245f844acSArun P. Mohanan static void handleSpecialModeChange(const std::string& manufacturingModeStatus) 6031263c3daSBruce Lee { 6041263c3daSBruce Lee manufacturingMode = false; 60545f844acSArun P. Mohanan if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security." 6061263c3daSBruce Lee "SpecialMode.Modes.Manufacturing") 6071263c3daSBruce Lee { 6081263c3daSBruce Lee manufacturingMode = true; 6091263c3daSBruce Lee } 61074cffa88SEd Tanous if (validateUnsecureFeature == 1) 6111263c3daSBruce Lee { 61245f844acSArun P. Mohanan if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security." 6131263c3daSBruce Lee "SpecialMode.Modes.ValidationUnsecure") 6141263c3daSBruce Lee { 6151263c3daSBruce Lee manufacturingMode = true; 6161263c3daSBruce Lee } 6171263c3daSBruce Lee } 61845f844acSArun P. Mohanan } 61945f844acSArun P. Mohanan 62045f844acSArun P. Mohanan void setupManufacturingModeMatch(sdbusplus::asio::connection& conn) 62145f844acSArun P. Mohanan { 62245f844acSArun P. Mohanan namespace rules = sdbusplus::bus::match::rules; 62345f844acSArun P. Mohanan static constexpr const char* specialModeInterface = 62445f844acSArun P. Mohanan "xyz.openbmc_project.Security.SpecialMode"; 62545f844acSArun P. Mohanan 62645f844acSArun P. Mohanan const std::string filterSpecialModeIntfAdd = 62745f844acSArun P. Mohanan rules::interfacesAdded() + 62845f844acSArun P. Mohanan rules::argNpath(0, "/xyz/openbmc_project/security/special_mode"); 62945f844acSArun P. Mohanan static std::unique_ptr<sdbusplus::bus::match::match> specialModeIntfMatch = 63045f844acSArun P. Mohanan std::make_unique<sdbusplus::bus::match::match>( 631bb67932aSEd Tanous conn, filterSpecialModeIntfAdd, 632bb67932aSEd Tanous [](sdbusplus::message::message& m) { 63345f844acSArun P. Mohanan sdbusplus::message::object_path path; 63445f844acSArun P. Mohanan using PropertyMap = 635bb67932aSEd Tanous boost::container::flat_map<std::string, std::variant<std::string>>; 636bb67932aSEd Tanous boost::container::flat_map<std::string, PropertyMap> interfaceAdded; 63745f844acSArun P. Mohanan m.read(path, interfaceAdded); 63845f844acSArun P. Mohanan auto intfItr = interfaceAdded.find(specialModeInterface); 63945f844acSArun P. Mohanan if (intfItr == interfaceAdded.end()) 64045f844acSArun P. Mohanan { 64145f844acSArun P. Mohanan return; 64245f844acSArun P. Mohanan } 64345f844acSArun P. Mohanan PropertyMap& propertyList = intfItr->second; 64445f844acSArun P. Mohanan auto itr = propertyList.find("SpecialMode"); 64545f844acSArun P. Mohanan if (itr == propertyList.end()) 64645f844acSArun P. Mohanan { 64745f844acSArun P. Mohanan std::cerr << "error getting SpecialMode property " 64845f844acSArun P. Mohanan << "\n"; 64945f844acSArun P. Mohanan return; 65045f844acSArun P. Mohanan } 651*2049bd26SEd Tanous auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second); 65245f844acSArun P. Mohanan handleSpecialModeChange(*manufacturingModeStatus); 6531263c3daSBruce Lee }); 6541263c3daSBruce Lee 65545f844acSArun P. Mohanan const std::string filterSpecialModeChange = 65645f844acSArun P. Mohanan rules::type::signal() + rules::member("PropertiesChanged") + 65745f844acSArun P. Mohanan rules::interface("org.freedesktop.DBus.Properties") + 65845f844acSArun P. Mohanan rules::argN(0, specialModeInterface); 65945f844acSArun P. Mohanan static std::unique_ptr<sdbusplus::bus::match::match> 66045f844acSArun P. Mohanan specialModeChangeMatch = std::make_unique<sdbusplus::bus::match::match>( 661bb67932aSEd Tanous conn, filterSpecialModeChange, 662bb67932aSEd Tanous [](sdbusplus::message::message& m) { 66345f844acSArun P. Mohanan std::string interfaceName; 664bb67932aSEd Tanous boost::container::flat_map<std::string, std::variant<std::string>> 66545f844acSArun P. Mohanan propertiesChanged; 66645f844acSArun P. Mohanan 66745f844acSArun P. Mohanan m.read(interfaceName, propertiesChanged); 66845f844acSArun P. Mohanan auto itr = propertiesChanged.find("SpecialMode"); 66945f844acSArun P. Mohanan if (itr == propertiesChanged.end()) 67045f844acSArun P. Mohanan { 6711263c3daSBruce Lee return; 6721263c3daSBruce Lee } 673*2049bd26SEd Tanous auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second); 67445f844acSArun P. Mohanan handleSpecialModeChange(*manufacturingModeStatus); 67545f844acSArun P. Mohanan }); 67645f844acSArun P. Mohanan 67745f844acSArun P. Mohanan conn.async_method_call( 67845f844acSArun P. Mohanan [](const boost::system::error_code ec, 67945f844acSArun P. Mohanan const std::variant<std::string>& getManufactMode) { 68045f844acSArun P. Mohanan if (ec) 68145f844acSArun P. Mohanan { 682bb67932aSEd Tanous std::cerr << "error getting SpecialMode status " << ec.message() 683bb67932aSEd Tanous << "\n"; 68445f844acSArun P. Mohanan return; 68545f844acSArun P. Mohanan } 686*2049bd26SEd Tanous const auto* manufacturingModeStatus = 68745f844acSArun P. Mohanan std::get_if<std::string>(&getManufactMode); 68845f844acSArun P. Mohanan handleSpecialModeChange(*manufacturingModeStatus); 68945f844acSArun P. Mohanan }, 69045f844acSArun P. Mohanan "xyz.openbmc_project.SpecialMode", 69145f844acSArun P. Mohanan "/xyz/openbmc_project/security/special_mode", 69245f844acSArun P. Mohanan "org.freedesktop.DBus.Properties", "Get", specialModeInterface, 69345f844acSArun P. Mohanan "SpecialMode"); 69445f844acSArun P. Mohanan } 6951263c3daSBruce Lee 6961263c3daSBruce Lee bool getManufacturingMode() 6971263c3daSBruce Lee { 6981263c3daSBruce Lee return manufacturingMode; 6991263c3daSBruce Lee } 700