blob: eb4620de890b588de4466b77856fe4ede67f1478 [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001/*
2// Copyright (c) 2017 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Bruce Lee1263c3d2021-06-04 15:16:33 +080017#include "dbus-sensor_config.h"
18
Zev Weissdabd48d2022-08-03 15:43:17 -070019#include <DeviceMgmt.hpp>
Ed Tanous8a57ec02020-10-09 12:46:52 -070020#include <Utils.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070021#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070022#include <sdbusplus/asio/connection.hpp>
23#include <sdbusplus/asio/object_server.hpp>
24#include <sdbusplus/bus/match.hpp>
25
James Feist24f02f22019-04-15 11:05:39 -070026#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070027#include <fstream>
Patrick Venture96e97db2019-10-31 13:44:38 -070028#include <memory>
James Feist6714a252018-09-10 15:26:18 -070029#include <regex>
Patrick Venture96e97db2019-10-31 13:44:38 -070030#include <stdexcept>
31#include <string>
32#include <utility>
33#include <variant>
34#include <vector>
James Feist6714a252018-09-10 15:26:18 -070035
James Feistcf3bce62019-01-08 10:07:19 -080036namespace fs = std::filesystem;
James Feist6714a252018-09-10 15:26:18 -070037
James Feist6ef20402019-01-07 16:45:08 -080038static bool powerStatusOn = false;
James Feistfc94b212019-02-06 16:14:51 -080039static bool biosHasPost = false;
Bruce Lee1263c3d2021-06-04 15:16:33 +080040static bool manufacturingMode = false;
Thu Nguyen6db8aae2022-10-04 08:12:48 +070041static bool chassisStatusOn = false;
James Feist58295ad2019-05-30 15:01:41 -070042
Patrick Williams92f8f512022-07-22 19:26:55 -050043static std::unique_ptr<sdbusplus::bus::match_t> powerMatch = nullptr;
44static std::unique_ptr<sdbusplus::bus::match_t> postMatch = nullptr;
Thu Nguyen6db8aae2022-10-04 08:12:48 +070045static std::unique_ptr<sdbusplus::bus::match_t> chassisMatch = nullptr;
James Feist71d31b22019-01-02 16:57:54 -080046
Jason Ling100c20b2020-08-11 14:50:33 -070047/**
48 * return the contents of a file
49 * @param[in] hwmonFile - the path to the file to read
50 * @return the contents of the file as a string or nullopt if the file could not
51 * be opened.
52 */
53
54std::optional<std::string> openAndRead(const std::string& hwmonFile)
55{
56 std::string fileVal;
57 std::ifstream fileStream(hwmonFile);
58 if (!fileStream.is_open())
59 {
60 return std::nullopt;
61 }
62 std::getline(fileStream, fileVal);
63 return fileVal;
64}
65
66/**
67 * given a hwmon temperature base name if valid return the full path else
68 * nullopt
69 * @param[in] directory - the hwmon sysfs directory
70 * @param[in] permitSet - a set of labels or hwmon basenames to permit. If this
71 * is empty then *everything* is permitted.
72 * @return a string to the full path of the file to create a temp sensor with or
73 * nullopt to indicate that no sensor should be created for this basename.
74 */
75std::optional<std::string>
76 getFullHwmonFilePath(const std::string& directory,
77 const std::string& hwmonBaseName,
78 const std::set<std::string>& permitSet)
79{
80 std::optional<std::string> result;
81 std::string filename;
82 if (permitSet.empty())
83 {
84 result = directory + "/" + hwmonBaseName + "_input";
85 return result;
86 }
87 filename = directory + "/" + hwmonBaseName + "_label";
88 auto searchVal = openAndRead(filename);
89 if (!searchVal)
90 {
91 /* if the hwmon temp doesn't have a corresponding label file
92 * then use the hwmon temperature base name
93 */
94 searchVal = hwmonBaseName;
95 }
96 if (permitSet.find(*searchVal) != permitSet.end())
97 {
98 result = directory + "/" + hwmonBaseName + "_input";
99 }
100 return result;
101}
102
103/**
104 * retrieve a set of basenames and labels to allow sensor creation for.
105 * @param[in] config - a map representing the configuration for a specific
106 * device
107 * @return a set of basenames and labels to allow sensor creation for. An empty
108 * set indicates that everything is permitted.
109 */
110std::set<std::string> getPermitSet(const SensorBaseConfigMap& config)
111{
112 auto permitAttribute = config.find("Labels");
113 std::set<std::string> permitSet;
114 if (permitAttribute != config.end())
115 {
116 try
117 {
118 auto val =
119 std::get<std::vector<std::string>>(permitAttribute->second);
120
121 permitSet.insert(std::make_move_iterator(val.begin()),
122 std::make_move_iterator(val.end()));
123 }
124 catch (const std::bad_variant_access& err)
125 {
126 std::cerr << err.what()
127 << ":PermitList does not contain a list, wrong "
128 "variant type.\n";
129 }
130 }
131 return permitSet;
132}
133
James Feist6714a252018-09-10 15:26:18 -0700134bool getSensorConfiguration(
135 const std::string& type,
136 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700137 ManagedObjectType& resp)
138{
139 return getSensorConfiguration(type, dbusConnection, resp, false);
140}
141
142bool getSensorConfiguration(
143 const std::string& type,
144 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
James Feist6714a252018-09-10 15:26:18 -0700145 ManagedObjectType& resp, bool useCache)
146{
147 static ManagedObjectType managedObj;
Zev Weiss054aad82022-08-18 01:37:34 -0700148 std::string typeIntf = configInterfaceName(type);
James Feist6714a252018-09-10 15:26:18 -0700149
150 if (!useCache)
151 {
152 managedObj.clear();
Patrick Williams92f8f512022-07-22 19:26:55 -0500153 sdbusplus::message_t getManagedObjects =
James Feist6714a252018-09-10 15:26:18 -0700154 dbusConnection->new_method_call(
JeffLin2c5a1f22022-10-05 15:19:09 +0800155 entityManagerName, "/xyz/openbmc_project/inventory",
156 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6714a252018-09-10 15:26:18 -0700157 try
158 {
Patrick Williams92f8f512022-07-22 19:26:55 -0500159 sdbusplus::message_t reply =
James Feist6714a252018-09-10 15:26:18 -0700160 dbusConnection->call(getManagedObjects);
Yoo, Jae Hyun0e022052018-10-15 14:05:37 -0700161 reply.read(managedObj);
James Feist6714a252018-09-10 15:26:18 -0700162 }
Patrick Williams92f8f512022-07-22 19:26:55 -0500163 catch (const sdbusplus::exception_t& e)
James Feist6714a252018-09-10 15:26:18 -0700164 {
Jason Ling5747fab2019-10-02 16:46:23 -0700165 std::cerr << "While calling GetManagedObjects on service:"
166 << entityManagerName << " exception name:" << e.name()
167 << "and description:" << e.description()
168 << " was thrown\n";
James Feist6714a252018-09-10 15:26:18 -0700169 return false;
170 }
171 }
172 for (const auto& pathPair : managedObj)
173 {
Zev Weissfd3d5f72022-08-12 18:21:02 -0700174 for (const auto& [intf, cfg] : pathPair.second)
James Feist6714a252018-09-10 15:26:18 -0700175 {
Zev Weiss054aad82022-08-18 01:37:34 -0700176 if (intf.starts_with(typeIntf))
James Feist6714a252018-09-10 15:26:18 -0700177 {
Zev Weiss79d8aef2022-08-17 21:45:44 -0700178 resp.emplace(pathPair);
James Feist6714a252018-09-10 15:26:18 -0700179 break;
180 }
181 }
James Feist6714a252018-09-10 15:26:18 -0700182 }
183 return true;
184}
185
Lei YU6a4e9732021-10-20 13:27:34 +0800186bool findFiles(const fs::path& dirPath, std::string_view matchString,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700187 std::vector<fs::path>& foundPaths, int symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700188{
Lei YU6a4e9732021-10-20 13:27:34 +0800189 std::error_code ec;
190 if (!fs::exists(dirPath, ec))
Ed Tanous8a57ec02020-10-09 12:46:52 -0700191 {
James Feist6714a252018-09-10 15:26:18 -0700192 return false;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700193 }
James Feist6714a252018-09-10 15:26:18 -0700194
Lei YU6a4e9732021-10-20 13:27:34 +0800195 std::vector<std::regex> matchPieces;
196
197 size_t pos = 0;
198 std::string token;
199 // Generate the regex expressions list from the match we were given
200 while ((pos = matchString.find('/')) != std::string::npos)
201 {
202 token = matchString.substr(0, pos);
203 matchPieces.emplace_back(token);
204 matchString.remove_prefix(pos + 1);
205 }
206 matchPieces.emplace_back(std::string{matchString});
207
208 // Check if the match string contains directories, and skip the match of
209 // subdirectory if not
210 if (matchPieces.size() <= 1)
211 {
212 std::regex search(std::string{matchString});
213 std::smatch match;
214 for (auto p = fs::recursive_directory_iterator(
215 dirPath, fs::directory_options::follow_directory_symlink);
216 p != fs::recursive_directory_iterator(); ++p)
217 {
218 std::string path = p->path().string();
219 if (!is_directory(*p))
220 {
221 if (std::regex_search(path, match, search))
222 {
223 foundPaths.emplace_back(p->path());
224 }
225 }
226 if (p.depth() >= symlinkDepth)
227 {
228 p.disable_recursion_pending();
229 }
230 }
231 return true;
232 }
233
234 // The match string contains directories, verify each level of sub
235 // directories
Ed Tanous8a57ec02020-10-09 12:46:52 -0700236 for (auto p = fs::recursive_directory_iterator(
237 dirPath, fs::directory_options::follow_directory_symlink);
238 p != fs::recursive_directory_iterator(); ++p)
James Feist6714a252018-09-10 15:26:18 -0700239 {
Lei YU6a4e9732021-10-20 13:27:34 +0800240 std::vector<std::regex>::iterator matchPiece = matchPieces.begin();
241 fs::path::iterator pathIt = p->path().begin();
242 for (const fs::path& dir : dirPath)
243 {
244 if (dir.empty())
245 {
246 // When the path ends with '/', it gets am empty path
247 // skip such case.
248 break;
249 }
250 pathIt++;
251 }
252
253 while (pathIt != p->path().end())
254 {
255 // Found a path deeper than match.
256 if (matchPiece == matchPieces.end())
257 {
258 p.disable_recursion_pending();
259 break;
260 }
261 std::smatch match;
262 std::string component = pathIt->string();
263 std::regex regexPiece(*matchPiece);
264 if (!std::regex_match(component, match, regexPiece))
265 {
266 // path prefix doesn't match, no need to iterate further
267 p.disable_recursion_pending();
268 break;
269 }
270 matchPiece++;
271 pathIt++;
272 }
273
Ed Tanous8a57ec02020-10-09 12:46:52 -0700274 if (!is_directory(*p))
James Feist6714a252018-09-10 15:26:18 -0700275 {
Lei YU6a4e9732021-10-20 13:27:34 +0800276 if (matchPiece == matchPieces.end())
Ed Tanous8a57ec02020-10-09 12:46:52 -0700277 {
278 foundPaths.emplace_back(p->path());
279 }
James Feist6714a252018-09-10 15:26:18 -0700280 }
Lei YU6a4e9732021-10-20 13:27:34 +0800281
Ed Tanous8a57ec02020-10-09 12:46:52 -0700282 if (p.depth() >= symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700283 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700284 p.disable_recursion_pending();
James Feist6714a252018-09-10 15:26:18 -0700285 }
286 }
287 return true;
288}
289
James Feist71d31b22019-01-02 16:57:54 -0800290bool isPowerOn(void)
James Feist6714a252018-09-10 15:26:18 -0700291{
James Feist71d31b22019-01-02 16:57:54 -0800292 if (!powerMatch)
James Feist6714a252018-09-10 15:26:18 -0700293 {
James Feist71d31b22019-01-02 16:57:54 -0800294 throw std::runtime_error("Power Match Not Created");
James Feist6714a252018-09-10 15:26:18 -0700295 }
James Feist71d31b22019-01-02 16:57:54 -0800296 return powerStatusOn;
297}
298
James Feistfc94b212019-02-06 16:14:51 -0800299bool hasBiosPost(void)
300{
James Feist52497fd2019-06-07 13:01:33 -0700301 if (!postMatch)
James Feistfc94b212019-02-06 16:14:51 -0800302 {
James Feist52497fd2019-06-07 13:01:33 -0700303 throw std::runtime_error("Post Match Not Created");
James Feistfc94b212019-02-06 16:14:51 -0800304 }
305 return biosHasPost;
306}
307
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700308bool isChassisOn(void)
309{
310 if (!chassisMatch)
311 {
312 throw std::runtime_error("Chassis On Match Not Created");
313 }
314 return chassisStatusOn;
315}
316
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000317bool readingStateGood(const PowerState& powerState)
318{
319 if (powerState == PowerState::on && !isPowerOn())
320 {
321 return false;
322 }
323 if (powerState == PowerState::biosPost && (!hasBiosPost() || !isPowerOn()))
324 {
325 return false;
326 }
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700327 if (powerState == PowerState::chassisOn && !isChassisOn())
328 {
329 return false;
330 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000331
332 return true;
333}
334
James Feist8aeffd92020-09-14 12:08:28 -0700335static void
336 getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
337 size_t retries = 2)
338{
339 conn->async_method_call(
340 [conn, retries](boost::system::error_code ec,
341 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700342 if (ec)
343 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700344 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700345 {
Ed Tanousbb679322022-05-16 16:10:00 -0700346 auto timer = std::make_shared<boost::asio::steady_timer>(
347 conn->get_io_context());
348 timer->expires_after(std::chrono::seconds(15));
349 timer->async_wait(
350 [timer, conn, retries](boost::system::error_code) {
351 getPowerStatus(conn, retries - 1);
352 });
James Feist8aeffd92020-09-14 12:08:28 -0700353 return;
354 }
Ed Tanousbb679322022-05-16 16:10:00 -0700355
356 // we commonly come up before power control, we'll capture the
357 // property change later
358 std::cerr << "error getting power status " << ec.message() << "\n";
359 return;
360 }
Zev Weiss6c106d62022-08-17 20:50:00 -0700361 powerStatusOn = std::get<std::string>(state).ends_with(".Running");
James Feist8aeffd92020-09-14 12:08:28 -0700362 },
363 power::busname, power::path, properties::interface, properties::get,
364 power::interface, power::property);
365}
366
367static void
368 getPostStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
369 size_t retries = 2)
370{
371 conn->async_method_call(
372 [conn, retries](boost::system::error_code ec,
373 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700374 if (ec)
375 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700376 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700377 {
Ed Tanousbb679322022-05-16 16:10:00 -0700378 auto timer = std::make_shared<boost::asio::steady_timer>(
379 conn->get_io_context());
380 timer->expires_after(std::chrono::seconds(15));
381 timer->async_wait(
382 [timer, conn, retries](boost::system::error_code) {
383 getPostStatus(conn, retries - 1);
384 });
James Feist8aeffd92020-09-14 12:08:28 -0700385 return;
386 }
Ed Tanousbb679322022-05-16 16:10:00 -0700387 // we commonly come up before power control, we'll capture the
388 // property change later
389 std::cerr << "error getting post status " << ec.message() << "\n";
390 return;
391 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700392 const auto& value = std::get<std::string>(state);
Ed Tanousbb679322022-05-16 16:10:00 -0700393 biosHasPost = (value != "Inactive") &&
394 (value != "xyz.openbmc_project.State.OperatingSystem."
395 "Status.OSStatus.Inactive");
James Feist8aeffd92020-09-14 12:08:28 -0700396 },
397 post::busname, post::path, properties::interface, properties::get,
398 post::interface, post::property);
399}
400
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700401static void
402 getChassisStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
403 size_t retries = 2)
404{
405 conn->async_method_call(
406 [conn, retries](boost::system::error_code ec,
407 const std::variant<std::string>& state) {
408 if (ec)
409 {
410 if (retries != 0U)
411 {
412 auto timer = std::make_shared<boost::asio::steady_timer>(
413 conn->get_io_context());
414 timer->expires_after(std::chrono::seconds(15));
415 timer->async_wait(
416 [timer, conn, retries](boost::system::error_code) {
417 getChassisStatus(conn, retries - 1);
418 });
419 return;
420 }
421
422 // we commonly come up before power control, we'll capture the
423 // property change later
424 std::cerr << "error getting chassis power status " << ec.message()
425 << "\n";
426 return;
427 }
428 chassisStatusOn = std::get<std::string>(state).ends_with(chassis::sOn);
429 },
430 chassis::busname, chassis::path, properties::interface, properties::get,
431 chassis::interface, chassis::property);
432}
433
Zev Weiss88cb29d2022-05-09 03:46:15 +0000434void setupPowerMatchCallback(
435 const std::shared_ptr<sdbusplus::asio::connection>& conn,
436 std::function<void(PowerState type, bool state)>&& hostStatusCallback)
James Feist71d31b22019-01-02 16:57:54 -0800437{
James Feist43d32fe2019-09-04 10:35:20 -0700438 static boost::asio::steady_timer timer(conn->get_io_context());
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700439 static boost::asio::steady_timer timerChassisOn(conn->get_io_context());
James Feist6714a252018-09-10 15:26:18 -0700440 // create a match for powergood changes, first time do a method call to
James Feist71d31b22019-01-02 16:57:54 -0800441 // cache the correct value
James Feist52497fd2019-06-07 13:01:33 -0700442 if (powerMatch)
443 {
444 return;
445 }
James Feist6714a252018-09-10 15:26:18 -0700446
Patrick Williams92f8f512022-07-22 19:26:55 -0500447 powerMatch = std::make_unique<sdbusplus::bus::match_t>(
448 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700449 "type='signal',interface='" + std::string(properties::interface) +
450 "',path='" + std::string(power::path) + "',arg0='" +
451 std::string(power::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000452 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700453 std::string objectName;
454 boost::container::flat_map<std::string, std::variant<std::string>>
455 values;
456 message.read(objectName, values);
457 auto findState = values.find(power::property);
458 if (findState != values.end())
459 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700460 bool on =
461 std::get<std::string>(findState->second).ends_with(".Running");
Ed Tanousbb679322022-05-16 16:10:00 -0700462 if (!on)
James Feist6714a252018-09-10 15:26:18 -0700463 {
Ed Tanousbb679322022-05-16 16:10:00 -0700464 timer.cancel();
465 powerStatusOn = false;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000466 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700467 return;
468 }
469 // on comes too quickly
470 timer.expires_after(std::chrono::seconds(10));
Zev Weiss88cb29d2022-05-09 03:46:15 +0000471 timer.async_wait(
472 [hostStatusCallback](boost::system::error_code ec) {
Ed Tanousbb679322022-05-16 16:10:00 -0700473 if (ec == boost::asio::error::operation_aborted)
James Feist43d32fe2019-09-04 10:35:20 -0700474 {
James Feist43d32fe2019-09-04 10:35:20 -0700475 return;
476 }
Ed Tanousbb679322022-05-16 16:10:00 -0700477 if (ec)
478 {
479 std::cerr << "Timer error " << ec.message() << "\n";
480 return;
481 }
482 powerStatusOn = true;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000483 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700484 });
485 }
James Feist52497fd2019-06-07 13:01:33 -0700486 });
487
Patrick Williams92f8f512022-07-22 19:26:55 -0500488 postMatch = std::make_unique<sdbusplus::bus::match_t>(
489 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700490 "type='signal',interface='" + std::string(properties::interface) +
491 "',path='" + std::string(post::path) + "',arg0='" +
492 std::string(post::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000493 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700494 std::string objectName;
495 boost::container::flat_map<std::string, std::variant<std::string>>
496 values;
497 message.read(objectName, values);
498 auto findState = values.find(post::property);
499 if (findState != values.end())
500 {
501 auto& value = std::get<std::string>(findState->second);
502 biosHasPost = (value != "Inactive") &&
503 (value != "xyz.openbmc_project.State.OperatingSystem."
504 "Status.OSStatus.Inactive");
Zev Weiss88cb29d2022-05-09 03:46:15 +0000505 hostStatusCallback(PowerState::biosPost, biosHasPost);
Ed Tanousbb679322022-05-16 16:10:00 -0700506 }
James Feist52497fd2019-06-07 13:01:33 -0700507 });
James Feistfc94b212019-02-06 16:14:51 -0800508
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700509 chassisMatch = std::make_unique<sdbusplus::bus::match_t>(
510 static_cast<sdbusplus::bus_t&>(*conn),
511 "type='signal',interface='" + std::string(properties::interface) +
512 "',path='" + std::string(chassis::path) + "',arg0='" +
513 std::string(chassis::interface) + "'",
514 [hostStatusCallback](sdbusplus::message_t& message) {
515 std::string objectName;
516 boost::container::flat_map<std::string, std::variant<std::string>>
517 values;
518 message.read(objectName, values);
519 auto findState = values.find(chassis::property);
520 if (findState != values.end())
521 {
522 bool on = std::get<std::string>(findState->second)
523 .ends_with(chassis::sOn);
524 if (!on)
525 {
526 timerChassisOn.cancel();
527 chassisStatusOn = false;
528 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
529 return;
530 }
531 // on comes too quickly
532 timerChassisOn.expires_after(std::chrono::seconds(10));
533 timerChassisOn.async_wait(
534 [hostStatusCallback](boost::system::error_code ec) {
535 if (ec == boost::asio::error::operation_aborted)
536 {
537 return;
538 }
539 if (ec)
540 {
541 std::cerr << "Timer error " << ec.message() << "\n";
542 return;
543 }
544 chassisStatusOn = true;
545 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
546 });
547 }
548 });
James Feist8aeffd92020-09-14 12:08:28 -0700549 getPowerStatus(conn);
550 getPostStatus(conn);
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700551 getChassisStatus(conn);
James Feist3f0e8762018-11-27 11:30:42 -0800552}
James Feist87d713a2018-12-06 16:06:24 -0800553
Zev Weiss88cb29d2022-05-09 03:46:15 +0000554void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
555{
556 setupPowerMatchCallback(conn, [](PowerState, bool) {});
557}
558
James Feist87d713a2018-12-06 16:06:24 -0800559// replaces limits if MinReading and MaxReading are found.
560void findLimits(std::pair<double, double>& limits,
561 const SensorBaseConfiguration* data)
562{
Ed Tanous2049bd22022-07-09 07:20:26 -0700563 if (data == nullptr)
James Feist87d713a2018-12-06 16:06:24 -0800564 {
565 return;
566 }
567 auto maxFind = data->second.find("MaxReading");
568 auto minFind = data->second.find("MinReading");
569
570 if (minFind != data->second.end())
571 {
James Feist3eb82622019-02-08 13:10:22 -0800572 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800573 }
574 if (maxFind != data->second.end())
575 {
James Feist3eb82622019-02-08 13:10:22 -0800576 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800577 }
James Feistfc94b212019-02-06 16:14:51 -0800578}
James Feist82bac4c2019-03-11 11:16:53 -0700579
580void createAssociation(
581 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
582 const std::string& path)
583{
584 if (association)
585 {
Lei YU6a4e9732021-10-20 13:27:34 +0800586 fs::path p(path);
James Feistd2543f82019-04-09 11:10:06 -0700587
James Feist82bac4c2019-03-11 11:16:53 -0700588 std::vector<Association> associations;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700589 associations.emplace_back("chassis", "all_sensors",
590 p.parent_path().string());
James Feist2adc95c2019-09-30 14:55:28 -0700591 association->register_property("Associations", associations);
James Feist82bac4c2019-03-11 11:16:53 -0700592 association->initialize();
593 }
James Feist43d32fe2019-09-04 10:35:20 -0700594}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800595
596void setInventoryAssociation(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700597 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
AppaRao Pulic82213c2020-02-27 01:24:58 +0530598 const std::string& path,
599 const std::vector<std::string>& chassisPaths = std::vector<std::string>())
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800600{
601 if (association)
602 {
Lei YU6a4e9732021-10-20 13:27:34 +0800603 fs::path p(path);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800604 std::vector<Association> associations;
AppaRao Pulic82213c2020-02-27 01:24:58 +0530605 std::string objPath(p.parent_path().string());
606
Ed Tanous8a57ec02020-10-09 12:46:52 -0700607 associations.emplace_back("inventory", "sensors", objPath);
608 associations.emplace_back("chassis", "all_sensors", objPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530609
610 for (const std::string& chassisPath : chassisPaths)
611 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700612 associations.emplace_back("chassis", "all_sensors", chassisPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530613 }
614
James Feist2adc95c2019-09-30 14:55:28 -0700615 association->register_property("Associations", associations);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800616 association->initialize();
617 }
618}
619
620void createInventoryAssoc(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700621 const std::shared_ptr<sdbusplus::asio::connection>& conn,
622 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800623 const std::string& path)
624{
625 if (!association)
626 {
627 return;
628 }
AppaRao Pulic82213c2020-02-27 01:24:58 +0530629
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800630 conn->async_method_call(
631 [association, path](const boost::system::error_code ec,
AppaRao Pulic82213c2020-02-27 01:24:58 +0530632 const std::vector<std::string>& invSysObjPaths) {
Ed Tanousbb679322022-05-16 16:10:00 -0700633 if (ec)
634 {
635 // In case of error, set the default associations and
636 // initialize the association Interface.
637 setInventoryAssociation(association, path);
638 return;
639 }
640 setInventoryAssociation(association, path, invSysObjPaths);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800641 },
642 mapper::busName, mapper::path, mapper::interface, "GetSubTreePaths",
643 "/xyz/openbmc_project/inventory/system", 2,
644 std::array<std::string, 1>{
645 "xyz.openbmc_project.Inventory.Item.System"});
646}
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200647
648std::optional<double> readFile(const std::string& thresholdFile,
649 const double& scaleFactor)
650{
651 std::string line;
652 std::ifstream labelFile(thresholdFile);
653 if (labelFile.good())
654 {
655 std::getline(labelFile, line);
656 labelFile.close();
657
658 try
659 {
660 return std::stod(line) / scaleFactor;
661 }
662 catch (const std::invalid_argument&)
663 {
664 return std::nullopt;
665 }
666 }
667 return std::nullopt;
668}
669
670std::optional<std::tuple<std::string, std::string, std::string>>
Lei YU6a4e9732021-10-20 13:27:34 +0800671 splitFileName(const fs::path& filePath)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200672{
673 if (filePath.has_filename())
674 {
675 const auto fileName = filePath.filename().string();
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200676
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200677 size_t numberPos = std::strcspn(fileName.c_str(), "1234567890");
678 size_t itemPos = std::strcspn(fileName.c_str(), "_");
679
680 if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200681 {
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200682 return std::make_optional(
683 std::make_tuple(fileName.substr(0, numberPos),
684 fileName.substr(numberPos, itemPos - numberPos),
685 fileName.substr(itemPos + 1, fileName.size())));
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200686 }
687 }
688 return std::nullopt;
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200689}
Bruce Lee1263c3d2021-06-04 15:16:33 +0800690
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530691static void handleSpecialModeChange(const std::string& manufacturingModeStatus)
692{
693 manufacturingMode = false;
694 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
695 "SpecialMode.Modes.Manufacturing")
696 {
697 manufacturingMode = true;
698 }
Ed Tanous74cffa82022-01-25 13:00:28 -0800699 if (validateUnsecureFeature == 1)
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530700 {
701 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
702 "SpecialMode.Modes.ValidationUnsecure")
703 {
704 manufacturingMode = true;
705 }
706 }
707}
708
Bruce Lee1263c3d2021-06-04 15:16:33 +0800709void setupManufacturingModeMatch(sdbusplus::asio::connection& conn)
710{
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530711 namespace rules = sdbusplus::bus::match::rules;
712 static constexpr const char* specialModeInterface =
713 "xyz.openbmc_project.Security.SpecialMode";
714
715 const std::string filterSpecialModeIntfAdd =
716 rules::interfacesAdded() +
717 rules::argNpath(0, "/xyz/openbmc_project/security/special_mode");
Patrick Williams92f8f512022-07-22 19:26:55 -0500718 static std::unique_ptr<sdbusplus::bus::match_t> specialModeIntfMatch =
719 std::make_unique<sdbusplus::bus::match_t>(conn,
720 filterSpecialModeIntfAdd,
721 [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700722 sdbusplus::message::object_path path;
723 using PropertyMap =
724 boost::container::flat_map<std::string, std::variant<std::string>>;
725 boost::container::flat_map<std::string, PropertyMap> interfaceAdded;
726 m.read(path, interfaceAdded);
727 auto intfItr = interfaceAdded.find(specialModeInterface);
728 if (intfItr == interfaceAdded.end())
729 {
730 return;
731 }
732 PropertyMap& propertyList = intfItr->second;
733 auto itr = propertyList.find("SpecialMode");
734 if (itr == propertyList.end())
735 {
736 std::cerr << "error getting SpecialMode property "
737 << "\n";
738 return;
739 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700740 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700741 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams92f8f512022-07-22 19:26:55 -0500742 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800743
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530744 const std::string filterSpecialModeChange =
745 rules::type::signal() + rules::member("PropertiesChanged") +
746 rules::interface("org.freedesktop.DBus.Properties") +
747 rules::argN(0, specialModeInterface);
Patrick Williams92f8f512022-07-22 19:26:55 -0500748 static std::unique_ptr<sdbusplus::bus::match_t> specialModeChangeMatch =
749 std::make_unique<sdbusplus::bus::match_t>(conn, filterSpecialModeChange,
750 [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700751 std::string interfaceName;
752 boost::container::flat_map<std::string, std::variant<std::string>>
753 propertiesChanged;
Bruce Lee1263c3d2021-06-04 15:16:33 +0800754
Ed Tanousbb679322022-05-16 16:10:00 -0700755 m.read(interfaceName, propertiesChanged);
756 auto itr = propertiesChanged.find("SpecialMode");
757 if (itr == propertiesChanged.end())
758 {
759 return;
760 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700761 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700762 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams92f8f512022-07-22 19:26:55 -0500763 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800764
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530765 conn.async_method_call(
766 [](const boost::system::error_code ec,
767 const std::variant<std::string>& getManufactMode) {
Ed Tanousbb679322022-05-16 16:10:00 -0700768 if (ec)
769 {
770 std::cerr << "error getting SpecialMode status " << ec.message()
771 << "\n";
772 return;
773 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700774 const auto* manufacturingModeStatus =
Ed Tanousbb679322022-05-16 16:10:00 -0700775 std::get_if<std::string>(&getManufactMode);
776 handleSpecialModeChange(*manufacturingModeStatus);
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530777 },
778 "xyz.openbmc_project.SpecialMode",
779 "/xyz/openbmc_project/security/special_mode",
780 "org.freedesktop.DBus.Properties", "Get", specialModeInterface,
781 "SpecialMode");
Bruce Lee1263c3d2021-06-04 15:16:33 +0800782}
783
784bool getManufacturingMode()
785{
786 return manufacturingMode;
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000787}
Zev Weiss214d9712022-08-12 12:54:31 -0700788
789std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
790 setupPropertiesChangedMatches(
791 sdbusplus::asio::connection& bus, std::span<const char* const> types,
792 const std::function<void(sdbusplus::message_t&)>& handler)
793{
794 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches;
795 for (const char* type : types)
796 {
797 auto match = std::make_unique<sdbusplus::bus::match_t>(
798 static_cast<sdbusplus::bus_t&>(bus),
799 "type='signal',member='PropertiesChanged',path_namespace='" +
Zev Weiss054aad82022-08-18 01:37:34 -0700800 std::string(inventoryPath) + "',arg0namespace='" +
801 configInterfaceName(type) + "'",
Zev Weiss214d9712022-08-12 12:54:31 -0700802 handler);
803 matches.emplace_back(std::move(match));
804 }
805 return matches;
806}
Zev Weissdabd48d2022-08-03 15:43:17 -0700807
808std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
809 setupPropertiesChangedMatches(
810 sdbusplus::asio::connection& bus, const I2CDeviceTypeMap& typeMap,
811 const std::function<void(sdbusplus::message_t&)>& handler)
812{
813 std::vector<const char*> types;
814 types.reserve(typeMap.size());
815 for (const auto& [type, dt] : typeMap)
816 {
817 types.push_back(type.data());
818 }
819 return setupPropertiesChangedMatches(bus, {types}, handler);
820}