blob: 357d1436c361b5dc524a5475bb7035061843b608 [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
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103017#include "Utils.hpp"
18
Bruce Lee1263c3d2021-06-04 15:16:33 +080019#include "dbus-sensor_config.h"
20
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103021#include "DeviceMgmt.hpp"
22
Patrick Venture96e97db2019-10-31 13:44:38 -070023#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070024#include <sdbusplus/asio/connection.hpp>
25#include <sdbusplus/asio/object_server.hpp>
26#include <sdbusplus/bus/match.hpp>
27
Andrew Jefferye98adf52023-10-11 23:23:18 +103028#include <charconv>
James Feist24f02f22019-04-15 11:05:39 -070029#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070030#include <fstream>
Patrick Venture96e97db2019-10-31 13:44:38 -070031#include <memory>
James Feist6714a252018-09-10 15:26:18 -070032#include <regex>
Patrick Venture96e97db2019-10-31 13:44:38 -070033#include <stdexcept>
34#include <string>
35#include <utility>
36#include <variant>
37#include <vector>
James Feist6714a252018-09-10 15:26:18 -070038
James Feistcf3bce62019-01-08 10:07:19 -080039namespace fs = std::filesystem;
James Feist6714a252018-09-10 15:26:18 -070040
James Feist6ef20402019-01-07 16:45:08 -080041static bool powerStatusOn = false;
James Feistfc94b212019-02-06 16:14:51 -080042static bool biosHasPost = false;
Bruce Lee1263c3d2021-06-04 15:16:33 +080043static bool manufacturingMode = false;
Thu Nguyen6db8aae2022-10-04 08:12:48 +070044static bool chassisStatusOn = false;
James Feist58295ad2019-05-30 15:01:41 -070045
Patrick Williams92f8f512022-07-22 19:26:55 -050046static std::unique_ptr<sdbusplus::bus::match_t> powerMatch = nullptr;
47static std::unique_ptr<sdbusplus::bus::match_t> postMatch = nullptr;
Thu Nguyen6db8aae2022-10-04 08:12:48 +070048static std::unique_ptr<sdbusplus::bus::match_t> chassisMatch = nullptr;
James Feist71d31b22019-01-02 16:57:54 -080049
Jason Ling100c20b2020-08-11 14:50:33 -070050/**
51 * return the contents of a file
52 * @param[in] hwmonFile - the path to the file to read
53 * @return the contents of the file as a string or nullopt if the file could not
54 * be opened.
55 */
56
57std::optional<std::string> openAndRead(const std::string& hwmonFile)
58{
59 std::string fileVal;
60 std::ifstream fileStream(hwmonFile);
61 if (!fileStream.is_open())
62 {
63 return std::nullopt;
64 }
65 std::getline(fileStream, fileVal);
66 return fileVal;
67}
68
69/**
70 * given a hwmon temperature base name if valid return the full path else
71 * nullopt
72 * @param[in] directory - the hwmon sysfs directory
73 * @param[in] permitSet - a set of labels or hwmon basenames to permit. If this
74 * is empty then *everything* is permitted.
75 * @return a string to the full path of the file to create a temp sensor with or
76 * nullopt to indicate that no sensor should be created for this basename.
77 */
78std::optional<std::string>
79 getFullHwmonFilePath(const std::string& directory,
80 const std::string& hwmonBaseName,
81 const std::set<std::string>& permitSet)
82{
83 std::optional<std::string> result;
84 std::string filename;
85 if (permitSet.empty())
86 {
87 result = directory + "/" + hwmonBaseName + "_input";
88 return result;
89 }
90 filename = directory + "/" + hwmonBaseName + "_label";
91 auto searchVal = openAndRead(filename);
92 if (!searchVal)
93 {
94 /* if the hwmon temp doesn't have a corresponding label file
95 * then use the hwmon temperature base name
96 */
97 searchVal = hwmonBaseName;
98 }
99 if (permitSet.find(*searchVal) != permitSet.end())
100 {
101 result = directory + "/" + hwmonBaseName + "_input";
102 }
103 return result;
104}
105
106/**
107 * retrieve a set of basenames and labels to allow sensor creation for.
108 * @param[in] config - a map representing the configuration for a specific
109 * device
110 * @return a set of basenames and labels to allow sensor creation for. An empty
111 * set indicates that everything is permitted.
112 */
113std::set<std::string> getPermitSet(const SensorBaseConfigMap& config)
114{
115 auto permitAttribute = config.find("Labels");
116 std::set<std::string> permitSet;
117 if (permitAttribute != config.end())
118 {
119 try
120 {
121 auto val =
122 std::get<std::vector<std::string>>(permitAttribute->second);
123
124 permitSet.insert(std::make_move_iterator(val.begin()),
125 std::make_move_iterator(val.end()));
126 }
127 catch (const std::bad_variant_access& err)
128 {
129 std::cerr << err.what()
130 << ":PermitList does not contain a list, wrong "
131 "variant type.\n";
132 }
133 }
134 return permitSet;
135}
136
James Feist6714a252018-09-10 15:26:18 -0700137bool getSensorConfiguration(
138 const std::string& type,
139 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700140 ManagedObjectType& resp)
141{
142 return getSensorConfiguration(type, dbusConnection, resp, false);
143}
144
145bool getSensorConfiguration(
146 const std::string& type,
147 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
James Feist6714a252018-09-10 15:26:18 -0700148 ManagedObjectType& resp, bool useCache)
149{
150 static ManagedObjectType managedObj;
Zev Weiss054aad82022-08-18 01:37:34 -0700151 std::string typeIntf = configInterfaceName(type);
James Feist6714a252018-09-10 15:26:18 -0700152
153 if (!useCache)
154 {
155 managedObj.clear();
Patrick Williams92f8f512022-07-22 19:26:55 -0500156 sdbusplus::message_t getManagedObjects =
James Feist6714a252018-09-10 15:26:18 -0700157 dbusConnection->new_method_call(
JeffLin2c5a1f22022-10-05 15:19:09 +0800158 entityManagerName, "/xyz/openbmc_project/inventory",
159 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6714a252018-09-10 15:26:18 -0700160 try
161 {
Patrick Williams92f8f512022-07-22 19:26:55 -0500162 sdbusplus::message_t reply =
James Feist6714a252018-09-10 15:26:18 -0700163 dbusConnection->call(getManagedObjects);
Yoo, Jae Hyun0e022052018-10-15 14:05:37 -0700164 reply.read(managedObj);
James Feist6714a252018-09-10 15:26:18 -0700165 }
Patrick Williams92f8f512022-07-22 19:26:55 -0500166 catch (const sdbusplus::exception_t& e)
James Feist6714a252018-09-10 15:26:18 -0700167 {
Jason Ling5747fab2019-10-02 16:46:23 -0700168 std::cerr << "While calling GetManagedObjects on service:"
169 << entityManagerName << " exception name:" << e.name()
170 << "and description:" << e.description()
171 << " was thrown\n";
James Feist6714a252018-09-10 15:26:18 -0700172 return false;
173 }
174 }
175 for (const auto& pathPair : managedObj)
176 {
Zev Weissfd3d5f72022-08-12 18:21:02 -0700177 for (const auto& [intf, cfg] : pathPair.second)
James Feist6714a252018-09-10 15:26:18 -0700178 {
Zev Weiss054aad82022-08-18 01:37:34 -0700179 if (intf.starts_with(typeIntf))
James Feist6714a252018-09-10 15:26:18 -0700180 {
Zev Weiss79d8aef2022-08-17 21:45:44 -0700181 resp.emplace(pathPair);
James Feist6714a252018-09-10 15:26:18 -0700182 break;
183 }
184 }
James Feist6714a252018-09-10 15:26:18 -0700185 }
186 return true;
187}
188
Lei YU6a4e9732021-10-20 13:27:34 +0800189bool findFiles(const fs::path& dirPath, std::string_view matchString,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700190 std::vector<fs::path>& foundPaths, int symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700191{
Lei YU6a4e9732021-10-20 13:27:34 +0800192 std::error_code ec;
193 if (!fs::exists(dirPath, ec))
Ed Tanous8a57ec02020-10-09 12:46:52 -0700194 {
James Feist6714a252018-09-10 15:26:18 -0700195 return false;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700196 }
James Feist6714a252018-09-10 15:26:18 -0700197
Lei YU6a4e9732021-10-20 13:27:34 +0800198 std::vector<std::regex> matchPieces;
199
200 size_t pos = 0;
201 std::string token;
202 // Generate the regex expressions list from the match we were given
203 while ((pos = matchString.find('/')) != std::string::npos)
204 {
205 token = matchString.substr(0, pos);
206 matchPieces.emplace_back(token);
207 matchString.remove_prefix(pos + 1);
208 }
209 matchPieces.emplace_back(std::string{matchString});
210
211 // Check if the match string contains directories, and skip the match of
212 // subdirectory if not
213 if (matchPieces.size() <= 1)
214 {
215 std::regex search(std::string{matchString});
216 std::smatch match;
217 for (auto p = fs::recursive_directory_iterator(
218 dirPath, fs::directory_options::follow_directory_symlink);
219 p != fs::recursive_directory_iterator(); ++p)
220 {
221 std::string path = p->path().string();
222 if (!is_directory(*p))
223 {
224 if (std::regex_search(path, match, search))
225 {
226 foundPaths.emplace_back(p->path());
227 }
228 }
229 if (p.depth() >= symlinkDepth)
230 {
231 p.disable_recursion_pending();
232 }
233 }
234 return true;
235 }
236
237 // The match string contains directories, verify each level of sub
238 // directories
Ed Tanous8a57ec02020-10-09 12:46:52 -0700239 for (auto p = fs::recursive_directory_iterator(
240 dirPath, fs::directory_options::follow_directory_symlink);
241 p != fs::recursive_directory_iterator(); ++p)
James Feist6714a252018-09-10 15:26:18 -0700242 {
Lei YU6a4e9732021-10-20 13:27:34 +0800243 std::vector<std::regex>::iterator matchPiece = matchPieces.begin();
244 fs::path::iterator pathIt = p->path().begin();
245 for (const fs::path& dir : dirPath)
246 {
247 if (dir.empty())
248 {
249 // When the path ends with '/', it gets am empty path
250 // skip such case.
251 break;
252 }
253 pathIt++;
254 }
255
256 while (pathIt != p->path().end())
257 {
258 // Found a path deeper than match.
259 if (matchPiece == matchPieces.end())
260 {
261 p.disable_recursion_pending();
262 break;
263 }
264 std::smatch match;
265 std::string component = pathIt->string();
266 std::regex regexPiece(*matchPiece);
267 if (!std::regex_match(component, match, regexPiece))
268 {
269 // path prefix doesn't match, no need to iterate further
270 p.disable_recursion_pending();
271 break;
272 }
273 matchPiece++;
274 pathIt++;
275 }
276
Ed Tanous8a57ec02020-10-09 12:46:52 -0700277 if (!is_directory(*p))
James Feist6714a252018-09-10 15:26:18 -0700278 {
Lei YU6a4e9732021-10-20 13:27:34 +0800279 if (matchPiece == matchPieces.end())
Ed Tanous8a57ec02020-10-09 12:46:52 -0700280 {
281 foundPaths.emplace_back(p->path());
282 }
James Feist6714a252018-09-10 15:26:18 -0700283 }
Lei YU6a4e9732021-10-20 13:27:34 +0800284
Ed Tanous8a57ec02020-10-09 12:46:52 -0700285 if (p.depth() >= symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700286 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700287 p.disable_recursion_pending();
James Feist6714a252018-09-10 15:26:18 -0700288 }
289 }
290 return true;
291}
292
James Feist71d31b22019-01-02 16:57:54 -0800293bool isPowerOn(void)
James Feist6714a252018-09-10 15:26:18 -0700294{
James Feist71d31b22019-01-02 16:57:54 -0800295 if (!powerMatch)
James Feist6714a252018-09-10 15:26:18 -0700296 {
James Feist71d31b22019-01-02 16:57:54 -0800297 throw std::runtime_error("Power Match Not Created");
James Feist6714a252018-09-10 15:26:18 -0700298 }
James Feist71d31b22019-01-02 16:57:54 -0800299 return powerStatusOn;
300}
301
James Feistfc94b212019-02-06 16:14:51 -0800302bool hasBiosPost(void)
303{
James Feist52497fd2019-06-07 13:01:33 -0700304 if (!postMatch)
James Feistfc94b212019-02-06 16:14:51 -0800305 {
James Feist52497fd2019-06-07 13:01:33 -0700306 throw std::runtime_error("Post Match Not Created");
James Feistfc94b212019-02-06 16:14:51 -0800307 }
308 return biosHasPost;
309}
310
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700311bool isChassisOn(void)
312{
313 if (!chassisMatch)
314 {
315 throw std::runtime_error("Chassis On Match Not Created");
316 }
317 return chassisStatusOn;
318}
319
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000320bool readingStateGood(const PowerState& powerState)
321{
322 if (powerState == PowerState::on && !isPowerOn())
323 {
324 return false;
325 }
326 if (powerState == PowerState::biosPost && (!hasBiosPost() || !isPowerOn()))
327 {
328 return false;
329 }
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700330 if (powerState == PowerState::chassisOn && !isChassisOn())
331 {
332 return false;
333 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000334
335 return true;
336}
337
James Feist8aeffd92020-09-14 12:08:28 -0700338static void
339 getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
340 size_t retries = 2)
341{
342 conn->async_method_call(
343 [conn, retries](boost::system::error_code ec,
344 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700345 if (ec)
346 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700347 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700348 {
Ed Tanousbb679322022-05-16 16:10:00 -0700349 auto timer = std::make_shared<boost::asio::steady_timer>(
350 conn->get_io_context());
351 timer->expires_after(std::chrono::seconds(15));
352 timer->async_wait(
353 [timer, conn, retries](boost::system::error_code) {
354 getPowerStatus(conn, retries - 1);
355 });
James Feist8aeffd92020-09-14 12:08:28 -0700356 return;
357 }
Ed Tanousbb679322022-05-16 16:10:00 -0700358
359 // we commonly come up before power control, we'll capture the
360 // property change later
361 std::cerr << "error getting power status " << ec.message() << "\n";
362 return;
363 }
Zev Weiss6c106d62022-08-17 20:50:00 -0700364 powerStatusOn = std::get<std::string>(state).ends_with(".Running");
Patrick Williams597e8422023-10-20 11:19:01 -0500365 },
James Feist8aeffd92020-09-14 12:08:28 -0700366 power::busname, power::path, properties::interface, properties::get,
367 power::interface, power::property);
368}
369
370static void
371 getPostStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
372 size_t retries = 2)
373{
374 conn->async_method_call(
375 [conn, retries](boost::system::error_code ec,
376 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700377 if (ec)
378 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700379 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700380 {
Ed Tanousbb679322022-05-16 16:10:00 -0700381 auto timer = std::make_shared<boost::asio::steady_timer>(
382 conn->get_io_context());
383 timer->expires_after(std::chrono::seconds(15));
384 timer->async_wait(
385 [timer, conn, retries](boost::system::error_code) {
386 getPostStatus(conn, retries - 1);
387 });
James Feist8aeffd92020-09-14 12:08:28 -0700388 return;
389 }
Ed Tanousbb679322022-05-16 16:10:00 -0700390 // we commonly come up before power control, we'll capture the
391 // property change later
392 std::cerr << "error getting post status " << ec.message() << "\n";
393 return;
394 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700395 const auto& value = std::get<std::string>(state);
Ed Tanousbb679322022-05-16 16:10:00 -0700396 biosHasPost = (value != "Inactive") &&
397 (value != "xyz.openbmc_project.State.OperatingSystem."
398 "Status.OSStatus.Inactive");
Patrick Williams597e8422023-10-20 11:19:01 -0500399 },
James Feist8aeffd92020-09-14 12:08:28 -0700400 post::busname, post::path, properties::interface, properties::get,
401 post::interface, post::property);
402}
403
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700404static void
405 getChassisStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
406 size_t retries = 2)
407{
408 conn->async_method_call(
409 [conn, retries](boost::system::error_code ec,
410 const std::variant<std::string>& state) {
411 if (ec)
412 {
413 if (retries != 0U)
414 {
415 auto timer = std::make_shared<boost::asio::steady_timer>(
416 conn->get_io_context());
417 timer->expires_after(std::chrono::seconds(15));
418 timer->async_wait(
419 [timer, conn, retries](boost::system::error_code) {
420 getChassisStatus(conn, retries - 1);
421 });
422 return;
423 }
424
425 // we commonly come up before power control, we'll capture the
426 // property change later
427 std::cerr << "error getting chassis power status " << ec.message()
428 << "\n";
429 return;
430 }
431 chassisStatusOn = std::get<std::string>(state).ends_with(chassis::sOn);
Patrick Williams597e8422023-10-20 11:19:01 -0500432 },
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700433 chassis::busname, chassis::path, properties::interface, properties::get,
434 chassis::interface, chassis::property);
435}
436
Zev Weiss88cb29d2022-05-09 03:46:15 +0000437void setupPowerMatchCallback(
438 const std::shared_ptr<sdbusplus::asio::connection>& conn,
439 std::function<void(PowerState type, bool state)>&& hostStatusCallback)
James Feist71d31b22019-01-02 16:57:54 -0800440{
James Feist43d32fe2019-09-04 10:35:20 -0700441 static boost::asio::steady_timer timer(conn->get_io_context());
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700442 static boost::asio::steady_timer timerChassisOn(conn->get_io_context());
James Feist6714a252018-09-10 15:26:18 -0700443 // create a match for powergood changes, first time do a method call to
James Feist71d31b22019-01-02 16:57:54 -0800444 // cache the correct value
James Feist52497fd2019-06-07 13:01:33 -0700445 if (powerMatch)
446 {
447 return;
448 }
James Feist6714a252018-09-10 15:26:18 -0700449
Patrick Williams92f8f512022-07-22 19:26:55 -0500450 powerMatch = std::make_unique<sdbusplus::bus::match_t>(
451 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700452 "type='signal',interface='" + std::string(properties::interface) +
453 "',path='" + std::string(power::path) + "',arg0='" +
454 std::string(power::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000455 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700456 std::string objectName;
457 boost::container::flat_map<std::string, std::variant<std::string>>
458 values;
459 message.read(objectName, values);
460 auto findState = values.find(power::property);
461 if (findState != values.end())
462 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700463 bool on =
464 std::get<std::string>(findState->second).ends_with(".Running");
Ed Tanousbb679322022-05-16 16:10:00 -0700465 if (!on)
James Feist6714a252018-09-10 15:26:18 -0700466 {
Ed Tanousbb679322022-05-16 16:10:00 -0700467 timer.cancel();
468 powerStatusOn = false;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000469 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700470 return;
471 }
472 // on comes too quickly
473 timer.expires_after(std::chrono::seconds(10));
Zev Weiss88cb29d2022-05-09 03:46:15 +0000474 timer.async_wait(
475 [hostStatusCallback](boost::system::error_code ec) {
Ed Tanousbb679322022-05-16 16:10:00 -0700476 if (ec == boost::asio::error::operation_aborted)
James Feist43d32fe2019-09-04 10:35:20 -0700477 {
James Feist43d32fe2019-09-04 10:35:20 -0700478 return;
479 }
Ed Tanousbb679322022-05-16 16:10:00 -0700480 if (ec)
481 {
482 std::cerr << "Timer error " << ec.message() << "\n";
483 return;
484 }
485 powerStatusOn = true;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000486 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700487 });
488 }
Patrick Williams597e8422023-10-20 11:19:01 -0500489 });
James Feist52497fd2019-06-07 13:01:33 -0700490
Patrick Williams92f8f512022-07-22 19:26:55 -0500491 postMatch = std::make_unique<sdbusplus::bus::match_t>(
492 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700493 "type='signal',interface='" + std::string(properties::interface) +
494 "',path='" + std::string(post::path) + "',arg0='" +
495 std::string(post::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000496 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700497 std::string objectName;
498 boost::container::flat_map<std::string, std::variant<std::string>>
499 values;
500 message.read(objectName, values);
501 auto findState = values.find(post::property);
502 if (findState != values.end())
503 {
504 auto& value = std::get<std::string>(findState->second);
505 biosHasPost = (value != "Inactive") &&
506 (value != "xyz.openbmc_project.State.OperatingSystem."
507 "Status.OSStatus.Inactive");
Zev Weiss88cb29d2022-05-09 03:46:15 +0000508 hostStatusCallback(PowerState::biosPost, biosHasPost);
Ed Tanousbb679322022-05-16 16:10:00 -0700509 }
Patrick Williams597e8422023-10-20 11:19:01 -0500510 });
James Feistfc94b212019-02-06 16:14:51 -0800511
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700512 chassisMatch = std::make_unique<sdbusplus::bus::match_t>(
513 static_cast<sdbusplus::bus_t&>(*conn),
514 "type='signal',interface='" + std::string(properties::interface) +
515 "',path='" + std::string(chassis::path) + "',arg0='" +
516 std::string(chassis::interface) + "'",
517 [hostStatusCallback](sdbusplus::message_t& message) {
518 std::string objectName;
519 boost::container::flat_map<std::string, std::variant<std::string>>
520 values;
521 message.read(objectName, values);
522 auto findState = values.find(chassis::property);
523 if (findState != values.end())
524 {
525 bool on = std::get<std::string>(findState->second)
526 .ends_with(chassis::sOn);
527 if (!on)
528 {
529 timerChassisOn.cancel();
530 chassisStatusOn = false;
531 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
532 return;
533 }
534 // on comes too quickly
535 timerChassisOn.expires_after(std::chrono::seconds(10));
536 timerChassisOn.async_wait(
537 [hostStatusCallback](boost::system::error_code ec) {
538 if (ec == boost::asio::error::operation_aborted)
539 {
540 return;
541 }
542 if (ec)
543 {
544 std::cerr << "Timer error " << ec.message() << "\n";
545 return;
546 }
547 chassisStatusOn = true;
548 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
549 });
550 }
Patrick Williams597e8422023-10-20 11:19:01 -0500551 });
James Feist8aeffd92020-09-14 12:08:28 -0700552 getPowerStatus(conn);
553 getPostStatus(conn);
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700554 getChassisStatus(conn);
James Feist3f0e8762018-11-27 11:30:42 -0800555}
James Feist87d713a2018-12-06 16:06:24 -0800556
Zev Weiss88cb29d2022-05-09 03:46:15 +0000557void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
558{
559 setupPowerMatchCallback(conn, [](PowerState, bool) {});
560}
561
James Feist87d713a2018-12-06 16:06:24 -0800562// replaces limits if MinReading and MaxReading are found.
563void findLimits(std::pair<double, double>& limits,
564 const SensorBaseConfiguration* data)
565{
Ed Tanous2049bd22022-07-09 07:20:26 -0700566 if (data == nullptr)
James Feist87d713a2018-12-06 16:06:24 -0800567 {
568 return;
569 }
570 auto maxFind = data->second.find("MaxReading");
571 auto minFind = data->second.find("MinReading");
572
573 if (minFind != data->second.end())
574 {
James Feist3eb82622019-02-08 13:10:22 -0800575 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800576 }
577 if (maxFind != data->second.end())
578 {
James Feist3eb82622019-02-08 13:10:22 -0800579 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800580 }
James Feistfc94b212019-02-06 16:14:51 -0800581}
James Feist82bac4c2019-03-11 11:16:53 -0700582
583void createAssociation(
584 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
585 const std::string& path)
586{
587 if (association)
588 {
Lei YU6a4e9732021-10-20 13:27:34 +0800589 fs::path p(path);
James Feistd2543f82019-04-09 11:10:06 -0700590
James Feist82bac4c2019-03-11 11:16:53 -0700591 std::vector<Association> associations;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700592 associations.emplace_back("chassis", "all_sensors",
593 p.parent_path().string());
James Feist2adc95c2019-09-30 14:55:28 -0700594 association->register_property("Associations", associations);
James Feist82bac4c2019-03-11 11:16:53 -0700595 association->initialize();
596 }
James Feist43d32fe2019-09-04 10:35:20 -0700597}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800598
599void setInventoryAssociation(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700600 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000601 const std::string& inventoryPath, const std::string& chassisPath)
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800602{
603 if (association)
604 {
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800605 std::vector<Association> associations;
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000606 associations.emplace_back("inventory", "sensors", inventoryPath);
607 associations.emplace_back("chassis", "all_sensors", chassisPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530608
James Feist2adc95c2019-09-30 14:55:28 -0700609 association->register_property("Associations", associations);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800610 association->initialize();
611 }
612}
613
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000614std::optional<std::string> findContainingChassis(std::string_view configParent,
615 const GetSubTreeType& subtree)
616{
617 // A parent that is a chassis takes precedence
618 for (const auto& [obj, services] : subtree)
619 {
620 if (obj == configParent)
621 {
622 return obj;
623 }
624 }
625
626 // If the parent is not a chassis, the system chassis is used. This does not
627 // work if there is more than one System, but we assume there is only one
628 // today.
629 for (const auto& [obj, services] : subtree)
630 {
631 for (const auto& [service, interfaces] : services)
632 {
633 if (std::find(interfaces.begin(), interfaces.end(),
634 "xyz.openbmc_project.Inventory.Item.System") !=
635 interfaces.end())
636 {
637 return obj;
638 }
639 }
640 }
641 return std::nullopt;
642}
643
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800644void createInventoryAssoc(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700645 const std::shared_ptr<sdbusplus::asio::connection>& conn,
646 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800647 const std::string& path)
648{
649 if (!association)
650 {
651 return;
652 }
AppaRao Pulic82213c2020-02-27 01:24:58 +0530653
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000654 constexpr auto allInterfaces = std::to_array({
655 "xyz.openbmc_project.Inventory.Item.Board",
656 "xyz.openbmc_project.Inventory.Item.Chassis",
657 });
658
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800659 conn->async_method_call(
660 [association, path](const boost::system::error_code ec,
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000661 const GetSubTreeType& subtree) {
662 // The parent of the config is always the inventory object, and may be
663 // the associated chassis. If the parent is not itself a chassis or
664 // board, the sensor is associated with the system chassis.
665 std::string parent = fs::path(path).parent_path().string();
Ed Tanousbb679322022-05-16 16:10:00 -0700666 if (ec)
667 {
668 // In case of error, set the default associations and
669 // initialize the association Interface.
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000670 setInventoryAssociation(association, parent, parent);
Ed Tanousbb679322022-05-16 16:10:00 -0700671 return;
672 }
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000673 setInventoryAssociation(
674 association, parent,
675 findContainingChassis(parent, subtree).value_or(parent));
Patrick Williams597e8422023-10-20 11:19:01 -0500676 },
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000677 mapper::busName, mapper::path, mapper::interface, "GetSubTree",
678 "/xyz/openbmc_project/inventory/system", 2, allInterfaces);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800679}
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200680
681std::optional<double> readFile(const std::string& thresholdFile,
682 const double& scaleFactor)
683{
684 std::string line;
685 std::ifstream labelFile(thresholdFile);
686 if (labelFile.good())
687 {
688 std::getline(labelFile, line);
689 labelFile.close();
690
691 try
692 {
693 return std::stod(line) / scaleFactor;
694 }
695 catch (const std::invalid_argument&)
696 {
697 return std::nullopt;
698 }
699 }
700 return std::nullopt;
701}
702
703std::optional<std::tuple<std::string, std::string, std::string>>
Lei YU6a4e9732021-10-20 13:27:34 +0800704 splitFileName(const fs::path& filePath)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200705{
706 if (filePath.has_filename())
707 {
708 const auto fileName = filePath.filename().string();
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200709
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200710 size_t numberPos = std::strcspn(fileName.c_str(), "1234567890");
711 size_t itemPos = std::strcspn(fileName.c_str(), "_");
712
713 if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200714 {
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200715 return std::make_optional(
716 std::make_tuple(fileName.substr(0, numberPos),
717 fileName.substr(numberPos, itemPos - numberPos),
718 fileName.substr(itemPos + 1, fileName.size())));
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200719 }
720 }
721 return std::nullopt;
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200722}
Bruce Lee1263c3d2021-06-04 15:16:33 +0800723
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530724static void handleSpecialModeChange(const std::string& manufacturingModeStatus)
725{
726 manufacturingMode = false;
727 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
728 "SpecialMode.Modes.Manufacturing")
729 {
730 manufacturingMode = true;
731 }
Ed Tanous74cffa82022-01-25 13:00:28 -0800732 if (validateUnsecureFeature == 1)
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530733 {
734 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
735 "SpecialMode.Modes.ValidationUnsecure")
736 {
737 manufacturingMode = true;
738 }
739 }
740}
741
Bruce Lee1263c3d2021-06-04 15:16:33 +0800742void setupManufacturingModeMatch(sdbusplus::asio::connection& conn)
743{
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530744 namespace rules = sdbusplus::bus::match::rules;
745 static constexpr const char* specialModeInterface =
746 "xyz.openbmc_project.Security.SpecialMode";
747
748 const std::string filterSpecialModeIntfAdd =
749 rules::interfacesAdded() +
750 rules::argNpath(0, "/xyz/openbmc_project/security/special_mode");
Patrick Williams92f8f512022-07-22 19:26:55 -0500751 static std::unique_ptr<sdbusplus::bus::match_t> specialModeIntfMatch =
Patrick Williams597e8422023-10-20 11:19:01 -0500752 std::make_unique<sdbusplus::bus::match_t>(
753 conn, filterSpecialModeIntfAdd, [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700754 sdbusplus::message::object_path path;
755 using PropertyMap =
756 boost::container::flat_map<std::string, std::variant<std::string>>;
757 boost::container::flat_map<std::string, PropertyMap> interfaceAdded;
758 m.read(path, interfaceAdded);
759 auto intfItr = interfaceAdded.find(specialModeInterface);
760 if (intfItr == interfaceAdded.end())
761 {
762 return;
763 }
764 PropertyMap& propertyList = intfItr->second;
765 auto itr = propertyList.find("SpecialMode");
766 if (itr == propertyList.end())
767 {
768 std::cerr << "error getting SpecialMode property "
769 << "\n";
770 return;
771 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700772 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700773 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams597e8422023-10-20 11:19:01 -0500774 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800775
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530776 const std::string filterSpecialModeChange =
777 rules::type::signal() + rules::member("PropertiesChanged") +
778 rules::interface("org.freedesktop.DBus.Properties") +
779 rules::argN(0, specialModeInterface);
Patrick Williams92f8f512022-07-22 19:26:55 -0500780 static std::unique_ptr<sdbusplus::bus::match_t> specialModeChangeMatch =
781 std::make_unique<sdbusplus::bus::match_t>(conn, filterSpecialModeChange,
782 [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700783 std::string interfaceName;
784 boost::container::flat_map<std::string, std::variant<std::string>>
785 propertiesChanged;
Bruce Lee1263c3d2021-06-04 15:16:33 +0800786
Ed Tanousbb679322022-05-16 16:10:00 -0700787 m.read(interfaceName, propertiesChanged);
788 auto itr = propertiesChanged.find("SpecialMode");
789 if (itr == propertiesChanged.end())
790 {
791 return;
792 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700793 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700794 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams597e8422023-10-20 11:19:01 -0500795 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800796
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530797 conn.async_method_call(
798 [](const boost::system::error_code ec,
799 const std::variant<std::string>& getManufactMode) {
Ed Tanousbb679322022-05-16 16:10:00 -0700800 if (ec)
801 {
802 std::cerr << "error getting SpecialMode status " << ec.message()
803 << "\n";
804 return;
805 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700806 const auto* manufacturingModeStatus =
Ed Tanousbb679322022-05-16 16:10:00 -0700807 std::get_if<std::string>(&getManufactMode);
808 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams597e8422023-10-20 11:19:01 -0500809 },
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530810 "xyz.openbmc_project.SpecialMode",
811 "/xyz/openbmc_project/security/special_mode",
812 "org.freedesktop.DBus.Properties", "Get", specialModeInterface,
813 "SpecialMode");
Bruce Lee1263c3d2021-06-04 15:16:33 +0800814}
815
816bool getManufacturingMode()
817{
818 return manufacturingMode;
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000819}
Zev Weiss214d9712022-08-12 12:54:31 -0700820
821std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
822 setupPropertiesChangedMatches(
823 sdbusplus::asio::connection& bus, std::span<const char* const> types,
824 const std::function<void(sdbusplus::message_t&)>& handler)
825{
826 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches;
827 for (const char* type : types)
828 {
829 auto match = std::make_unique<sdbusplus::bus::match_t>(
830 static_cast<sdbusplus::bus_t&>(bus),
831 "type='signal',member='PropertiesChanged',path_namespace='" +
Zev Weiss054aad82022-08-18 01:37:34 -0700832 std::string(inventoryPath) + "',arg0namespace='" +
833 configInterfaceName(type) + "'",
Zev Weiss214d9712022-08-12 12:54:31 -0700834 handler);
835 matches.emplace_back(std::move(match));
836 }
837 return matches;
838}
Zev Weissdabd48d2022-08-03 15:43:17 -0700839
840std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
841 setupPropertiesChangedMatches(
842 sdbusplus::asio::connection& bus, const I2CDeviceTypeMap& typeMap,
843 const std::function<void(sdbusplus::message_t&)>& handler)
844{
845 std::vector<const char*> types;
846 types.reserve(typeMap.size());
847 for (const auto& [type, dt] : typeMap)
848 {
849 types.push_back(type.data());
850 }
851 return setupPropertiesChangedMatches(bus, {types}, handler);
852}