blob: ac0778d6ac3159cb7ac8347fc0f228bb923c7b62 [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 */
Patrick Williams2aaf7172024-08-16 15:20:40 -040098std::optional<std::string> getFullHwmonFilePath(
99 const std::string& directory, const std::string& hwmonBaseName,
100 const std::set<std::string>& permitSet)
Jason Ling100c20b2020-08-11 14:50:33 -0700101{
102 std::optional<std::string> result;
103 std::string filename;
104 if (permitSet.empty())
105 {
106 result = directory + "/" + hwmonBaseName + "_input";
107 return result;
108 }
109 filename = directory + "/" + hwmonBaseName + "_label";
110 auto searchVal = openAndRead(filename);
111 if (!searchVal)
112 {
113 /* if the hwmon temp doesn't have a corresponding label file
114 * then use the hwmon temperature base name
115 */
116 searchVal = hwmonBaseName;
117 }
118 if (permitSet.find(*searchVal) != permitSet.end())
119 {
120 result = directory + "/" + hwmonBaseName + "_input";
121 }
122 return result;
123}
124
125/**
126 * retrieve a set of basenames and labels to allow sensor creation for.
127 * @param[in] config - a map representing the configuration for a specific
128 * device
129 * @return a set of basenames and labels to allow sensor creation for. An empty
130 * set indicates that everything is permitted.
131 */
132std::set<std::string> getPermitSet(const SensorBaseConfigMap& config)
133{
134 auto permitAttribute = config.find("Labels");
135 std::set<std::string> permitSet;
136 if (permitAttribute != config.end())
137 {
138 try
139 {
140 auto val =
141 std::get<std::vector<std::string>>(permitAttribute->second);
142
143 permitSet.insert(std::make_move_iterator(val.begin()),
144 std::make_move_iterator(val.end()));
145 }
146 catch (const std::bad_variant_access& err)
147 {
148 std::cerr << err.what()
149 << ":PermitList does not contain a list, wrong "
150 "variant type.\n";
151 }
152 }
153 return permitSet;
154}
155
James Feist6714a252018-09-10 15:26:18 -0700156bool getSensorConfiguration(
157 const std::string& type,
158 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
159 ManagedObjectType& resp, bool useCache)
160{
161 static ManagedObjectType managedObj;
Zev Weiss054aad82022-08-18 01:37:34 -0700162 std::string typeIntf = configInterfaceName(type);
James Feist6714a252018-09-10 15:26:18 -0700163
164 if (!useCache)
165 {
166 managedObj.clear();
Patrick Williams92f8f512022-07-22 19:26:55 -0500167 sdbusplus::message_t getManagedObjects =
James Feist6714a252018-09-10 15:26:18 -0700168 dbusConnection->new_method_call(
JeffLin2c5a1f22022-10-05 15:19:09 +0800169 entityManagerName, "/xyz/openbmc_project/inventory",
170 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6714a252018-09-10 15:26:18 -0700171 try
172 {
Patrick Williams92f8f512022-07-22 19:26:55 -0500173 sdbusplus::message_t reply =
James Feist6714a252018-09-10 15:26:18 -0700174 dbusConnection->call(getManagedObjects);
Yoo, Jae Hyun0e022052018-10-15 14:05:37 -0700175 reply.read(managedObj);
James Feist6714a252018-09-10 15:26:18 -0700176 }
Patrick Williams92f8f512022-07-22 19:26:55 -0500177 catch (const sdbusplus::exception_t& e)
James Feist6714a252018-09-10 15:26:18 -0700178 {
Jason Ling5747fab2019-10-02 16:46:23 -0700179 std::cerr << "While calling GetManagedObjects on service:"
180 << entityManagerName << " exception name:" << e.name()
181 << "and description:" << e.description()
182 << " was thrown\n";
James Feist6714a252018-09-10 15:26:18 -0700183 return false;
184 }
185 }
186 for (const auto& pathPair : managedObj)
187 {
Zev Weissfd3d5f72022-08-12 18:21:02 -0700188 for (const auto& [intf, cfg] : pathPair.second)
James Feist6714a252018-09-10 15:26:18 -0700189 {
Zev Weiss054aad82022-08-18 01:37:34 -0700190 if (intf.starts_with(typeIntf))
James Feist6714a252018-09-10 15:26:18 -0700191 {
Zev Weiss79d8aef2022-08-17 21:45:44 -0700192 resp.emplace(pathPair);
James Feist6714a252018-09-10 15:26:18 -0700193 break;
194 }
195 }
James Feist6714a252018-09-10 15:26:18 -0700196 }
197 return true;
198}
199
Lei YU6a4e9732021-10-20 13:27:34 +0800200bool findFiles(const fs::path& dirPath, std::string_view matchString,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700201 std::vector<fs::path>& foundPaths, int symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700202{
Lei YU6a4e9732021-10-20 13:27:34 +0800203 std::error_code ec;
204 if (!fs::exists(dirPath, ec))
Ed Tanous8a57ec02020-10-09 12:46:52 -0700205 {
James Feist6714a252018-09-10 15:26:18 -0700206 return false;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700207 }
James Feist6714a252018-09-10 15:26:18 -0700208
Lei YU6a4e9732021-10-20 13:27:34 +0800209 std::vector<std::regex> matchPieces;
210
211 size_t pos = 0;
212 std::string token;
213 // Generate the regex expressions list from the match we were given
214 while ((pos = matchString.find('/')) != std::string::npos)
215 {
216 token = matchString.substr(0, pos);
217 matchPieces.emplace_back(token);
218 matchString.remove_prefix(pos + 1);
219 }
220 matchPieces.emplace_back(std::string{matchString});
221
222 // Check if the match string contains directories, and skip the match of
223 // subdirectory if not
224 if (matchPieces.size() <= 1)
225 {
226 std::regex search(std::string{matchString});
227 std::smatch match;
228 for (auto p = fs::recursive_directory_iterator(
229 dirPath, fs::directory_options::follow_directory_symlink);
230 p != fs::recursive_directory_iterator(); ++p)
231 {
232 std::string path = p->path().string();
233 if (!is_directory(*p))
234 {
235 if (std::regex_search(path, match, search))
236 {
237 foundPaths.emplace_back(p->path());
238 }
239 }
240 if (p.depth() >= symlinkDepth)
241 {
242 p.disable_recursion_pending();
243 }
244 }
245 return true;
246 }
247
248 // The match string contains directories, verify each level of sub
249 // directories
Ed Tanous8a57ec02020-10-09 12:46:52 -0700250 for (auto p = fs::recursive_directory_iterator(
251 dirPath, fs::directory_options::follow_directory_symlink);
252 p != fs::recursive_directory_iterator(); ++p)
James Feist6714a252018-09-10 15:26:18 -0700253 {
Lei YU6a4e9732021-10-20 13:27:34 +0800254 std::vector<std::regex>::iterator matchPiece = matchPieces.begin();
255 fs::path::iterator pathIt = p->path().begin();
256 for (const fs::path& dir : dirPath)
257 {
258 if (dir.empty())
259 {
260 // When the path ends with '/', it gets am empty path
261 // skip such case.
262 break;
263 }
264 pathIt++;
265 }
266
267 while (pathIt != p->path().end())
268 {
269 // Found a path deeper than match.
270 if (matchPiece == matchPieces.end())
271 {
272 p.disable_recursion_pending();
273 break;
274 }
275 std::smatch match;
276 std::string component = pathIt->string();
277 std::regex regexPiece(*matchPiece);
278 if (!std::regex_match(component, match, regexPiece))
279 {
280 // path prefix doesn't match, no need to iterate further
281 p.disable_recursion_pending();
282 break;
283 }
284 matchPiece++;
285 pathIt++;
286 }
287
Ed Tanous8a57ec02020-10-09 12:46:52 -0700288 if (!is_directory(*p))
James Feist6714a252018-09-10 15:26:18 -0700289 {
Lei YU6a4e9732021-10-20 13:27:34 +0800290 if (matchPiece == matchPieces.end())
Ed Tanous8a57ec02020-10-09 12:46:52 -0700291 {
292 foundPaths.emplace_back(p->path());
293 }
James Feist6714a252018-09-10 15:26:18 -0700294 }
Lei YU6a4e9732021-10-20 13:27:34 +0800295
Ed Tanous8a57ec02020-10-09 12:46:52 -0700296 if (p.depth() >= symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700297 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700298 p.disable_recursion_pending();
James Feist6714a252018-09-10 15:26:18 -0700299 }
300 }
301 return true;
302}
303
Ed Tanous201a1012024-04-03 18:07:28 -0700304bool isPowerOn()
James Feist6714a252018-09-10 15:26:18 -0700305{
James Feist71d31b22019-01-02 16:57:54 -0800306 if (!powerMatch)
James Feist6714a252018-09-10 15:26:18 -0700307 {
James Feist71d31b22019-01-02 16:57:54 -0800308 throw std::runtime_error("Power Match Not Created");
James Feist6714a252018-09-10 15:26:18 -0700309 }
James Feist71d31b22019-01-02 16:57:54 -0800310 return powerStatusOn;
311}
312
Ed Tanous201a1012024-04-03 18:07:28 -0700313bool hasBiosPost()
James Feistfc94b212019-02-06 16:14:51 -0800314{
James Feist52497fd2019-06-07 13:01:33 -0700315 if (!postMatch)
James Feistfc94b212019-02-06 16:14:51 -0800316 {
James Feist52497fd2019-06-07 13:01:33 -0700317 throw std::runtime_error("Post Match Not Created");
James Feistfc94b212019-02-06 16:14:51 -0800318 }
319 return biosHasPost;
320}
321
Ed Tanous201a1012024-04-03 18:07:28 -0700322bool isChassisOn()
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700323{
324 if (!chassisMatch)
325 {
326 throw std::runtime_error("Chassis On Match Not Created");
327 }
328 return chassisStatusOn;
329}
330
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000331bool readingStateGood(const PowerState& powerState)
332{
333 if (powerState == PowerState::on && !isPowerOn())
334 {
335 return false;
336 }
337 if (powerState == PowerState::biosPost && (!hasBiosPost() || !isPowerOn()))
338 {
339 return false;
340 }
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700341 if (powerState == PowerState::chassisOn && !isChassisOn())
342 {
343 return false;
344 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000345
346 return true;
347}
348
James Feist8aeffd92020-09-14 12:08:28 -0700349static void
350 getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
351 size_t retries = 2)
352{
353 conn->async_method_call(
354 [conn, retries](boost::system::error_code ec,
355 const std::variant<std::string>& state) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400356 if (ec)
James Feist8aeffd92020-09-14 12:08:28 -0700357 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400358 if (retries != 0U)
359 {
360 auto timer = std::make_shared<boost::asio::steady_timer>(
361 conn->get_io_context());
362 timer->expires_after(std::chrono::seconds(15));
363 timer->async_wait(
364 [timer, conn, retries](boost::system::error_code) {
365 getPowerStatus(conn, retries - 1);
366 });
367 return;
368 }
369
370 // we commonly come up before power control, we'll capture the
371 // property change later
372 std::cerr << "error getting power status " << ec.message()
373 << "\n";
James Feist8aeffd92020-09-14 12:08:28 -0700374 return;
375 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400376 powerStatusOn = std::get<std::string>(state).ends_with(".Running");
377 },
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) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400389 if (ec)
James Feist8aeffd92020-09-14 12:08:28 -0700390 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400391 if (retries != 0U)
392 {
393 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 });
400 return;
401 }
402 // we commonly come up before power control, we'll capture the
403 // property change later
404 std::cerr << "error getting post status " << ec.message()
405 << "\n";
James Feist8aeffd92020-09-14 12:08:28 -0700406 return;
407 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400408 const auto& value = std::get<std::string>(state);
409 biosHasPost = (value != "Inactive") &&
410 (value != "xyz.openbmc_project.State.OperatingSystem."
411 "Status.OSStatus.Inactive");
412 },
James Feist8aeffd92020-09-14 12:08:28 -0700413 post::busname, post::path, properties::interface, properties::get,
414 post::interface, post::property);
415}
416
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700417static void
418 getChassisStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
419 size_t retries = 2)
420{
421 conn->async_method_call(
422 [conn, retries](boost::system::error_code ec,
423 const std::variant<std::string>& state) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400424 if (ec)
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700425 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400426 if (retries != 0U)
427 {
428 auto timer = std::make_shared<boost::asio::steady_timer>(
429 conn->get_io_context());
430 timer->expires_after(std::chrono::seconds(15));
431 timer->async_wait(
432 [timer, conn, retries](boost::system::error_code) {
433 getChassisStatus(conn, retries - 1);
434 });
435 return;
436 }
437
438 // we commonly come up before power control, we'll capture the
439 // property change later
440 std::cerr << "error getting chassis power status "
441 << ec.message() << "\n";
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700442 return;
443 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400444 chassisStatusOn =
445 std::get<std::string>(state).ends_with(chassis::sOn);
446 },
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700447 chassis::busname, chassis::path, properties::interface, properties::get,
448 chassis::interface, chassis::property);
449}
450
Zev Weiss88cb29d2022-05-09 03:46:15 +0000451void setupPowerMatchCallback(
452 const std::shared_ptr<sdbusplus::asio::connection>& conn,
453 std::function<void(PowerState type, bool state)>&& hostStatusCallback)
James Feist71d31b22019-01-02 16:57:54 -0800454{
James Feist43d32fe2019-09-04 10:35:20 -0700455 static boost::asio::steady_timer timer(conn->get_io_context());
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700456 static boost::asio::steady_timer timerChassisOn(conn->get_io_context());
James Feist6714a252018-09-10 15:26:18 -0700457 // create a match for powergood changes, first time do a method call to
James Feist71d31b22019-01-02 16:57:54 -0800458 // cache the correct value
James Feist52497fd2019-06-07 13:01:33 -0700459 if (powerMatch)
460 {
461 return;
462 }
James Feist6714a252018-09-10 15:26:18 -0700463
Patrick Williams92f8f512022-07-22 19:26:55 -0500464 powerMatch = std::make_unique<sdbusplus::bus::match_t>(
465 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700466 "type='signal',interface='" + std::string(properties::interface) +
467 "',path='" + std::string(power::path) + "',arg0='" +
468 std::string(power::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000469 [hostStatusCallback](sdbusplus::message_t& message) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400470 std::string objectName;
471 boost::container::flat_map<std::string, std::variant<std::string>>
472 values;
473 message.read(objectName, values);
474 auto findState = values.find(power::property);
475 if (findState != values.end())
James Feist6714a252018-09-10 15:26:18 -0700476 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400477 bool on = std::get<std::string>(findState->second)
478 .ends_with(".Running");
479 if (!on)
480 {
481 timer.cancel();
482 powerStatusOn = false;
483 hostStatusCallback(PowerState::on, powerStatusOn);
484 return;
485 }
486 // on comes too quickly
487 timer.expires_after(std::chrono::seconds(10));
488 timer.async_wait(
489 [hostStatusCallback](boost::system::error_code ec) {
490 if (ec == boost::asio::error::operation_aborted)
491 {
492 return;
493 }
494 if (ec)
495 {
496 std::cerr << "Timer error " << ec.message() << "\n";
497 return;
498 }
499 powerStatusOn = true;
500 hostStatusCallback(PowerState::on, powerStatusOn);
501 });
Ed Tanousbb679322022-05-16 16:10:00 -0700502 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400503 });
James Feist52497fd2019-06-07 13:01:33 -0700504
Patrick Williams92f8f512022-07-22 19:26:55 -0500505 postMatch = std::make_unique<sdbusplus::bus::match_t>(
506 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700507 "type='signal',interface='" + std::string(properties::interface) +
508 "',path='" + std::string(post::path) + "',arg0='" +
509 std::string(post::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000510 [hostStatusCallback](sdbusplus::message_t& message) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400511 std::string objectName;
512 boost::container::flat_map<std::string, std::variant<std::string>>
513 values;
514 message.read(objectName, values);
515 auto findState = values.find(post::property);
516 if (findState != values.end())
517 {
518 auto& value = std::get<std::string>(findState->second);
519 biosHasPost =
520 (value != "Inactive") &&
521 (value != "xyz.openbmc_project.State.OperatingSystem."
522 "Status.OSStatus.Inactive");
523 hostStatusCallback(PowerState::biosPost, biosHasPost);
524 }
525 });
James Feistfc94b212019-02-06 16:14:51 -0800526
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700527 chassisMatch = std::make_unique<sdbusplus::bus::match_t>(
528 static_cast<sdbusplus::bus_t&>(*conn),
529 "type='signal',interface='" + std::string(properties::interface) +
530 "',path='" + std::string(chassis::path) + "',arg0='" +
531 std::string(chassis::interface) + "'",
Ed Tanous91423432024-04-04 08:34:21 -0700532 [hostStatusCallback = std::move(hostStatusCallback)](
533 sdbusplus::message_t& message) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400534 std::string objectName;
535 boost::container::flat_map<std::string, std::variant<std::string>>
536 values;
537 message.read(objectName, values);
538 auto findState = values.find(chassis::property);
539 if (findState != values.end())
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700540 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400541 bool on = std::get<std::string>(findState->second)
542 .ends_with(chassis::sOn);
543 if (!on)
544 {
545 timerChassisOn.cancel();
546 chassisStatusOn = false;
547 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
548 return;
549 }
550 // on comes too quickly
551 timerChassisOn.expires_after(std::chrono::seconds(10));
552 timerChassisOn.async_wait([hostStatusCallback](
553 boost::system::error_code ec) {
554 if (ec == boost::asio::error::operation_aborted)
555 {
556 return;
557 }
558 if (ec)
559 {
560 std::cerr << "Timer error " << ec.message() << "\n";
561 return;
562 }
563 chassisStatusOn = true;
564 hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
565 });
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700566 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400567 });
James Feist8aeffd92020-09-14 12:08:28 -0700568 getPowerStatus(conn);
569 getPostStatus(conn);
Thu Nguyen6db8aae2022-10-04 08:12:48 +0700570 getChassisStatus(conn);
James Feist3f0e8762018-11-27 11:30:42 -0800571}
James Feist87d713a2018-12-06 16:06:24 -0800572
Zev Weiss88cb29d2022-05-09 03:46:15 +0000573void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
574{
575 setupPowerMatchCallback(conn, [](PowerState, bool) {});
576}
577
James Feist87d713a2018-12-06 16:06:24 -0800578// replaces limits if MinReading and MaxReading are found.
579void findLimits(std::pair<double, double>& limits,
580 const SensorBaseConfiguration* data)
581{
Ed Tanous2049bd22022-07-09 07:20:26 -0700582 if (data == nullptr)
James Feist87d713a2018-12-06 16:06:24 -0800583 {
584 return;
585 }
586 auto maxFind = data->second.find("MaxReading");
587 auto minFind = data->second.find("MinReading");
588
589 if (minFind != data->second.end())
590 {
James Feist3eb82622019-02-08 13:10:22 -0800591 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800592 }
593 if (maxFind != data->second.end())
594 {
James Feist3eb82622019-02-08 13:10:22 -0800595 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800596 }
James Feistfc94b212019-02-06 16:14:51 -0800597}
James Feist82bac4c2019-03-11 11:16:53 -0700598
599void createAssociation(
600 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
601 const std::string& path)
602{
603 if (association)
604 {
Lei YU6a4e9732021-10-20 13:27:34 +0800605 fs::path p(path);
James Feistd2543f82019-04-09 11:10:06 -0700606
James Feist82bac4c2019-03-11 11:16:53 -0700607 std::vector<Association> associations;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700608 associations.emplace_back("chassis", "all_sensors",
609 p.parent_path().string());
James Feist2adc95c2019-09-30 14:55:28 -0700610 association->register_property("Associations", associations);
James Feist82bac4c2019-03-11 11:16:53 -0700611 association->initialize();
612 }
James Feist43d32fe2019-09-04 10:35:20 -0700613}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800614
615void setInventoryAssociation(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700616 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000617 const std::string& inventoryPath, const std::string& chassisPath)
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800618{
619 if (association)
620 {
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800621 std::vector<Association> associations;
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000622 associations.emplace_back("inventory", "sensors", inventoryPath);
623 associations.emplace_back("chassis", "all_sensors", chassisPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530624
James Feist2adc95c2019-09-30 14:55:28 -0700625 association->register_property("Associations", associations);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800626 association->initialize();
627 }
628}
629
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000630std::optional<std::string> findContainingChassis(std::string_view configParent,
631 const GetSubTreeType& subtree)
632{
633 // A parent that is a chassis takes precedence
634 for (const auto& [obj, services] : subtree)
635 {
636 if (obj == configParent)
637 {
638 return obj;
639 }
640 }
641
642 // If the parent is not a chassis, the system chassis is used. This does not
643 // work if there is more than one System, but we assume there is only one
644 // today.
645 for (const auto& [obj, services] : subtree)
646 {
647 for (const auto& [service, interfaces] : services)
648 {
649 if (std::find(interfaces.begin(), interfaces.end(),
650 "xyz.openbmc_project.Inventory.Item.System") !=
651 interfaces.end())
652 {
653 return obj;
654 }
655 }
656 }
657 return std::nullopt;
658}
659
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800660void createInventoryAssoc(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700661 const std::shared_ptr<sdbusplus::asio::connection>& conn,
662 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800663 const std::string& path)
664{
665 if (!association)
666 {
667 return;
668 }
AppaRao Pulic82213c2020-02-27 01:24:58 +0530669
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000670 constexpr auto allInterfaces = std::to_array({
671 "xyz.openbmc_project.Inventory.Item.Board",
672 "xyz.openbmc_project.Inventory.Item.Chassis",
673 });
674
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800675 conn->async_method_call(
676 [association, path](const boost::system::error_code ec,
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000677 const GetSubTreeType& subtree) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400678 // The parent of the config is always the inventory object, and may
679 // be the associated chassis. If the parent is not itself a chassis
680 // or board, the sensor is associated with the system chassis.
681 std::string parent = fs::path(path).parent_path().string();
682 if (ec)
683 {
684 // In case of error, set the default associations and
685 // initialize the association Interface.
686 setInventoryAssociation(association, parent, parent);
687 return;
688 }
689 setInventoryAssociation(
690 association, parent,
691 findContainingChassis(parent, subtree).value_or(parent));
692 },
Shounak Mitra8a28bf12022-10-17 18:07:50 +0000693 mapper::busName, mapper::path, mapper::interface, "GetSubTree",
694 "/xyz/openbmc_project/inventory/system", 2, allInterfaces);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800695}
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200696
697std::optional<double> readFile(const std::string& thresholdFile,
698 const double& scaleFactor)
699{
700 std::string line;
701 std::ifstream labelFile(thresholdFile);
702 if (labelFile.good())
703 {
704 std::getline(labelFile, line);
705 labelFile.close();
706
707 try
708 {
709 return std::stod(line) / scaleFactor;
710 }
711 catch (const std::invalid_argument&)
712 {
713 return std::nullopt;
714 }
715 }
716 return std::nullopt;
717}
718
719std::optional<std::tuple<std::string, std::string, std::string>>
Lei YU6a4e9732021-10-20 13:27:34 +0800720 splitFileName(const fs::path& filePath)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200721{
722 if (filePath.has_filename())
723 {
724 const auto fileName = filePath.filename().string();
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200725
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200726 size_t numberPos = std::strcspn(fileName.c_str(), "1234567890");
727 size_t itemPos = std::strcspn(fileName.c_str(), "_");
728
729 if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200730 {
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200731 return std::make_optional(
732 std::make_tuple(fileName.substr(0, numberPos),
733 fileName.substr(numberPos, itemPos - numberPos),
734 fileName.substr(itemPos + 1, fileName.size())));
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200735 }
736 }
737 return std::nullopt;
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200738}
Bruce Lee1263c3d2021-06-04 15:16:33 +0800739
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530740static void handleSpecialModeChange(const std::string& manufacturingModeStatus)
741{
742 manufacturingMode = false;
743 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
744 "SpecialMode.Modes.Manufacturing")
745 {
746 manufacturingMode = true;
747 }
Ed Tanous74cffa82022-01-25 13:00:28 -0800748 if (validateUnsecureFeature == 1)
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530749 {
750 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
751 "SpecialMode.Modes.ValidationUnsecure")
752 {
753 manufacturingMode = true;
754 }
755 }
756}
757
Bruce Lee1263c3d2021-06-04 15:16:33 +0800758void setupManufacturingModeMatch(sdbusplus::asio::connection& conn)
759{
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530760 namespace rules = sdbusplus::bus::match::rules;
761 static constexpr const char* specialModeInterface =
762 "xyz.openbmc_project.Security.SpecialMode";
763
764 const std::string filterSpecialModeIntfAdd =
765 rules::interfacesAdded() +
766 rules::argNpath(0, "/xyz/openbmc_project/security/special_mode");
Patrick Williams92f8f512022-07-22 19:26:55 -0500767 static std::unique_ptr<sdbusplus::bus::match_t> specialModeIntfMatch =
Patrick Williams597e8422023-10-20 11:19:01 -0500768 std::make_unique<sdbusplus::bus::match_t>(
769 conn, filterSpecialModeIntfAdd, [](sdbusplus::message_t& m) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400770 sdbusplus::message::object_path path;
771 using PropertyMap =
772 boost::container::flat_map<std::string,
773 std::variant<std::string>>;
774 boost::container::flat_map<std::string, PropertyMap>
775 interfaceAdded;
776 m.read(path, interfaceAdded);
777 auto intfItr = interfaceAdded.find(specialModeInterface);
778 if (intfItr == interfaceAdded.end())
779 {
780 return;
781 }
782 PropertyMap& propertyList = intfItr->second;
783 auto itr = propertyList.find("SpecialMode");
784 if (itr == propertyList.end())
785 {
786 std::cerr << "error getting SpecialMode property "
787 << "\n";
788 return;
789 }
790 auto* manufacturingModeStatus =
791 std::get_if<std::string>(&itr->second);
792 handleSpecialModeChange(*manufacturingModeStatus);
793 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800794
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530795 const std::string filterSpecialModeChange =
796 rules::type::signal() + rules::member("PropertiesChanged") +
797 rules::interface("org.freedesktop.DBus.Properties") +
798 rules::argN(0, specialModeInterface);
Patrick Williams92f8f512022-07-22 19:26:55 -0500799 static std::unique_ptr<sdbusplus::bus::match_t> specialModeChangeMatch =
Patrick Williams2aaf7172024-08-16 15:20:40 -0400800 std::make_unique<sdbusplus::bus::match_t>(
801 conn, filterSpecialModeChange, [](sdbusplus::message_t& m) {
802 std::string interfaceName;
803 boost::container::flat_map<std::string,
804 std::variant<std::string>>
805 propertiesChanged;
Bruce Lee1263c3d2021-06-04 15:16:33 +0800806
Patrick Williams2aaf7172024-08-16 15:20:40 -0400807 m.read(interfaceName, propertiesChanged);
808 auto itr = propertiesChanged.find("SpecialMode");
809 if (itr == propertiesChanged.end())
810 {
811 return;
812 }
813 auto* manufacturingModeStatus =
814 std::get_if<std::string>(&itr->second);
815 handleSpecialModeChange(*manufacturingModeStatus);
816 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800817
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530818 conn.async_method_call(
819 [](const boost::system::error_code ec,
820 const std::variant<std::string>& getManufactMode) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400821 if (ec)
822 {
823 std::cerr << "error getting SpecialMode status "
824 << ec.message() << "\n";
825 return;
826 }
827 const auto* manufacturingModeStatus =
828 std::get_if<std::string>(&getManufactMode);
829 handleSpecialModeChange(*manufacturingModeStatus);
830 },
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530831 "xyz.openbmc_project.SpecialMode",
832 "/xyz/openbmc_project/security/special_mode",
833 "org.freedesktop.DBus.Properties", "Get", specialModeInterface,
834 "SpecialMode");
Bruce Lee1263c3d2021-06-04 15:16:33 +0800835}
836
837bool getManufacturingMode()
838{
839 return manufacturingMode;
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000840}
Zev Weiss214d9712022-08-12 12:54:31 -0700841
842std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
843 setupPropertiesChangedMatches(
844 sdbusplus::asio::connection& bus, std::span<const char* const> types,
845 const std::function<void(sdbusplus::message_t&)>& handler)
846{
847 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches;
848 for (const char* type : types)
849 {
850 auto match = std::make_unique<sdbusplus::bus::match_t>(
851 static_cast<sdbusplus::bus_t&>(bus),
852 "type='signal',member='PropertiesChanged',path_namespace='" +
Zev Weiss054aad82022-08-18 01:37:34 -0700853 std::string(inventoryPath) + "',arg0namespace='" +
854 configInterfaceName(type) + "'",
Zev Weiss214d9712022-08-12 12:54:31 -0700855 handler);
856 matches.emplace_back(std::move(match));
857 }
858 return matches;
859}
Zev Weissdabd48d2022-08-03 15:43:17 -0700860
861std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
862 setupPropertiesChangedMatches(
863 sdbusplus::asio::connection& bus, const I2CDeviceTypeMap& typeMap,
864 const std::function<void(sdbusplus::message_t&)>& handler)
865{
866 std::vector<const char*> types;
867 types.reserve(typeMap.size());
868 for (const auto& [type, dt] : typeMap)
869 {
870 types.push_back(type.data());
871 }
872 return setupPropertiesChangedMatches(bus, {types}, handler);
873}