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