blob: e3cbfebd1163d39aec9ff19e107c583d83294e60 [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"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070022#include "VariantVisitors.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103023
Ed Tanouseacbfdd2024-04-04 12:00:24 -070024#include <boost/asio/error.hpp>
25#include <boost/asio/steady_timer.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070026#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070027#include <sdbusplus/asio/connection.hpp>
28#include <sdbusplus/asio/object_server.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070029#include <sdbusplus/bus.hpp>
James Feist38fb5982020-05-28 10:09:54 -070030#include <sdbusplus/bus/match.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070031#include <sdbusplus/exception.hpp>
32#include <sdbusplus/message.hpp>
33#include <sdbusplus/message/native_types.hpp>
James Feist38fb5982020-05-28 10:09:54 -070034
Ed Tanouseacbfdd2024-04-04 12:00:24 -070035#include <algorithm>
36#include <array>
37#include <chrono>
38#include <cstddef>
39#include <cstring>
James Feist24f02f22019-04-15 11:05:39 -070040#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070041#include <fstream>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070042#include <functional>
43#include <iostream>
44#include <iterator>
Patrick Venture96e97db2019-10-31 13:44:38 -070045#include <memory>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070046#include <optional>
James Feist6714a252018-09-10 15:26:18 -070047#include <regex>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070048#include <set>
49#include <span>
Patrick Venture96e97db2019-10-31 13:44:38 -070050#include <stdexcept>
51#include <string>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070052#include <string_view>
53#include <system_error>
54#include <tuple>
Patrick Venture96e97db2019-10-31 13:44:38 -070055#include <utility>
56#include <variant>
57#include <vector>
James Feist6714a252018-09-10 15:26:18 -070058
James Feistcf3bce62019-01-08 10:07:19 -080059namespace fs = std::filesystem;
James Feist6714a252018-09-10 15:26:18 -070060
James Feist6ef20402019-01-07 16:45:08 -080061static bool powerStatusOn = false;
James Feistfc94b212019-02-06 16:14:51 -080062static bool biosHasPost = false;
Bruce Lee1263c3d2021-06-04 15:16:33 +080063static bool manufacturingMode = false;
Thu Nguyen6db8aae2022-10-04 08:12:48 +070064static bool chassisStatusOn = false;
James Feist58295ad2019-05-30 15:01:41 -070065
Patrick Williams92f8f512022-07-22 19:26:55 -050066static std::unique_ptr<sdbusplus::bus::match_t> powerMatch = nullptr;
67static std::unique_ptr<sdbusplus::bus::match_t> postMatch = nullptr;
Thu Nguyen6db8aae2022-10-04 08:12:48 +070068static std::unique_ptr<sdbusplus::bus::match_t> chassisMatch = nullptr;
James Feist71d31b22019-01-02 16:57:54 -080069
Jason Ling100c20b2020-08-11 14:50:33 -070070/**
71 * return the contents of a file
72 * @param[in] hwmonFile - the path to the file to read
73 * @return the contents of the file as a string or nullopt if the file could not
74 * be opened.
75 */
76
77std::optional<std::string> openAndRead(const std::string& hwmonFile)
78{
79 std::string fileVal;
80 std::ifstream fileStream(hwmonFile);
81 if (!fileStream.is_open())
82 {
83 return std::nullopt;
84 }
85 std::getline(fileStream, fileVal);
86 return fileVal;
87}
88
89/**
90 * given a hwmon temperature base name if valid return the full path else
91 * nullopt
92 * @param[in] directory - the hwmon sysfs directory
93 * @param[in] permitSet - a set of labels or hwmon basenames to permit. If this
94 * is empty then *everything* is permitted.
95 * @return a string to the full path of the file to create a temp sensor with or
96 * nullopt to indicate that no sensor should be created for this basename.
97 */
98std::optional<std::string>
99 getFullHwmonFilePath(const std::string& directory,
100 const std::string& hwmonBaseName,
101 const std::set<std::string>& permitSet)
102{
103 std::optional<std::string> result;
104 std::string filename;
105 if (permitSet.empty())
106 {
107 result = directory + "/" + hwmonBaseName + "_input";
108 return result;
109 }
110 filename = directory + "/" + hwmonBaseName + "_label";
111 auto searchVal = openAndRead(filename);
112 if (!searchVal)
113 {
114 /* if the hwmon temp doesn't have a corresponding label file
115 * then use the hwmon temperature base name
116 */
117 searchVal = hwmonBaseName;
118 }
119 if (permitSet.find(*searchVal) != permitSet.end())
120 {
121 result = directory + "/" + hwmonBaseName + "_input";
122 }
123 return result;
124}
125
126/**
127 * retrieve a set of basenames and labels to allow sensor creation for.
128 * @param[in] config - a map representing the configuration for a specific
129 * device
130 * @return a set of basenames and labels to allow sensor creation for. An empty
131 * set indicates that everything is permitted.
132 */
133std::set<std::string> getPermitSet(const SensorBaseConfigMap& config)
134{
135 auto permitAttribute = config.find("Labels");
136 std::set<std::string> permitSet;
137 if (permitAttribute != config.end())
138 {
139 try
140 {
141 auto val =
142 std::get<std::vector<std::string>>(permitAttribute->second);
143
144 permitSet.insert(std::make_move_iterator(val.begin()),
145 std::make_move_iterator(val.end()));
146 }
147 catch (const std::bad_variant_access& err)
148 {
149 std::cerr << err.what()
150 << ":PermitList does not contain a list, wrong "
151 "variant type.\n";
152 }
153 }
154 return permitSet;
155}
156
James Feist6714a252018-09-10 15:26:18 -0700157bool getSensorConfiguration(
158 const std::string& type,
159 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
160 ManagedObjectType& resp, bool useCache)
161{
162 static ManagedObjectType managedObj;
Zev Weiss054aad82022-08-18 01:37:34 -0700163 std::string typeIntf = configInterfaceName(type);
James Feist6714a252018-09-10 15:26:18 -0700164
165 if (!useCache)
166 {
167 managedObj.clear();
Patrick Williams92f8f512022-07-22 19:26:55 -0500168 sdbusplus::message_t getManagedObjects =
James Feist6714a252018-09-10 15:26:18 -0700169 dbusConnection->new_method_call(
JeffLin2c5a1f22022-10-05 15:19:09 +0800170 entityManagerName, "/xyz/openbmc_project/inventory",
171 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6714a252018-09-10 15:26:18 -0700172 try
173 {
Patrick Williams92f8f512022-07-22 19:26:55 -0500174 sdbusplus::message_t reply =
James Feist6714a252018-09-10 15:26:18 -0700175 dbusConnection->call(getManagedObjects);
Yoo, Jae Hyun0e022052018-10-15 14:05:37 -0700176 reply.read(managedObj);
James Feist6714a252018-09-10 15:26:18 -0700177 }
Patrick Williams92f8f512022-07-22 19:26:55 -0500178 catch (const sdbusplus::exception_t& e)
James Feist6714a252018-09-10 15:26:18 -0700179 {
Jason Ling5747fab2019-10-02 16:46:23 -0700180 std::cerr << "While calling GetManagedObjects on service:"
181 << entityManagerName << " exception name:" << e.name()
182 << "and description:" << e.description()
183 << " was thrown\n";
James Feist6714a252018-09-10 15:26:18 -0700184 return false;
185 }
186 }
187 for (const auto& pathPair : managedObj)
188 {
Zev Weissfd3d5f72022-08-12 18:21:02 -0700189 for (const auto& [intf, cfg] : pathPair.second)
James Feist6714a252018-09-10 15:26:18 -0700190 {
Zev Weiss054aad82022-08-18 01:37:34 -0700191 if (intf.starts_with(typeIntf))
James Feist6714a252018-09-10 15:26:18 -0700192 {
Zev Weiss79d8aef2022-08-17 21:45:44 -0700193 resp.emplace(pathPair);
James Feist6714a252018-09-10 15:26:18 -0700194 break;
195 }
196 }
James Feist6714a252018-09-10 15:26:18 -0700197 }
198 return true;
199}
200
Lei YU6a4e9732021-10-20 13:27:34 +0800201bool findFiles(const fs::path& dirPath, std::string_view matchString,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700202 std::vector<fs::path>& foundPaths, int symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700203{
Lei YU6a4e9732021-10-20 13:27:34 +0800204 std::error_code ec;
205 if (!fs::exists(dirPath, ec))
Ed Tanous8a57ec02020-10-09 12:46:52 -0700206 {
James Feist6714a252018-09-10 15:26:18 -0700207 return false;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700208 }
James Feist6714a252018-09-10 15:26:18 -0700209
Lei YU6a4e9732021-10-20 13:27:34 +0800210 std::vector<std::regex> matchPieces;
211
212 size_t pos = 0;
213 std::string token;
214 // Generate the regex expressions list from the match we were given
215 while ((pos = matchString.find('/')) != std::string::npos)
216 {
217 token = matchString.substr(0, pos);
218 matchPieces.emplace_back(token);
219 matchString.remove_prefix(pos + 1);
220 }
221 matchPieces.emplace_back(std::string{matchString});
222
223 // Check if the match string contains directories, and skip the match of
224 // subdirectory if not
225 if (matchPieces.size() <= 1)
226 {
227 std::regex search(std::string{matchString});
228 std::smatch match;
229 for (auto p = fs::recursive_directory_iterator(
230 dirPath, fs::directory_options::follow_directory_symlink);
231 p != fs::recursive_directory_iterator(); ++p)
232 {
233 std::string path = p->path().string();
234 if (!is_directory(*p))
235 {
236 if (std::regex_search(path, match, search))
237 {
238 foundPaths.emplace_back(p->path());
239 }
240 }
241 if (p.depth() >= symlinkDepth)
242 {
243 p.disable_recursion_pending();
244 }
245 }
246 return true;
247 }
248
249 // The match string contains directories, verify each level of sub
250 // directories
Ed Tanous8a57ec02020-10-09 12:46:52 -0700251 for (auto p = fs::recursive_directory_iterator(
252 dirPath, fs::directory_options::follow_directory_symlink);
253 p != fs::recursive_directory_iterator(); ++p)
James Feist6714a252018-09-10 15:26:18 -0700254 {
Lei YU6a4e9732021-10-20 13:27:34 +0800255 std::vector<std::regex>::iterator matchPiece = matchPieces.begin();
256 fs::path::iterator pathIt = p->path().begin();
257 for (const fs::path& dir : dirPath)
258 {
259 if (dir.empty())
260 {
261 // When the path ends with '/', it gets am empty path
262 // skip such case.
263 break;
264 }
265 pathIt++;
266 }
267
268 while (pathIt != p->path().end())
269 {
270 // Found a path deeper than match.
271 if (matchPiece == matchPieces.end())
272 {
273 p.disable_recursion_pending();
274 break;
275 }
276 std::smatch match;
277 std::string component = pathIt->string();
278 std::regex regexPiece(*matchPiece);
279 if (!std::regex_match(component, match, regexPiece))
280 {
281 // path prefix doesn't match, no need to iterate further
282 p.disable_recursion_pending();
283 break;
284 }
285 matchPiece++;
286 pathIt++;
287 }
288
Ed Tanous8a57ec02020-10-09 12:46:52 -0700289 if (!is_directory(*p))
James Feist6714a252018-09-10 15:26:18 -0700290 {
Lei YU6a4e9732021-10-20 13:27:34 +0800291 if (matchPiece == matchPieces.end())
Ed Tanous8a57ec02020-10-09 12:46:52 -0700292 {
293 foundPaths.emplace_back(p->path());
294 }
James Feist6714a252018-09-10 15:26:18 -0700295 }
Lei YU6a4e9732021-10-20 13:27:34 +0800296
Ed Tanous8a57ec02020-10-09 12:46:52 -0700297 if (p.depth() >= symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700298 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700299 p.disable_recursion_pending();
James Feist6714a252018-09-10 15:26:18 -0700300 }
301 }
302 return true;
303}
304
Ed Tanous201a1012024-04-03 18:07:28 -0700305bool isPowerOn()
James Feist6714a252018-09-10 15:26:18 -0700306{
James Feist71d31b22019-01-02 16:57:54 -0800307 if (!powerMatch)
James Feist6714a252018-09-10 15:26:18 -0700308 {
James Feist71d31b22019-01-02 16:57:54 -0800309 throw std::runtime_error("Power Match Not Created");
James Feist6714a252018-09-10 15:26:18 -0700310 }
James Feist71d31b22019-01-02 16:57:54 -0800311 return powerStatusOn;
312}
313
Ed Tanous201a1012024-04-03 18:07:28 -0700314bool hasBiosPost()
James Feistfc94b212019-02-06 16:14:51 -0800315{
James Feist52497fd2019-06-07 13:01:33 -0700316 if (!postMatch)
James Feistfc94b212019-02-06 16:14:51 -0800317 {
James Feist52497fd2019-06-07 13:01:33 -0700318 throw std::runtime_error("Post Match Not Created");
James Feistfc94b212019-02-06 16:14:51 -0800319 }
320 return biosHasPost;
321}
322
Ed Tanous201a1012024-04-03 18:07:28 -0700323bool isChassisOn()
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700324{
325 if (!chassisMatch)
326 {
327 throw std::runtime_error("Chassis On Match Not Created");
328 }
329 return chassisStatusOn;
330}
331
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000332bool readingStateGood(const PowerState& powerState)
333{
334 if (powerState == PowerState::on && !isPowerOn())
335 {
336 return false;
337 }
338 if (powerState == PowerState::biosPost && (!hasBiosPost() || !isPowerOn()))
339 {
340 return false;
341 }
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700342 if (powerState == PowerState::chassisOn && !isChassisOn())
343 {
344 return false;
345 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000346
347 return true;
348}
349
James Feist8aeffd92020-09-14 12:08:28 -0700350static void
351 getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
352 size_t retries = 2)
353{
354 conn->async_method_call(
355 [conn, retries](boost::system::error_code ec,
356 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700357 if (ec)
358 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700359 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700360 {
Ed Tanousbb679322022-05-16 16:10:00 -0700361 auto timer = std::make_shared<boost::asio::steady_timer>(
362 conn->get_io_context());
363 timer->expires_after(std::chrono::seconds(15));
364 timer->async_wait(
365 [timer, conn, retries](boost::system::error_code) {
366 getPowerStatus(conn, retries - 1);
367 });
James Feist8aeffd92020-09-14 12:08:28 -0700368 return;
369 }
Ed Tanousbb679322022-05-16 16:10:00 -0700370
371 // we commonly come up before power control, we'll capture the
372 // property change later
373 std::cerr << "error getting power status " << ec.message() << "\n";
374 return;
375 }
Zev Weiss6c106d62022-08-17 20:50:00 -0700376 powerStatusOn = std::get<std::string>(state).ends_with(".Running");
Patrick Williams597e8422023-10-20 11:19:01 -0500377 },
James Feist8aeffd92020-09-14 12:08:28 -0700378 power::busname, power::path, properties::interface, properties::get,
379 power::interface, power::property);
380}
381
382static void
383 getPostStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
384 size_t retries = 2)
385{
386 conn->async_method_call(
387 [conn, retries](boost::system::error_code ec,
388 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700389 if (ec)
390 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700391 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700392 {
Ed Tanousbb679322022-05-16 16:10:00 -0700393 auto timer = std::make_shared<boost::asio::steady_timer>(
394 conn->get_io_context());
395 timer->expires_after(std::chrono::seconds(15));
396 timer->async_wait(
397 [timer, conn, retries](boost::system::error_code) {
398 getPostStatus(conn, retries - 1);
399 });
James Feist8aeffd92020-09-14 12:08:28 -0700400 return;
401 }
Ed Tanousbb679322022-05-16 16:10:00 -0700402 // we commonly come up before power control, we'll capture the
403 // property change later
404 std::cerr << "error getting post status " << ec.message() << "\n";
405 return;
406 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700407 const auto& value = std::get<std::string>(state);
Ed Tanousbb679322022-05-16 16:10:00 -0700408 biosHasPost = (value != "Inactive") &&
409 (value != "xyz.openbmc_project.State.OperatingSystem."
410 "Status.OSStatus.Inactive");
Patrick Williams597e8422023-10-20 11:19:01 -0500411 },
James Feist8aeffd92020-09-14 12:08:28 -0700412 post::busname, post::path, properties::interface, properties::get,
413 post::interface, post::property);
414}
415
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700416static void
417 getChassisStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
418 size_t retries = 2)
419{
420 conn->async_method_call(
421 [conn, retries](boost::system::error_code ec,
422 const std::variant<std::string>& state) {
423 if (ec)
424 {
425 if (retries != 0U)
426 {
427 auto timer = std::make_shared<boost::asio::steady_timer>(
428 conn->get_io_context());
429 timer->expires_after(std::chrono::seconds(15));
430 timer->async_wait(
431 [timer, conn, retries](boost::system::error_code) {
432 getChassisStatus(conn, retries - 1);
433 });
434 return;
435 }
436
437 // we commonly come up before power control, we'll capture the
438 // property change later
439 std::cerr << "error getting chassis power status " << ec.message()
440 << "\n";
441 return;
442 }
443 chassisStatusOn = std::get<std::string>(state).ends_with(chassis::sOn);
Patrick Williams597e8422023-10-20 11:19:01 -0500444 },
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700445 chassis::busname, chassis::path, properties::interface, properties::get,
446 chassis::interface, chassis::property);
447}
448
Zev Weiss88cb29d2022-05-09 03:46:15 +0000449void setupPowerMatchCallback(
450 const std::shared_ptr<sdbusplus::asio::connection>& conn,
451 std::function<void(PowerState type, bool state)>&& hostStatusCallback)
James Feist71d31b22019-01-02 16:57:54 -0800452{
James Feist43d32fe2019-09-04 10:35:20 -0700453 static boost::asio::steady_timer timer(conn->get_io_context());
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700454 static boost::asio::steady_timer timerChassisOn(conn->get_io_context());
James Feist6714a252018-09-10 15:26:18 -0700455 // create a match for powergood changes, first time do a method call to
James Feist71d31b22019-01-02 16:57:54 -0800456 // cache the correct value
James Feist52497fd2019-06-07 13:01:33 -0700457 if (powerMatch)
458 {
459 return;
460 }
James Feist6714a252018-09-10 15:26:18 -0700461
Patrick Williams92f8f512022-07-22 19:26:55 -0500462 powerMatch = std::make_unique<sdbusplus::bus::match_t>(
463 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700464 "type='signal',interface='" + std::string(properties::interface) +
465 "',path='" + std::string(power::path) + "',arg0='" +
466 std::string(power::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000467 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700468 std::string objectName;
469 boost::container::flat_map<std::string, std::variant<std::string>>
470 values;
471 message.read(objectName, values);
472 auto findState = values.find(power::property);
473 if (findState != values.end())
474 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700475 bool on =
476 std::get<std::string>(findState->second).ends_with(".Running");
Ed Tanousbb679322022-05-16 16:10:00 -0700477 if (!on)
James Feist6714a252018-09-10 15:26:18 -0700478 {
Ed Tanousbb679322022-05-16 16:10:00 -0700479 timer.cancel();
480 powerStatusOn = false;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000481 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700482 return;
483 }
484 // on comes too quickly
485 timer.expires_after(std::chrono::seconds(10));
Zev Weiss88cb29d2022-05-09 03:46:15 +0000486 timer.async_wait(
487 [hostStatusCallback](boost::system::error_code ec) {
Ed Tanousbb679322022-05-16 16:10:00 -0700488 if (ec == boost::asio::error::operation_aborted)
James Feist43d32fe2019-09-04 10:35:20 -0700489 {
James Feist43d32fe2019-09-04 10:35:20 -0700490 return;
491 }
Ed Tanousbb679322022-05-16 16:10:00 -0700492 if (ec)
493 {
494 std::cerr << "Timer error " << ec.message() << "\n";
495 return;
496 }
497 powerStatusOn = true;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000498 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700499 });
500 }
Patrick Williams597e8422023-10-20 11:19:01 -0500501 });
James Feist52497fd2019-06-07 13:01:33 -0700502
Patrick Williams92f8f512022-07-22 19:26:55 -0500503 postMatch = std::make_unique<sdbusplus::bus::match_t>(
504 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700505 "type='signal',interface='" + std::string(properties::interface) +
506 "',path='" + std::string(post::path) + "',arg0='" +
507 std::string(post::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000508 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700509 std::string objectName;
510 boost::container::flat_map<std::string, std::variant<std::string>>
511 values;
512 message.read(objectName, values);
513 auto findState = values.find(post::property);
514 if (findState != values.end())
515 {
516 auto& value = std::get<std::string>(findState->second);
517 biosHasPost = (value != "Inactive") &&
518 (value != "xyz.openbmc_project.State.OperatingSystem."
519 "Status.OSStatus.Inactive");
Zev Weiss88cb29d2022-05-09 03:46:15 +0000520 hostStatusCallback(PowerState::biosPost, biosHasPost);
Ed Tanousbb679322022-05-16 16:10:00 -0700521 }
Patrick Williams597e8422023-10-20 11:19:01 -0500522 });
James Feistfc94b212019-02-06 16:14:51 -0800523
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700524 chassisMatch = std::make_unique<sdbusplus::bus::match_t>(
525 static_cast<sdbusplus::bus_t&>(*conn),
526 "type='signal',interface='" + std::string(properties::interface) +
527 "',path='" + std::string(chassis::path) + "',arg0='" +
528 std::string(chassis::interface) + "'",
Ed Tanous91423432024-04-04 08:34:21 -0700529 [hostStatusCallback = std::move(hostStatusCallback)](
530 sdbusplus::message_t& message) {
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700531 std::string objectName;
532 boost::container::flat_map<std::string, std::variant<std::string>>
533 values;
534 message.read(objectName, values);
535 auto findState = values.find(chassis::property);
536 if (findState != values.end())
537 {
538 bool on = std::get<std::string>(findState->second)
539 .ends_with(chassis::sOn);
540 if (!on)
541 {
542 timerChassisOn.cancel();
543 chassisStatusOn = false;
544 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
545 return;
546 }
547 // on comes too quickly
548 timerChassisOn.expires_after(std::chrono::seconds(10));
549 timerChassisOn.async_wait(
550 [hostStatusCallback](boost::system::error_code ec) {
551 if (ec == boost::asio::error::operation_aborted)
552 {
553 return;
554 }
555 if (ec)
556 {
557 std::cerr << "Timer error " << ec.message() << "\n";
558 return;
559 }
560 chassisStatusOn = true;
561 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
562 });
563 }
Patrick Williams597e8422023-10-20 11:19:01 -0500564 });
James Feist8aeffd92020-09-14 12:08:28 -0700565 getPowerStatus(conn);
566 getPostStatus(conn);
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700567 getChassisStatus(conn);
James Feist3f0e8762018-11-27 11:30:42 -0800568}
James Feist87d713a2018-12-06 16:06:24 -0800569
Zev Weiss88cb29d2022-05-09 03:46:15 +0000570void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
571{
572 setupPowerMatchCallback(conn, [](PowerState, bool) {});
573}
574
James Feist87d713a2018-12-06 16:06:24 -0800575// replaces limits if MinReading and MaxReading are found.
576void findLimits(std::pair<double, double>& limits,
577 const SensorBaseConfiguration* data)
578{
Ed Tanous2049bd22022-07-09 07:20:26 -0700579 if (data == nullptr)
James Feist87d713a2018-12-06 16:06:24 -0800580 {
581 return;
582 }
583 auto maxFind = data->second.find("MaxReading");
584 auto minFind = data->second.find("MinReading");
585
586 if (minFind != data->second.end())
587 {
James Feist3eb82622019-02-08 13:10:22 -0800588 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800589 }
590 if (maxFind != data->second.end())
591 {
James Feist3eb82622019-02-08 13:10:22 -0800592 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800593 }
James Feistfc94b212019-02-06 16:14:51 -0800594}
James Feist82bac4c2019-03-11 11:16:53 -0700595
596void createAssociation(
597 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
598 const std::string& path)
599{
600 if (association)
601 {
Lei YU6a4e9732021-10-20 13:27:34 +0800602 fs::path p(path);
James Feistd2543f82019-04-09 11:10:06 -0700603
James Feist82bac4c2019-03-11 11:16:53 -0700604 std::vector<Association> associations;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700605 associations.emplace_back("chassis", "all_sensors",
606 p.parent_path().string());
James Feist2adc95c2019-09-30 14:55:28 -0700607 association->register_property("Associations", associations);
James Feist82bac4c2019-03-11 11:16:53 -0700608 association->initialize();
609 }
James Feist43d32fe2019-09-04 10:35:20 -0700610}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800611
612void setInventoryAssociation(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700613 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000614 const std::string& inventoryPath, const std::string& chassisPath)
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800615{
616 if (association)
617 {
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800618 std::vector<Association> associations;
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000619 associations.emplace_back("inventory", "sensors", inventoryPath);
620 associations.emplace_back("chassis", "all_sensors", chassisPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530621
James Feist2adc95c2019-09-30 14:55:28 -0700622 association->register_property("Associations", associations);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800623 association->initialize();
624 }
625}
626
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000627std::optional<std::string> findContainingChassis(std::string_view configParent,
628 const GetSubTreeType& subtree)
629{
630 // A parent that is a chassis takes precedence
631 for (const auto& [obj, services] : subtree)
632 {
633 if (obj == configParent)
634 {
635 return obj;
636 }
637 }
638
639 // If the parent is not a chassis, the system chassis is used. This does not
640 // work if there is more than one System, but we assume there is only one
641 // today.
642 for (const auto& [obj, services] : subtree)
643 {
644 for (const auto& [service, interfaces] : services)
645 {
646 if (std::find(interfaces.begin(), interfaces.end(),
647 "xyz.openbmc_project.Inventory.Item.System") !=
648 interfaces.end())
649 {
650 return obj;
651 }
652 }
653 }
654 return std::nullopt;
655}
656
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800657void createInventoryAssoc(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700658 const std::shared_ptr<sdbusplus::asio::connection>& conn,
659 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800660 const std::string& path)
661{
662 if (!association)
663 {
664 return;
665 }
AppaRao Pulic82213c2020-02-27 01:24:58 +0530666
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000667 constexpr auto allInterfaces = std::to_array({
668 "xyz.openbmc_project.Inventory.Item.Board",
669 "xyz.openbmc_project.Inventory.Item.Chassis",
670 });
671
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800672 conn->async_method_call(
673 [association, path](const boost::system::error_code ec,
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000674 const GetSubTreeType& subtree) {
675 // The parent of the config is always the inventory object, and may be
676 // the associated chassis. If the parent is not itself a chassis or
677 // board, the sensor is associated with the system chassis.
678 std::string parent = fs::path(path).parent_path().string();
Ed Tanousbb679322022-05-16 16:10:00 -0700679 if (ec)
680 {
681 // In case of error, set the default associations and
682 // initialize the association Interface.
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000683 setInventoryAssociation(association, parent, parent);
Ed Tanousbb679322022-05-16 16:10:00 -0700684 return;
685 }
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000686 setInventoryAssociation(
687 association, parent,
688 findContainingChassis(parent, subtree).value_or(parent));
Patrick Williams597e8422023-10-20 11:19:01 -0500689 },
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000690 mapper::busName, mapper::path, mapper::interface, "GetSubTree",
691 "/xyz/openbmc_project/inventory/system", 2, allInterfaces);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800692}
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200693
694std::optional<double> readFile(const std::string& thresholdFile,
695 const double& scaleFactor)
696{
697 std::string line;
698 std::ifstream labelFile(thresholdFile);
699 if (labelFile.good())
700 {
701 std::getline(labelFile, line);
702 labelFile.close();
703
704 try
705 {
706 return std::stod(line) / scaleFactor;
707 }
708 catch (const std::invalid_argument&)
709 {
710 return std::nullopt;
711 }
712 }
713 return std::nullopt;
714}
715
716std::optional<std::tuple<std::string, std::string, std::string>>
Lei YU6a4e9732021-10-20 13:27:34 +0800717 splitFileName(const fs::path& filePath)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200718{
719 if (filePath.has_filename())
720 {
721 const auto fileName = filePath.filename().string();
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200722
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200723 size_t numberPos = std::strcspn(fileName.c_str(), "1234567890");
724 size_t itemPos = std::strcspn(fileName.c_str(), "_");
725
726 if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200727 {
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200728 return std::make_optional(
729 std::make_tuple(fileName.substr(0, numberPos),
730 fileName.substr(numberPos, itemPos - numberPos),
731 fileName.substr(itemPos + 1, fileName.size())));
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200732 }
733 }
734 return std::nullopt;
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200735}
Bruce Lee1263c3d2021-06-04 15:16:33 +0800736
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530737static void handleSpecialModeChange(const std::string& manufacturingModeStatus)
738{
739 manufacturingMode = false;
740 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
741 "SpecialMode.Modes.Manufacturing")
742 {
743 manufacturingMode = true;
744 }
Ed Tanous74cffa82022-01-25 13:00:28 -0800745 if (validateUnsecureFeature == 1)
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530746 {
747 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
748 "SpecialMode.Modes.ValidationUnsecure")
749 {
750 manufacturingMode = true;
751 }
752 }
753}
754
Bruce Lee1263c3d2021-06-04 15:16:33 +0800755void setupManufacturingModeMatch(sdbusplus::asio::connection& conn)
756{
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530757 namespace rules = sdbusplus::bus::match::rules;
758 static constexpr const char* specialModeInterface =
759 "xyz.openbmc_project.Security.SpecialMode";
760
761 const std::string filterSpecialModeIntfAdd =
762 rules::interfacesAdded() +
763 rules::argNpath(0, "/xyz/openbmc_project/security/special_mode");
Patrick Williams92f8f512022-07-22 19:26:55 -0500764 static std::unique_ptr<sdbusplus::bus::match_t> specialModeIntfMatch =
Patrick Williams597e8422023-10-20 11:19:01 -0500765 std::make_unique<sdbusplus::bus::match_t>(
766 conn, filterSpecialModeIntfAdd, [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700767 sdbusplus::message::object_path path;
768 using PropertyMap =
769 boost::container::flat_map<std::string, std::variant<std::string>>;
770 boost::container::flat_map<std::string, PropertyMap> interfaceAdded;
771 m.read(path, interfaceAdded);
772 auto intfItr = interfaceAdded.find(specialModeInterface);
773 if (intfItr == interfaceAdded.end())
774 {
775 return;
776 }
777 PropertyMap& propertyList = intfItr->second;
778 auto itr = propertyList.find("SpecialMode");
779 if (itr == propertyList.end())
780 {
781 std::cerr << "error getting SpecialMode property "
782 << "\n";
783 return;
784 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700785 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700786 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams597e8422023-10-20 11:19:01 -0500787 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800788
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530789 const std::string filterSpecialModeChange =
790 rules::type::signal() + rules::member("PropertiesChanged") +
791 rules::interface("org.freedesktop.DBus.Properties") +
792 rules::argN(0, specialModeInterface);
Patrick Williams92f8f512022-07-22 19:26:55 -0500793 static std::unique_ptr<sdbusplus::bus::match_t> specialModeChangeMatch =
794 std::make_unique<sdbusplus::bus::match_t>(conn, filterSpecialModeChange,
795 [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700796 std::string interfaceName;
797 boost::container::flat_map<std::string, std::variant<std::string>>
798 propertiesChanged;
Bruce Lee1263c3d2021-06-04 15:16:33 +0800799
Ed Tanousbb679322022-05-16 16:10:00 -0700800 m.read(interfaceName, propertiesChanged);
801 auto itr = propertiesChanged.find("SpecialMode");
802 if (itr == propertiesChanged.end())
803 {
804 return;
805 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700806 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700807 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams597e8422023-10-20 11:19:01 -0500808 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800809
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530810 conn.async_method_call(
811 [](const boost::system::error_code ec,
812 const std::variant<std::string>& getManufactMode) {
Ed Tanousbb679322022-05-16 16:10:00 -0700813 if (ec)
814 {
815 std::cerr << "error getting SpecialMode status " << ec.message()
816 << "\n";
817 return;
818 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700819 const auto* manufacturingModeStatus =
Ed Tanousbb679322022-05-16 16:10:00 -0700820 std::get_if<std::string>(&getManufactMode);
821 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams597e8422023-10-20 11:19:01 -0500822 },
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530823 "xyz.openbmc_project.SpecialMode",
824 "/xyz/openbmc_project/security/special_mode",
825 "org.freedesktop.DBus.Properties", "Get", specialModeInterface,
826 "SpecialMode");
Bruce Lee1263c3d2021-06-04 15:16:33 +0800827}
828
829bool getManufacturingMode()
830{
831 return manufacturingMode;
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000832}
Zev Weiss214d9712022-08-12 12:54:31 -0700833
834std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
835 setupPropertiesChangedMatches(
836 sdbusplus::asio::connection& bus, std::span<const char* const> types,
837 const std::function<void(sdbusplus::message_t&)>& handler)
838{
839 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches;
840 for (const char* type : types)
841 {
842 auto match = std::make_unique<sdbusplus::bus::match_t>(
843 static_cast<sdbusplus::bus_t&>(bus),
844 "type='signal',member='PropertiesChanged',path_namespace='" +
Zev Weiss054aad82022-08-18 01:37:34 -0700845 std::string(inventoryPath) + "',arg0namespace='" +
846 configInterfaceName(type) + "'",
Zev Weiss214d9712022-08-12 12:54:31 -0700847 handler);
848 matches.emplace_back(std::move(match));
849 }
850 return matches;
851}
Zev Weissdabd48d2022-08-03 15:43:17 -0700852
853std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
854 setupPropertiesChangedMatches(
855 sdbusplus::asio::connection& bus, const I2CDeviceTypeMap& typeMap,
856 const std::function<void(sdbusplus::message_t&)>& handler)
857{
858 std::vector<const char*> types;
859 types.reserve(typeMap.size());
860 for (const auto& [type, dt] : typeMap)
861 {
862 types.push_back(type.data());
863 }
864 return setupPropertiesChangedMatches(bus, {types}, handler);
865}