xref: /openbmc/dbus-sensors/src/Utils.cpp (revision 556e04b8f374a9eb8cf32bf0e36ac46c14873eba)
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