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
17e73bd0a1SAndrew Jeffery #include "Utils.hpp"
18e73bd0a1SAndrew Jeffery
191263c3daSBruce Lee #include "dbus-sensor_config.h"
201263c3daSBruce Lee
21e73bd0a1SAndrew Jeffery #include "DeviceMgmt.hpp"
22eacbfdd1SEd Tanous #include "VariantVisitors.hpp"
23e73bd0a1SAndrew Jeffery
24eacbfdd1SEd Tanous #include <boost/asio/error.hpp>
25eacbfdd1SEd Tanous #include <boost/asio/steady_timer.hpp>
2696e97db7SPatrick Venture #include <boost/container/flat_map.hpp>
2738fb5983SJames Feist #include <sdbusplus/asio/connection.hpp>
2838fb5983SJames Feist #include <sdbusplus/asio/object_server.hpp>
29eacbfdd1SEd Tanous #include <sdbusplus/bus.hpp>
3038fb5983SJames Feist #include <sdbusplus/bus/match.hpp>
31eacbfdd1SEd Tanous #include <sdbusplus/exception.hpp>
32eacbfdd1SEd Tanous #include <sdbusplus/message.hpp>
33eacbfdd1SEd Tanous #include <sdbusplus/message/native_types.hpp>
3438fb5983SJames Feist
35eacbfdd1SEd Tanous #include <algorithm>
36eacbfdd1SEd Tanous #include <array>
37eacbfdd1SEd Tanous #include <chrono>
38eacbfdd1SEd Tanous #include <cstddef>
39eacbfdd1SEd Tanous #include <cstring>
4024f02f24SJames Feist #include <filesystem>
416714a25aSJames Feist #include <fstream>
42eacbfdd1SEd Tanous #include <functional>
43eacbfdd1SEd Tanous #include <iostream>
44eacbfdd1SEd Tanous #include <iterator>
4596e97db7SPatrick Venture #include <memory>
46eacbfdd1SEd Tanous #include <optional>
476714a25aSJames Feist #include <regex>
48eacbfdd1SEd Tanous #include <set>
49eacbfdd1SEd Tanous #include <span>
5096e97db7SPatrick Venture #include <stdexcept>
5196e97db7SPatrick Venture #include <string>
52eacbfdd1SEd Tanous #include <string_view>
53eacbfdd1SEd Tanous #include <system_error>
54eacbfdd1SEd Tanous #include <tuple>
5596e97db7SPatrick Venture #include <utility>
5696e97db7SPatrick Venture #include <variant>
5796e97db7SPatrick Venture #include <vector>
586714a25aSJames Feist
596ef20407SJames Feist static bool powerStatusOn = false;
60fc94b215SJames Feist static bool biosHasPost = false;
611263c3daSBruce Lee static bool manufacturingMode = false;
626db8aae4SThu Nguyen static bool chassisStatusOn = false;
6358295adaSJames Feist
6492f8f515SPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> powerMatch = nullptr;
6592f8f515SPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> postMatch = nullptr;
666db8aae4SThu Nguyen static std::unique_ptr<sdbusplus::bus::match_t> chassisMatch = nullptr;
6771d31b2eSJames Feist
68100c20bfSJason Ling /**
69100c20bfSJason Ling * return the contents of a file
70100c20bfSJason Ling * @param[in] hwmonFile - the path to the file to read
71100c20bfSJason Ling * @return the contents of the file as a string or nullopt if the file could not
72100c20bfSJason Ling * be opened.
73100c20bfSJason Ling */
74100c20bfSJason Ling
openAndRead(const std::string & hwmonFile)75100c20bfSJason Ling std::optional<std::string> openAndRead(const std::string& hwmonFile)
76100c20bfSJason Ling {
77100c20bfSJason Ling std::string fileVal;
78100c20bfSJason Ling std::ifstream fileStream(hwmonFile);
79100c20bfSJason Ling if (!fileStream.is_open())
80100c20bfSJason Ling {
81100c20bfSJason Ling return std::nullopt;
82100c20bfSJason Ling }
83100c20bfSJason Ling std::getline(fileStream, fileVal);
84100c20bfSJason Ling return fileVal;
85100c20bfSJason Ling }
86100c20bfSJason Ling
87100c20bfSJason Ling /**
88100c20bfSJason Ling * given a hwmon temperature base name if valid return the full path else
89100c20bfSJason Ling * nullopt
90100c20bfSJason Ling * @param[in] directory - the hwmon sysfs directory
91100c20bfSJason Ling * @param[in] permitSet - a set of labels or hwmon basenames to permit. If this
92100c20bfSJason Ling * is empty then *everything* is permitted.
93100c20bfSJason Ling * @return a string to the full path of the file to create a temp sensor with or
94100c20bfSJason Ling * nullopt to indicate that no sensor should be created for this basename.
95100c20bfSJason Ling */
getFullHwmonFilePath(const std::string & directory,const std::string & hwmonBaseName,const std::set<std::string> & permitSet)962aaf7175SPatrick Williams std::optional<std::string> getFullHwmonFilePath(
972aaf7175SPatrick Williams const std::string& directory, const std::string& hwmonBaseName,
98100c20bfSJason Ling const std::set<std::string>& permitSet)
99100c20bfSJason Ling {
100100c20bfSJason Ling std::optional<std::string> result;
101100c20bfSJason Ling std::string filename;
102100c20bfSJason Ling if (permitSet.empty())
103100c20bfSJason Ling {
104100c20bfSJason Ling result = directory + "/" + hwmonBaseName + "_input";
105100c20bfSJason Ling return result;
106100c20bfSJason Ling }
107100c20bfSJason Ling filename = directory + "/" + hwmonBaseName + "_label";
108100c20bfSJason Ling auto searchVal = openAndRead(filename);
109100c20bfSJason Ling if (!searchVal)
110100c20bfSJason Ling {
111100c20bfSJason Ling /* if the hwmon temp doesn't have a corresponding label file
112100c20bfSJason Ling * then use the hwmon temperature base name
113100c20bfSJason Ling */
114100c20bfSJason Ling searchVal = hwmonBaseName;
115100c20bfSJason Ling }
116100c20bfSJason Ling if (permitSet.find(*searchVal) != permitSet.end())
117100c20bfSJason Ling {
118100c20bfSJason Ling result = directory + "/" + hwmonBaseName + "_input";
119100c20bfSJason Ling }
120100c20bfSJason Ling return result;
121100c20bfSJason Ling }
122100c20bfSJason Ling
123100c20bfSJason Ling /**
124100c20bfSJason Ling * retrieve a set of basenames and labels to allow sensor creation for.
125100c20bfSJason Ling * @param[in] config - a map representing the configuration for a specific
126100c20bfSJason Ling * device
127100c20bfSJason Ling * @return a set of basenames and labels to allow sensor creation for. An empty
128100c20bfSJason Ling * set indicates that everything is permitted.
129100c20bfSJason Ling */
getPermitSet(const SensorBaseConfigMap & config)130100c20bfSJason Ling std::set<std::string> getPermitSet(const SensorBaseConfigMap& config)
131100c20bfSJason Ling {
132100c20bfSJason Ling auto permitAttribute = config.find("Labels");
133100c20bfSJason Ling std::set<std::string> permitSet;
134100c20bfSJason Ling if (permitAttribute != config.end())
135100c20bfSJason Ling {
136100c20bfSJason Ling try
137100c20bfSJason Ling {
138100c20bfSJason Ling auto val =
139100c20bfSJason Ling std::get<std::vector<std::string>>(permitAttribute->second);
140100c20bfSJason Ling
141100c20bfSJason Ling permitSet.insert(std::make_move_iterator(val.begin()),
142100c20bfSJason Ling std::make_move_iterator(val.end()));
143100c20bfSJason Ling }
144100c20bfSJason Ling catch (const std::bad_variant_access& err)
145100c20bfSJason Ling {
146100c20bfSJason Ling std::cerr << err.what()
147100c20bfSJason Ling << ":PermitList does not contain a list, wrong "
148100c20bfSJason Ling "variant type.\n";
149100c20bfSJason Ling }
150100c20bfSJason Ling }
151100c20bfSJason Ling return permitSet;
152100c20bfSJason Ling }
153100c20bfSJason Ling
getSensorConfiguration(const std::string & type,const std::shared_ptr<sdbusplus::asio::connection> & dbusConnection,ManagedObjectType & resp,bool useCache)1546714a25aSJames Feist bool getSensorConfiguration(
1556714a25aSJames Feist const std::string& type,
1566714a25aSJames Feist const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
1576714a25aSJames Feist ManagedObjectType& resp, bool useCache)
1586714a25aSJames Feist {
1596714a25aSJames Feist static ManagedObjectType managedObj;
160054aad8fSZev Weiss std::string typeIntf = configInterfaceName(type);
1616714a25aSJames Feist
1626714a25aSJames Feist if (!useCache)
1636714a25aSJames Feist {
1646714a25aSJames Feist managedObj.clear();
16592f8f515SPatrick Williams sdbusplus::message_t getManagedObjects =
1666714a25aSJames Feist dbusConnection->new_method_call(
1672c5a1f2dSJeffLin entityManagerName, "/xyz/openbmc_project/inventory",
1682c5a1f2dSJeffLin "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1696714a25aSJames Feist try
1706714a25aSJames Feist {
17192f8f515SPatrick Williams sdbusplus::message_t reply =
1726714a25aSJames Feist dbusConnection->call(getManagedObjects);
1736714a25aSJames Feist reply.read(managedObj);
1746714a25aSJames Feist }
17592f8f515SPatrick Williams catch (const sdbusplus::exception_t& e)
1766714a25aSJames Feist {
1775747fab1SJason Ling std::cerr << "While calling GetManagedObjects on service:"
1785747fab1SJason Ling << entityManagerName << " exception name:" << e.name()
1795747fab1SJason Ling << "and description:" << e.description()
1805747fab1SJason Ling << " was thrown\n";
1816714a25aSJames Feist return false;
1826714a25aSJames Feist }
1836714a25aSJames Feist }
1846714a25aSJames Feist for (const auto& pathPair : managedObj)
1856714a25aSJames Feist {
186fd3d5f7eSZev Weiss for (const auto& [intf, cfg] : pathPair.second)
1876714a25aSJames Feist {
188054aad8fSZev Weiss if (intf.starts_with(typeIntf))
1896714a25aSJames Feist {
19079d8aef4SZev Weiss resp.emplace(pathPair);
1916714a25aSJames Feist break;
1926714a25aSJames Feist }
1936714a25aSJames Feist }
1946714a25aSJames Feist }
1956714a25aSJames Feist return true;
1966714a25aSJames Feist }
1976714a25aSJames Feist
findFiles(const std::filesystem::path & dirPath,std::string_view matchString,std::vector<std::filesystem::path> & foundPaths,int symlinkDepth)1982e466967SEd Tanous bool findFiles(const std::filesystem::path& dirPath,
1992e466967SEd Tanous std::string_view matchString,
2002e466967SEd Tanous std::vector<std::filesystem::path>& foundPaths, int symlinkDepth)
2016714a25aSJames Feist {
2026a4e9738SLei YU std::error_code ec;
2032e466967SEd Tanous if (!std::filesystem::exists(dirPath, ec))
2048a57ec09SEd Tanous {
2056714a25aSJames Feist return false;
2068a57ec09SEd Tanous }
2076714a25aSJames Feist
2086a4e9738SLei YU std::vector<std::regex> matchPieces;
2096a4e9738SLei YU
2106a4e9738SLei YU size_t pos = 0;
2116a4e9738SLei YU std::string token;
2126a4e9738SLei YU // Generate the regex expressions list from the match we were given
2136a4e9738SLei YU while ((pos = matchString.find('/')) != std::string::npos)
2146a4e9738SLei YU {
2156a4e9738SLei YU token = matchString.substr(0, pos);
2166a4e9738SLei YU matchPieces.emplace_back(token);
2176a4e9738SLei YU matchString.remove_prefix(pos + 1);
2186a4e9738SLei YU }
2196a4e9738SLei YU matchPieces.emplace_back(std::string{matchString});
2206a4e9738SLei YU
2216a4e9738SLei YU // Check if the match string contains directories, and skip the match of
2226a4e9738SLei YU // subdirectory if not
2236a4e9738SLei YU if (matchPieces.size() <= 1)
2246a4e9738SLei YU {
2256a4e9738SLei YU std::regex search(std::string{matchString});
2266714a25aSJames Feist std::smatch match;
2272e466967SEd Tanous for (auto p = std::filesystem::recursive_directory_iterator(
2282e466967SEd Tanous dirPath,
2292e466967SEd Tanous std::filesystem::directory_options::follow_directory_symlink);
2302e466967SEd Tanous p != std::filesystem::recursive_directory_iterator(); ++p)
2316714a25aSJames Feist {
2328a57ec09SEd Tanous std::string path = p->path().string();
2338a57ec09SEd Tanous if (!is_directory(*p))
2346714a25aSJames Feist {
2356714a25aSJames Feist if (std::regex_search(path, match, search))
2366714a25aSJames Feist {
2378a57ec09SEd Tanous foundPaths.emplace_back(p->path());
2388a57ec09SEd Tanous }
2398a57ec09SEd Tanous }
2408a57ec09SEd Tanous if (p.depth() >= symlinkDepth)
2418a57ec09SEd Tanous {
2428a57ec09SEd Tanous p.disable_recursion_pending();
2436714a25aSJames Feist }
2446714a25aSJames Feist }
2456714a25aSJames Feist return true;
2466714a25aSJames Feist }
2476714a25aSJames Feist
2486a4e9738SLei YU // The match string contains directories, verify each level of sub
2496a4e9738SLei YU // directories
2502e466967SEd Tanous for (auto p = std::filesystem::recursive_directory_iterator(
2512e466967SEd Tanous dirPath,
2522e466967SEd Tanous std::filesystem::directory_options::follow_directory_symlink);
2532e466967SEd Tanous p != std::filesystem::recursive_directory_iterator(); ++p)
2546a4e9738SLei YU {
2556a4e9738SLei YU std::vector<std::regex>::iterator matchPiece = matchPieces.begin();
2562e466967SEd Tanous std::filesystem::path::iterator pathIt = p->path().begin();
2572e466967SEd Tanous for (const std::filesystem::path& dir : dirPath)
2586a4e9738SLei YU {
2596a4e9738SLei YU if (dir.empty())
2606a4e9738SLei YU {
2616a4e9738SLei YU // When the path ends with '/', it gets am empty path
2626a4e9738SLei YU // skip such case.
2636a4e9738SLei YU break;
2646a4e9738SLei YU }
2656a4e9738SLei YU pathIt++;
2666a4e9738SLei YU }
2676a4e9738SLei YU
2686a4e9738SLei YU while (pathIt != p->path().end())
2696a4e9738SLei YU {
2706a4e9738SLei YU // Found a path deeper than match.
2716a4e9738SLei YU if (matchPiece == matchPieces.end())
2726a4e9738SLei YU {
2736a4e9738SLei YU p.disable_recursion_pending();
2746a4e9738SLei YU break;
2756a4e9738SLei YU }
2766a4e9738SLei YU std::smatch match;
2776a4e9738SLei YU std::string component = pathIt->string();
2786a4e9738SLei YU std::regex regexPiece(*matchPiece);
2796a4e9738SLei YU if (!std::regex_match(component, match, regexPiece))
2806a4e9738SLei YU {
2816a4e9738SLei YU // path prefix doesn't match, no need to iterate further
2826a4e9738SLei YU p.disable_recursion_pending();
2836a4e9738SLei YU break;
2846a4e9738SLei YU }
2856a4e9738SLei YU matchPiece++;
2866a4e9738SLei YU pathIt++;
2876a4e9738SLei YU }
2886a4e9738SLei YU
2896a4e9738SLei YU if (!is_directory(*p))
2906a4e9738SLei YU {
2916a4e9738SLei YU if (matchPiece == matchPieces.end())
2926a4e9738SLei YU {
2936a4e9738SLei YU foundPaths.emplace_back(p->path());
2946a4e9738SLei YU }
2956a4e9738SLei YU }
2966a4e9738SLei YU
2976a4e9738SLei YU if (p.depth() >= symlinkDepth)
2986a4e9738SLei YU {
2996a4e9738SLei YU p.disable_recursion_pending();
3006a4e9738SLei YU }
3016a4e9738SLei YU }
3026a4e9738SLei YU return true;
3036a4e9738SLei YU }
3046a4e9738SLei YU
isPowerOn()305201a1015SEd Tanous bool isPowerOn()
3066714a25aSJames Feist {
30771d31b2eSJames Feist if (!powerMatch)
3086714a25aSJames Feist {
30971d31b2eSJames Feist throw std::runtime_error("Power Match Not Created");
31071d31b2eSJames Feist }
3116714a25aSJames Feist return powerStatusOn;
3126714a25aSJames Feist }
3136714a25aSJames Feist
hasBiosPost()314201a1015SEd Tanous bool hasBiosPost()
315fc94b215SJames Feist {
31652497fd0SJames Feist if (!postMatch)
317fc94b215SJames Feist {
31852497fd0SJames Feist throw std::runtime_error("Post Match Not Created");
319fc94b215SJames Feist }
320fc94b215SJames Feist return biosHasPost;
321fc94b215SJames Feist }
322fc94b215SJames Feist
isChassisOn()323201a1015SEd Tanous bool isChassisOn()
3246db8aae4SThu Nguyen {
3256db8aae4SThu Nguyen if (!chassisMatch)
3266db8aae4SThu Nguyen {
3276db8aae4SThu Nguyen throw std::runtime_error("Chassis On Match Not Created");
3286db8aae4SThu Nguyen }
3296db8aae4SThu Nguyen return chassisStatusOn;
3306db8aae4SThu Nguyen }
3316db8aae4SThu Nguyen
readingStateGood(const PowerState & powerState)332c7a1ae6bSKonstantin Aladyshev bool readingStateGood(const PowerState& powerState)
333c7a1ae6bSKonstantin Aladyshev {
334c7a1ae6bSKonstantin Aladyshev if (powerState == PowerState::on && !isPowerOn())
335c7a1ae6bSKonstantin Aladyshev {
336c7a1ae6bSKonstantin Aladyshev return false;
337c7a1ae6bSKonstantin Aladyshev }
338c7a1ae6bSKonstantin Aladyshev if (powerState == PowerState::biosPost && (!hasBiosPost() || !isPowerOn()))
339c7a1ae6bSKonstantin Aladyshev {
340c7a1ae6bSKonstantin Aladyshev return false;
341c7a1ae6bSKonstantin Aladyshev }
3426db8aae4SThu Nguyen if (powerState == PowerState::chassisOn && !isChassisOn())
3436db8aae4SThu Nguyen {
3446db8aae4SThu Nguyen return false;
3456db8aae4SThu Nguyen }
346c7a1ae6bSKonstantin Aladyshev
347c7a1ae6bSKonstantin Aladyshev return true;
348c7a1ae6bSKonstantin Aladyshev }
349c7a1ae6bSKonstantin Aladyshev
getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection> & conn,size_t retries=2)350*556e04b8SPatrick Williams static void getPowerStatus(
351*556e04b8SPatrick Williams const std::shared_ptr<sdbusplus::asio::connection>& conn,
3528aeffd91SJames Feist size_t retries = 2)
3538aeffd91SJames Feist {
3548aeffd91SJames Feist conn->async_method_call(
3558aeffd91SJames Feist [conn, retries](boost::system::error_code ec,
3568aeffd91SJames Feist const std::variant<std::string>& state) {
3578aeffd91SJames Feist if (ec)
3588aeffd91SJames Feist {
3592049bd26SEd Tanous if (retries != 0U)
3608aeffd91SJames Feist {
3618aeffd91SJames Feist auto timer = std::make_shared<boost::asio::steady_timer>(
3628aeffd91SJames Feist conn->get_io_context());
3638aeffd91SJames Feist timer->expires_after(std::chrono::seconds(15));
3648aeffd91SJames Feist timer->async_wait(
3658aeffd91SJames Feist [timer, conn, retries](boost::system::error_code) {
3668aeffd91SJames Feist getPowerStatus(conn, retries - 1);
3678aeffd91SJames Feist });
3688aeffd91SJames Feist return;
3698aeffd91SJames Feist }
3708aeffd91SJames Feist
3718aeffd91SJames Feist // we commonly come up before power control, we'll capture the
3728aeffd91SJames Feist // property change later
3732aaf7175SPatrick Williams std::cerr << "error getting power status " << ec.message()
3742aaf7175SPatrick Williams << "\n";
3758aeffd91SJames Feist return;
3768aeffd91SJames Feist }
3776c106d66SZev Weiss powerStatusOn = std::get<std::string>(state).ends_with(".Running");
3788aeffd91SJames Feist },
3798aeffd91SJames Feist power::busname, power::path, properties::interface, properties::get,
3808aeffd91SJames Feist power::interface, power::property);
3818aeffd91SJames Feist }
3828aeffd91SJames Feist
getPostStatus(const std::shared_ptr<sdbusplus::asio::connection> & conn,size_t retries=2)383*556e04b8SPatrick Williams static void getPostStatus(
384*556e04b8SPatrick Williams const std::shared_ptr<sdbusplus::asio::connection>& conn,
3858aeffd91SJames Feist size_t retries = 2)
3868aeffd91SJames Feist {
3878aeffd91SJames Feist conn->async_method_call(
3888aeffd91SJames Feist [conn, retries](boost::system::error_code ec,
3898aeffd91SJames Feist const std::variant<std::string>& state) {
3908aeffd91SJames Feist if (ec)
3918aeffd91SJames Feist {
3922049bd26SEd Tanous if (retries != 0U)
3938aeffd91SJames Feist {
3948aeffd91SJames Feist auto timer = std::make_shared<boost::asio::steady_timer>(
3958aeffd91SJames Feist conn->get_io_context());
3968aeffd91SJames Feist timer->expires_after(std::chrono::seconds(15));
3978aeffd91SJames Feist timer->async_wait(
3988aeffd91SJames Feist [timer, conn, retries](boost::system::error_code) {
3998aeffd91SJames Feist getPostStatus(conn, retries - 1);
4008aeffd91SJames Feist });
4018aeffd91SJames Feist return;
4028aeffd91SJames Feist }
4038aeffd91SJames Feist // we commonly come up before power control, we'll capture the
4048aeffd91SJames Feist // property change later
4052aaf7175SPatrick Williams std::cerr << "error getting post status " << ec.message()
4062aaf7175SPatrick Williams << "\n";
4078aeffd91SJames Feist return;
4088aeffd91SJames Feist }
4092049bd26SEd Tanous const auto& value = std::get<std::string>(state);
41050107246SAndrei Kartashev biosHasPost = (value != "Inactive") &&
41150107246SAndrei Kartashev (value != "xyz.openbmc_project.State.OperatingSystem."
41250107246SAndrei Kartashev "Status.OSStatus.Inactive");
4138aeffd91SJames Feist },
4148aeffd91SJames Feist post::busname, post::path, properties::interface, properties::get,
4158aeffd91SJames Feist post::interface, post::property);
4168aeffd91SJames Feist }
4178aeffd91SJames Feist
getChassisStatus(const std::shared_ptr<sdbusplus::asio::connection> & conn,size_t retries=2)418*556e04b8SPatrick Williams static void getChassisStatus(
419*556e04b8SPatrick Williams const std::shared_ptr<sdbusplus::asio::connection>& conn,
4206db8aae4SThu Nguyen size_t retries = 2)
4216db8aae4SThu Nguyen {
4226db8aae4SThu Nguyen conn->async_method_call(
4236db8aae4SThu Nguyen [conn, retries](boost::system::error_code ec,
4246db8aae4SThu Nguyen const std::variant<std::string>& state) {
4256db8aae4SThu Nguyen if (ec)
4266db8aae4SThu Nguyen {
4276db8aae4SThu Nguyen if (retries != 0U)
4286db8aae4SThu Nguyen {
4296db8aae4SThu Nguyen auto timer = std::make_shared<boost::asio::steady_timer>(
4306db8aae4SThu Nguyen conn->get_io_context());
4316db8aae4SThu Nguyen timer->expires_after(std::chrono::seconds(15));
4326db8aae4SThu Nguyen timer->async_wait(
4336db8aae4SThu Nguyen [timer, conn, retries](boost::system::error_code) {
4346db8aae4SThu Nguyen getChassisStatus(conn, retries - 1);
4356db8aae4SThu Nguyen });
4366db8aae4SThu Nguyen return;
4376db8aae4SThu Nguyen }
4386db8aae4SThu Nguyen
4396db8aae4SThu Nguyen // we commonly come up before power control, we'll capture the
4406db8aae4SThu Nguyen // property change later
4412aaf7175SPatrick Williams std::cerr << "error getting chassis power status "
4422aaf7175SPatrick Williams << ec.message() << "\n";
4436db8aae4SThu Nguyen return;
4446db8aae4SThu Nguyen }
4452aaf7175SPatrick Williams chassisStatusOn =
4462aaf7175SPatrick Williams std::get<std::string>(state).ends_with(chassis::sOn);
4476db8aae4SThu Nguyen },
4486db8aae4SThu Nguyen chassis::busname, chassis::path, properties::interface, properties::get,
4496db8aae4SThu Nguyen chassis::interface, chassis::property);
4506db8aae4SThu Nguyen }
4516db8aae4SThu Nguyen
setupPowerMatchCallback(const std::shared_ptr<sdbusplus::asio::connection> & conn,std::function<void (PowerState type,bool state)> && hostStatusCallback)45288cb29d2SZev Weiss void setupPowerMatchCallback(
45388cb29d2SZev Weiss const std::shared_ptr<sdbusplus::asio::connection>& conn,
45488cb29d2SZev Weiss std::function<void(PowerState type, bool state)>&& hostStatusCallback)
45571d31b2eSJames Feist {
45643d32fefSJames Feist static boost::asio::steady_timer timer(conn->get_io_context());
4576db8aae4SThu Nguyen static boost::asio::steady_timer timerChassisOn(conn->get_io_context());
4586714a25aSJames Feist // create a match for powergood changes, first time do a method call to
45971d31b2eSJames Feist // cache the correct value
46052497fd0SJames Feist if (powerMatch)
4616714a25aSJames Feist {
46252497fd0SJames Feist return;
4636714a25aSJames Feist }
4646714a25aSJames Feist
46592f8f515SPatrick Williams powerMatch = std::make_unique<sdbusplus::bus::match_t>(
46692f8f515SPatrick Williams static_cast<sdbusplus::bus_t&>(*conn),
46752497fd0SJames Feist "type='signal',interface='" + std::string(properties::interface) +
46852497fd0SJames Feist "',path='" + std::string(power::path) + "',arg0='" +
46952497fd0SJames Feist std::string(power::interface) + "'",
47088cb29d2SZev Weiss [hostStatusCallback](sdbusplus::message_t& message) {
47152497fd0SJames Feist std::string objectName;
47252497fd0SJames Feist boost::container::flat_map<std::string, std::variant<std::string>>
47352497fd0SJames Feist values;
47452497fd0SJames Feist message.read(objectName, values);
47552497fd0SJames Feist auto findState = values.find(power::property);
47652497fd0SJames Feist if (findState != values.end())
4776714a25aSJames Feist {
4782aaf7175SPatrick Williams bool on = std::get<std::string>(findState->second)
4792aaf7175SPatrick Williams .ends_with(".Running");
48043d32fefSJames Feist if (!on)
48143d32fefSJames Feist {
48243d32fefSJames Feist timer.cancel();
48343d32fefSJames Feist powerStatusOn = false;
48488cb29d2SZev Weiss hostStatusCallback(PowerState::on, powerStatusOn);
48543d32fefSJames Feist return;
48643d32fefSJames Feist }
48743d32fefSJames Feist // on comes too quickly
48843d32fefSJames Feist timer.expires_after(std::chrono::seconds(10));
48988cb29d2SZev Weiss timer.async_wait(
49088cb29d2SZev Weiss [hostStatusCallback](boost::system::error_code ec) {
49143d32fefSJames Feist if (ec == boost::asio::error::operation_aborted)
49243d32fefSJames Feist {
49343d32fefSJames Feist return;
49443d32fefSJames Feist }
4958a57ec09SEd Tanous if (ec)
49643d32fefSJames Feist {
49743d32fefSJames Feist std::cerr << "Timer error " << ec.message() << "\n";
49843d32fefSJames Feist return;
49943d32fefSJames Feist }
50043d32fefSJames Feist powerStatusOn = true;
50188cb29d2SZev Weiss hostStatusCallback(PowerState::on, powerStatusOn);
50243d32fefSJames Feist });
5036714a25aSJames Feist }
50452497fd0SJames Feist });
50552497fd0SJames Feist
50692f8f515SPatrick Williams postMatch = std::make_unique<sdbusplus::bus::match_t>(
50792f8f515SPatrick Williams static_cast<sdbusplus::bus_t&>(*conn),
50852497fd0SJames Feist "type='signal',interface='" + std::string(properties::interface) +
50952497fd0SJames Feist "',path='" + std::string(post::path) + "',arg0='" +
51052497fd0SJames Feist std::string(post::interface) + "'",
51188cb29d2SZev Weiss [hostStatusCallback](sdbusplus::message_t& message) {
51252497fd0SJames Feist std::string objectName;
51352497fd0SJames Feist boost::container::flat_map<std::string, std::variant<std::string>>
51452497fd0SJames Feist values;
51552497fd0SJames Feist message.read(objectName, values);
51652497fd0SJames Feist auto findState = values.find(post::property);
51752497fd0SJames Feist if (findState != values.end())
51852497fd0SJames Feist {
51950107246SAndrei Kartashev auto& value = std::get<std::string>(findState->second);
5202aaf7175SPatrick Williams biosHasPost =
5212aaf7175SPatrick Williams (value != "Inactive") &&
52250107246SAndrei Kartashev (value != "xyz.openbmc_project.State.OperatingSystem."
52350107246SAndrei Kartashev "Status.OSStatus.Inactive");
52488cb29d2SZev Weiss hostStatusCallback(PowerState::biosPost, biosHasPost);
52552497fd0SJames Feist }
52652497fd0SJames Feist });
527fc94b215SJames Feist
5286db8aae4SThu Nguyen chassisMatch = std::make_unique<sdbusplus::bus::match_t>(
5296db8aae4SThu Nguyen static_cast<sdbusplus::bus_t&>(*conn),
5306db8aae4SThu Nguyen "type='signal',interface='" + std::string(properties::interface) +
5316db8aae4SThu Nguyen "',path='" + std::string(chassis::path) + "',arg0='" +
5326db8aae4SThu Nguyen std::string(chassis::interface) + "'",
5339142343bSEd Tanous [hostStatusCallback = std::move(hostStatusCallback)](
5349142343bSEd Tanous sdbusplus::message_t& message) {
5356db8aae4SThu Nguyen std::string objectName;
5366db8aae4SThu Nguyen boost::container::flat_map<std::string, std::variant<std::string>>
5376db8aae4SThu Nguyen values;
5386db8aae4SThu Nguyen message.read(objectName, values);
5396db8aae4SThu Nguyen auto findState = values.find(chassis::property);
5406db8aae4SThu Nguyen if (findState != values.end())
5416db8aae4SThu Nguyen {
5426db8aae4SThu Nguyen bool on = std::get<std::string>(findState->second)
5436db8aae4SThu Nguyen .ends_with(chassis::sOn);
5446db8aae4SThu Nguyen if (!on)
5456db8aae4SThu Nguyen {
5466db8aae4SThu Nguyen timerChassisOn.cancel();
5476db8aae4SThu Nguyen chassisStatusOn = false;
5486db8aae4SThu Nguyen hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
5496db8aae4SThu Nguyen return;
5506db8aae4SThu Nguyen }
5516db8aae4SThu Nguyen // on comes too quickly
5526db8aae4SThu Nguyen timerChassisOn.expires_after(std::chrono::seconds(10));
5532aaf7175SPatrick Williams timerChassisOn.async_wait([hostStatusCallback](
5542aaf7175SPatrick Williams boost::system::error_code ec) {
5556db8aae4SThu Nguyen if (ec == boost::asio::error::operation_aborted)
5566db8aae4SThu Nguyen {
5576db8aae4SThu Nguyen return;
5586db8aae4SThu Nguyen }
5596db8aae4SThu Nguyen if (ec)
5606db8aae4SThu Nguyen {
5616db8aae4SThu Nguyen std::cerr << "Timer error " << ec.message() << "\n";
5626db8aae4SThu Nguyen return;
5636db8aae4SThu Nguyen }
5646db8aae4SThu Nguyen chassisStatusOn = true;
5656db8aae4SThu Nguyen hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
5666db8aae4SThu Nguyen });
5676db8aae4SThu Nguyen }
5686db8aae4SThu Nguyen });
5698aeffd91SJames Feist getPowerStatus(conn);
5708aeffd91SJames Feist getPostStatus(conn);
5716db8aae4SThu Nguyen getChassisStatus(conn);
5726714a25aSJames Feist }
57387d713abSJames Feist
setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection> & conn)57488cb29d2SZev Weiss void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
57588cb29d2SZev Weiss {
57688cb29d2SZev Weiss setupPowerMatchCallback(conn, [](PowerState, bool) {});
57788cb29d2SZev Weiss }
57888cb29d2SZev Weiss
57987d713abSJames Feist // replaces limits if MinReading and MaxReading are found.
findLimits(std::pair<double,double> & limits,const SensorBaseConfiguration * data)58087d713abSJames Feist void findLimits(std::pair<double, double>& limits,
58187d713abSJames Feist const SensorBaseConfiguration* data)
58287d713abSJames Feist {
5832049bd26SEd Tanous if (data == nullptr)
58487d713abSJames Feist {
58587d713abSJames Feist return;
58687d713abSJames Feist }
58787d713abSJames Feist auto maxFind = data->second.find("MaxReading");
58887d713abSJames Feist auto minFind = data->second.find("MinReading");
58987d713abSJames Feist
59087d713abSJames Feist if (minFind != data->second.end())
59187d713abSJames Feist {
5923eb82629SJames Feist limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
59387d713abSJames Feist }
59487d713abSJames Feist if (maxFind != data->second.end())
59587d713abSJames Feist {
5963eb82629SJames Feist limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
59787d713abSJames Feist }
59887d713abSJames Feist }
59982bac4c7SJames Feist
createAssociation(std::shared_ptr<sdbusplus::asio::dbus_interface> & association,const std::string & path)60082bac4c7SJames Feist void createAssociation(
60182bac4c7SJames Feist std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
60282bac4c7SJames Feist const std::string& path)
60382bac4c7SJames Feist {
60482bac4c7SJames Feist if (association)
60582bac4c7SJames Feist {
6062e466967SEd Tanous std::filesystem::path p(path);
607d2543f81SJames Feist
60882bac4c7SJames Feist std::vector<Association> associations;
6098a57ec09SEd Tanous associations.emplace_back("chassis", "all_sensors",
6108a57ec09SEd Tanous p.parent_path().string());
6112adc95cbSJames Feist association->register_property("Associations", associations);
61282bac4c7SJames Feist association->initialize();
61382bac4c7SJames Feist }
61482bac4c7SJames Feist }
6155580f2f7SCheng C Yang
setInventoryAssociation(const std::shared_ptr<sdbusplus::asio::dbus_interface> & association,const std::string & inventoryPath,const std::string & chassisPath)6165580f2f7SCheng C Yang void setInventoryAssociation(
6178a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
6188a28bf11SShounak Mitra const std::string& inventoryPath, const std::string& chassisPath)
6195580f2f7SCheng C Yang {
6205580f2f7SCheng C Yang if (association)
6215580f2f7SCheng C Yang {
6225580f2f7SCheng C Yang std::vector<Association> associations;
6238a28bf11SShounak Mitra associations.emplace_back("inventory", "sensors", inventoryPath);
6248a57ec09SEd Tanous associations.emplace_back("chassis", "all_sensors", chassisPath);
625c82213ccSAppaRao Puli
6262adc95cbSJames Feist association->register_property("Associations", associations);
6275580f2f7SCheng C Yang association->initialize();
6285580f2f7SCheng C Yang }
6295580f2f7SCheng C Yang }
6305580f2f7SCheng C Yang
findContainingChassis(std::string_view configParent,const GetSubTreeType & subtree)6318a28bf11SShounak Mitra std::optional<std::string> findContainingChassis(std::string_view configParent,
6328a28bf11SShounak Mitra const GetSubTreeType& subtree)
6338a28bf11SShounak Mitra {
6348a28bf11SShounak Mitra // A parent that is a chassis takes precedence
6358a28bf11SShounak Mitra for (const auto& [obj, services] : subtree)
6368a28bf11SShounak Mitra {
6378a28bf11SShounak Mitra if (obj == configParent)
6388a28bf11SShounak Mitra {
6398a28bf11SShounak Mitra return obj;
6408a28bf11SShounak Mitra }
6418a28bf11SShounak Mitra }
6428a28bf11SShounak Mitra
6438a28bf11SShounak Mitra // If the parent is not a chassis, the system chassis is used. This does not
6448a28bf11SShounak Mitra // work if there is more than one System, but we assume there is only one
6458a28bf11SShounak Mitra // today.
6468a28bf11SShounak Mitra for (const auto& [obj, services] : subtree)
6478a28bf11SShounak Mitra {
6488a28bf11SShounak Mitra for (const auto& [service, interfaces] : services)
6498a28bf11SShounak Mitra {
6508a28bf11SShounak Mitra if (std::find(interfaces.begin(), interfaces.end(),
6518a28bf11SShounak Mitra "xyz.openbmc_project.Inventory.Item.System") !=
6528a28bf11SShounak Mitra interfaces.end())
6538a28bf11SShounak Mitra {
6548a28bf11SShounak Mitra return obj;
6558a28bf11SShounak Mitra }
6568a28bf11SShounak Mitra }
6578a28bf11SShounak Mitra }
6588a28bf11SShounak Mitra return std::nullopt;
6598a28bf11SShounak Mitra }
6608a28bf11SShounak Mitra
createInventoryAssoc(const std::shared_ptr<sdbusplus::asio::connection> & conn,const std::shared_ptr<sdbusplus::asio::dbus_interface> & association,const std::string & path)6615580f2f7SCheng C Yang void createInventoryAssoc(
6628a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::connection>& conn,
6638a57ec09SEd Tanous const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
6645580f2f7SCheng C Yang const std::string& path)
6655580f2f7SCheng C Yang {
6665580f2f7SCheng C Yang if (!association)
6675580f2f7SCheng C Yang {
6685580f2f7SCheng C Yang return;
6695580f2f7SCheng C Yang }
670c82213ccSAppaRao Puli
6718a28bf11SShounak Mitra constexpr auto allInterfaces = std::to_array({
6728a28bf11SShounak Mitra "xyz.openbmc_project.Inventory.Item.Board",
6738a28bf11SShounak Mitra "xyz.openbmc_project.Inventory.Item.Chassis",
6748a28bf11SShounak Mitra });
6758a28bf11SShounak Mitra
6765580f2f7SCheng C Yang conn->async_method_call(
6775580f2f7SCheng C Yang [association, path](const boost::system::error_code ec,
6788a28bf11SShounak Mitra const GetSubTreeType& subtree) {
6792aaf7175SPatrick Williams // The parent of the config is always the inventory object, and may
6802aaf7175SPatrick Williams // be the associated chassis. If the parent is not itself a chassis
6812aaf7175SPatrick Williams // or board, the sensor is associated with the system chassis.
6822e466967SEd Tanous std::string parent =
6832e466967SEd Tanous std::filesystem::path(path).parent_path().string();
6845580f2f7SCheng C Yang if (ec)
6855580f2f7SCheng C Yang {
686c82213ccSAppaRao Puli // In case of error, set the default associations and
687c82213ccSAppaRao Puli // initialize the association Interface.
6888a28bf11SShounak Mitra setInventoryAssociation(association, parent, parent);
6895580f2f7SCheng C Yang return;
6905580f2f7SCheng C Yang }
6918a28bf11SShounak Mitra setInventoryAssociation(
6928a28bf11SShounak Mitra association, parent,
6938a28bf11SShounak Mitra findContainingChassis(parent, subtree).value_or(parent));
6945580f2f7SCheng C Yang },
6958a28bf11SShounak Mitra mapper::busName, mapper::path, mapper::interface, "GetSubTree",
6968a28bf11SShounak Mitra "/xyz/openbmc_project/inventory/system", 2, allInterfaces);
6975580f2f7SCheng C Yang }
69863f38669SZbigniew Kurzynski
readFile(const std::string & thresholdFile,const double & scaleFactor)69963f38669SZbigniew Kurzynski std::optional<double> readFile(const std::string& thresholdFile,
70063f38669SZbigniew Kurzynski const double& scaleFactor)
70163f38669SZbigniew Kurzynski {
70263f38669SZbigniew Kurzynski std::string line;
70363f38669SZbigniew Kurzynski std::ifstream labelFile(thresholdFile);
70463f38669SZbigniew Kurzynski if (labelFile.good())
70563f38669SZbigniew Kurzynski {
70663f38669SZbigniew Kurzynski std::getline(labelFile, line);
70763f38669SZbigniew Kurzynski labelFile.close();
70863f38669SZbigniew Kurzynski
70963f38669SZbigniew Kurzynski try
71063f38669SZbigniew Kurzynski {
71163f38669SZbigniew Kurzynski return std::stod(line) / scaleFactor;
71263f38669SZbigniew Kurzynski }
71363f38669SZbigniew Kurzynski catch (const std::invalid_argument&)
71463f38669SZbigniew Kurzynski {
71563f38669SZbigniew Kurzynski return std::nullopt;
71663f38669SZbigniew Kurzynski }
71763f38669SZbigniew Kurzynski }
71863f38669SZbigniew Kurzynski return std::nullopt;
71963f38669SZbigniew Kurzynski }
72063f38669SZbigniew Kurzynski
splitFileName(const std::filesystem::path & filePath)721*556e04b8SPatrick Williams std::optional<std::tuple<std::string, std::string, std::string>> splitFileName(
722*556e04b8SPatrick Williams const std::filesystem::path& filePath)
72363f38669SZbigniew Kurzynski {
72463f38669SZbigniew Kurzynski if (filePath.has_filename())
72563f38669SZbigniew Kurzynski {
72663f38669SZbigniew Kurzynski const auto fileName = filePath.filename().string();
72763f38669SZbigniew Kurzynski
728dd648008SZbigniew Kurzynski size_t numberPos = std::strcspn(fileName.c_str(), "1234567890");
729dd648008SZbigniew Kurzynski size_t itemPos = std::strcspn(fileName.c_str(), "_");
730dd648008SZbigniew Kurzynski
731dd648008SZbigniew Kurzynski if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos)
73263f38669SZbigniew Kurzynski {
733dd648008SZbigniew Kurzynski return std::make_optional(
734dd648008SZbigniew Kurzynski std::make_tuple(fileName.substr(0, numberPos),
735dd648008SZbigniew Kurzynski fileName.substr(numberPos, itemPos - numberPos),
736dd648008SZbigniew Kurzynski fileName.substr(itemPos + 1, fileName.size())));
73763f38669SZbigniew Kurzynski }
73863f38669SZbigniew Kurzynski }
73963f38669SZbigniew Kurzynski return std::nullopt;
74063f38669SZbigniew Kurzynski }
7411263c3daSBruce Lee
handleSpecialModeChange(const std::string & manufacturingModeStatus)74245f844acSArun P. Mohanan static void handleSpecialModeChange(const std::string& manufacturingModeStatus)
7431263c3daSBruce Lee {
7441263c3daSBruce Lee manufacturingMode = false;
74545f844acSArun P. Mohanan if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
7461263c3daSBruce Lee "SpecialMode.Modes.Manufacturing")
7471263c3daSBruce Lee {
7481263c3daSBruce Lee manufacturingMode = true;
7491263c3daSBruce Lee }
75074cffa88SEd Tanous if (validateUnsecureFeature == 1)
7511263c3daSBruce Lee {
75245f844acSArun P. Mohanan if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
7531263c3daSBruce Lee "SpecialMode.Modes.ValidationUnsecure")
7541263c3daSBruce Lee {
7551263c3daSBruce Lee manufacturingMode = true;
7561263c3daSBruce Lee }
7571263c3daSBruce Lee }
75845f844acSArun P. Mohanan }
75945f844acSArun P. Mohanan
setupManufacturingModeMatch(sdbusplus::asio::connection & conn)76045f844acSArun P. Mohanan void setupManufacturingModeMatch(sdbusplus::asio::connection& conn)
76145f844acSArun P. Mohanan {
76245f844acSArun P. Mohanan namespace rules = sdbusplus::bus::match::rules;
76345f844acSArun P. Mohanan static constexpr const char* specialModeInterface =
76445f844acSArun P. Mohanan "xyz.openbmc_project.Security.SpecialMode";
76545f844acSArun P. Mohanan
76645f844acSArun P. Mohanan const std::string filterSpecialModeIntfAdd =
76745f844acSArun P. Mohanan rules::interfacesAdded() +
76845f844acSArun P. Mohanan rules::argNpath(0, "/xyz/openbmc_project/security/special_mode");
76992f8f515SPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> specialModeIntfMatch =
770597e8423SPatrick Williams std::make_unique<sdbusplus::bus::match_t>(
771597e8423SPatrick Williams conn, filterSpecialModeIntfAdd, [](sdbusplus::message_t& m) {
77245f844acSArun P. Mohanan sdbusplus::message::object_path path;
77345f844acSArun P. Mohanan using PropertyMap =
7742aaf7175SPatrick Williams boost::container::flat_map<std::string,
7752aaf7175SPatrick Williams std::variant<std::string>>;
7762aaf7175SPatrick Williams boost::container::flat_map<std::string, PropertyMap>
7772aaf7175SPatrick Williams interfaceAdded;
77845f844acSArun P. Mohanan m.read(path, interfaceAdded);
77945f844acSArun P. Mohanan auto intfItr = interfaceAdded.find(specialModeInterface);
78045f844acSArun P. Mohanan if (intfItr == interfaceAdded.end())
78145f844acSArun P. Mohanan {
78245f844acSArun P. Mohanan return;
78345f844acSArun P. Mohanan }
78445f844acSArun P. Mohanan PropertyMap& propertyList = intfItr->second;
78545f844acSArun P. Mohanan auto itr = propertyList.find("SpecialMode");
78645f844acSArun P. Mohanan if (itr == propertyList.end())
78745f844acSArun P. Mohanan {
78845f844acSArun P. Mohanan std::cerr << "error getting SpecialMode property "
78945f844acSArun P. Mohanan << "\n";
79045f844acSArun P. Mohanan return;
79145f844acSArun P. Mohanan }
7922aaf7175SPatrick Williams auto* manufacturingModeStatus =
7932aaf7175SPatrick Williams std::get_if<std::string>(&itr->second);
79445f844acSArun P. Mohanan handleSpecialModeChange(*manufacturingModeStatus);
7951263c3daSBruce Lee });
7961263c3daSBruce Lee
79745f844acSArun P. Mohanan const std::string filterSpecialModeChange =
79845f844acSArun P. Mohanan rules::type::signal() + rules::member("PropertiesChanged") +
79945f844acSArun P. Mohanan rules::interface("org.freedesktop.DBus.Properties") +
80045f844acSArun P. Mohanan rules::argN(0, specialModeInterface);
80192f8f515SPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> specialModeChangeMatch =
8022aaf7175SPatrick Williams std::make_unique<sdbusplus::bus::match_t>(
8032aaf7175SPatrick Williams conn, filterSpecialModeChange, [](sdbusplus::message_t& m) {
80445f844acSArun P. Mohanan std::string interfaceName;
8052aaf7175SPatrick Williams boost::container::flat_map<std::string,
8062aaf7175SPatrick Williams std::variant<std::string>>
80745f844acSArun P. Mohanan propertiesChanged;
80845f844acSArun P. Mohanan
80945f844acSArun P. Mohanan m.read(interfaceName, propertiesChanged);
81045f844acSArun P. Mohanan auto itr = propertiesChanged.find("SpecialMode");
81145f844acSArun P. Mohanan if (itr == propertiesChanged.end())
81245f844acSArun P. Mohanan {
8131263c3daSBruce Lee return;
8141263c3daSBruce Lee }
8152aaf7175SPatrick Williams auto* manufacturingModeStatus =
8162aaf7175SPatrick Williams std::get_if<std::string>(&itr->second);
81745f844acSArun P. Mohanan handleSpecialModeChange(*manufacturingModeStatus);
81845f844acSArun P. Mohanan });
81945f844acSArun P. Mohanan
82045f844acSArun P. Mohanan conn.async_method_call(
82145f844acSArun P. Mohanan [](const boost::system::error_code ec,
82245f844acSArun P. Mohanan const std::variant<std::string>& getManufactMode) {
82345f844acSArun P. Mohanan if (ec)
82445f844acSArun P. Mohanan {
8252aaf7175SPatrick Williams std::cerr << "error getting SpecialMode status "
8262aaf7175SPatrick Williams << ec.message() << "\n";
82745f844acSArun P. Mohanan return;
82845f844acSArun P. Mohanan }
8292049bd26SEd Tanous const auto* manufacturingModeStatus =
83045f844acSArun P. Mohanan std::get_if<std::string>(&getManufactMode);
83145f844acSArun P. Mohanan handleSpecialModeChange(*manufacturingModeStatus);
83245f844acSArun P. Mohanan },
83345f844acSArun P. Mohanan "xyz.openbmc_project.SpecialMode",
83445f844acSArun P. Mohanan "/xyz/openbmc_project/security/special_mode",
83545f844acSArun P. Mohanan "org.freedesktop.DBus.Properties", "Get", specialModeInterface,
83645f844acSArun P. Mohanan "SpecialMode");
83745f844acSArun P. Mohanan }
8381263c3daSBruce Lee
getManufacturingMode()8391263c3daSBruce Lee bool getManufacturingMode()
8401263c3daSBruce Lee {
8411263c3daSBruce Lee return manufacturingMode;
8421263c3daSBruce Lee }
843214d9717SZev Weiss
844214d9717SZev Weiss std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
setupPropertiesChangedMatches(sdbusplus::asio::connection & bus,std::span<const char * const> types,const std::function<void (sdbusplus::message_t &)> & handler)845214d9717SZev Weiss setupPropertiesChangedMatches(
846214d9717SZev Weiss sdbusplus::asio::connection& bus, std::span<const char* const> types,
847214d9717SZev Weiss const std::function<void(sdbusplus::message_t&)>& handler)
848214d9717SZev Weiss {
849214d9717SZev Weiss std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches;
850214d9717SZev Weiss for (const char* type : types)
851214d9717SZev Weiss {
852214d9717SZev Weiss auto match = std::make_unique<sdbusplus::bus::match_t>(
853214d9717SZev Weiss static_cast<sdbusplus::bus_t&>(bus),
854214d9717SZev Weiss "type='signal',member='PropertiesChanged',path_namespace='" +
855054aad8fSZev Weiss std::string(inventoryPath) + "',arg0namespace='" +
856054aad8fSZev Weiss configInterfaceName(type) + "'",
857214d9717SZev Weiss handler);
858214d9717SZev Weiss matches.emplace_back(std::move(match));
859214d9717SZev Weiss }
860214d9717SZev Weiss return matches;
861214d9717SZev Weiss }
862dabd48ddSZev Weiss
863dabd48ddSZev Weiss std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
setupPropertiesChangedMatches(sdbusplus::asio::connection & bus,const I2CDeviceTypeMap & typeMap,const std::function<void (sdbusplus::message_t &)> & handler)864dabd48ddSZev Weiss setupPropertiesChangedMatches(
865dabd48ddSZev Weiss sdbusplus::asio::connection& bus, const I2CDeviceTypeMap& typeMap,
866dabd48ddSZev Weiss const std::function<void(sdbusplus::message_t&)>& handler)
867dabd48ddSZev Weiss {
868dabd48ddSZev Weiss std::vector<const char*> types;
869dabd48ddSZev Weiss types.reserve(typeMap.size());
870dabd48ddSZev Weiss for (const auto& [type, dt] : typeMap)
871dabd48ddSZev Weiss {
872dabd48ddSZev Weiss types.push_back(type.data());
873dabd48ddSZev Weiss }
874dabd48ddSZev Weiss return setupPropertiesChangedMatches(bus, {types}, handler);
875dabd48ddSZev Weiss }
876