blob: 7b33cb7e3979ac27915219f6d728948bd873f1db [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001/*
2// Copyright (c) 2017 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Bruce Lee1263c3d2021-06-04 15:16:33 +080017#include "dbus-sensor_config.h"
18
Ed Tanous8a57ec02020-10-09 12:46:52 -070019#include <Utils.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070020#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070021#include <sdbusplus/asio/connection.hpp>
22#include <sdbusplus/asio/object_server.hpp>
23#include <sdbusplus/bus/match.hpp>
24
James Feist24f02f22019-04-15 11:05:39 -070025#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070026#include <fstream>
Patrick Venture96e97db2019-10-31 13:44:38 -070027#include <memory>
James Feist6714a252018-09-10 15:26:18 -070028#include <regex>
Patrick Venture96e97db2019-10-31 13:44:38 -070029#include <stdexcept>
30#include <string>
31#include <utility>
32#include <variant>
33#include <vector>
James Feist6714a252018-09-10 15:26:18 -070034
James Feistcf3bce62019-01-08 10:07:19 -080035namespace fs = std::filesystem;
James Feist6714a252018-09-10 15:26:18 -070036
James Feist6ef20402019-01-07 16:45:08 -080037static bool powerStatusOn = false;
James Feistfc94b212019-02-06 16:14:51 -080038static bool biosHasPost = false;
Bruce Lee1263c3d2021-06-04 15:16:33 +080039static bool manufacturingMode = false;
James Feist58295ad2019-05-30 15:01:41 -070040
Patrick Williams92f8f512022-07-22 19:26:55 -050041static std::unique_ptr<sdbusplus::bus::match_t> powerMatch = nullptr;
42static std::unique_ptr<sdbusplus::bus::match_t> postMatch = nullptr;
James Feist71d31b22019-01-02 16:57:54 -080043
Jason Ling100c20b2020-08-11 14:50:33 -070044/**
45 * return the contents of a file
46 * @param[in] hwmonFile - the path to the file to read
47 * @return the contents of the file as a string or nullopt if the file could not
48 * be opened.
49 */
50
51std::optional<std::string> openAndRead(const std::string& hwmonFile)
52{
53 std::string fileVal;
54 std::ifstream fileStream(hwmonFile);
55 if (!fileStream.is_open())
56 {
57 return std::nullopt;
58 }
59 std::getline(fileStream, fileVal);
60 return fileVal;
61}
62
63/**
64 * given a hwmon temperature base name if valid return the full path else
65 * nullopt
66 * @param[in] directory - the hwmon sysfs directory
67 * @param[in] permitSet - a set of labels or hwmon basenames to permit. If this
68 * is empty then *everything* is permitted.
69 * @return a string to the full path of the file to create a temp sensor with or
70 * nullopt to indicate that no sensor should be created for this basename.
71 */
72std::optional<std::string>
73 getFullHwmonFilePath(const std::string& directory,
74 const std::string& hwmonBaseName,
75 const std::set<std::string>& permitSet)
76{
77 std::optional<std::string> result;
78 std::string filename;
79 if (permitSet.empty())
80 {
81 result = directory + "/" + hwmonBaseName + "_input";
82 return result;
83 }
84 filename = directory + "/" + hwmonBaseName + "_label";
85 auto searchVal = openAndRead(filename);
86 if (!searchVal)
87 {
88 /* if the hwmon temp doesn't have a corresponding label file
89 * then use the hwmon temperature base name
90 */
91 searchVal = hwmonBaseName;
92 }
93 if (permitSet.find(*searchVal) != permitSet.end())
94 {
95 result = directory + "/" + hwmonBaseName + "_input";
96 }
97 return result;
98}
99
100/**
101 * retrieve a set of basenames and labels to allow sensor creation for.
102 * @param[in] config - a map representing the configuration for a specific
103 * device
104 * @return a set of basenames and labels to allow sensor creation for. An empty
105 * set indicates that everything is permitted.
106 */
107std::set<std::string> getPermitSet(const SensorBaseConfigMap& config)
108{
109 auto permitAttribute = config.find("Labels");
110 std::set<std::string> permitSet;
111 if (permitAttribute != config.end())
112 {
113 try
114 {
115 auto val =
116 std::get<std::vector<std::string>>(permitAttribute->second);
117
118 permitSet.insert(std::make_move_iterator(val.begin()),
119 std::make_move_iterator(val.end()));
120 }
121 catch (const std::bad_variant_access& err)
122 {
123 std::cerr << err.what()
124 << ":PermitList does not contain a list, wrong "
125 "variant type.\n";
126 }
127 }
128 return permitSet;
129}
130
James Feist6714a252018-09-10 15:26:18 -0700131bool getSensorConfiguration(
132 const std::string& type,
133 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700134 ManagedObjectType& resp)
135{
136 return getSensorConfiguration(type, dbusConnection, resp, false);
137}
138
139bool getSensorConfiguration(
140 const std::string& type,
141 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
James Feist6714a252018-09-10 15:26:18 -0700142 ManagedObjectType& resp, bool useCache)
143{
144 static ManagedObjectType managedObj;
Zev Weiss054aad82022-08-18 01:37:34 -0700145 std::string typeIntf = configInterfaceName(type);
James Feist6714a252018-09-10 15:26:18 -0700146
147 if (!useCache)
148 {
149 managedObj.clear();
Patrick Williams92f8f512022-07-22 19:26:55 -0500150 sdbusplus::message_t getManagedObjects =
James Feist6714a252018-09-10 15:26:18 -0700151 dbusConnection->new_method_call(
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700152 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
James Feist6714a252018-09-10 15:26:18 -0700153 "GetManagedObjects");
James Feist6714a252018-09-10 15:26:18 -0700154 try
155 {
Patrick Williams92f8f512022-07-22 19:26:55 -0500156 sdbusplus::message_t reply =
James Feist6714a252018-09-10 15:26:18 -0700157 dbusConnection->call(getManagedObjects);
Yoo, Jae Hyun0e022052018-10-15 14:05:37 -0700158 reply.read(managedObj);
James Feist6714a252018-09-10 15:26:18 -0700159 }
Patrick Williams92f8f512022-07-22 19:26:55 -0500160 catch (const sdbusplus::exception_t& e)
James Feist6714a252018-09-10 15:26:18 -0700161 {
Jason Ling5747fab2019-10-02 16:46:23 -0700162 std::cerr << "While calling GetManagedObjects on service:"
163 << entityManagerName << " exception name:" << e.name()
164 << "and description:" << e.description()
165 << " was thrown\n";
James Feist6714a252018-09-10 15:26:18 -0700166 return false;
167 }
168 }
169 for (const auto& pathPair : managedObj)
170 {
Zev Weissfd3d5f72022-08-12 18:21:02 -0700171 for (const auto& [intf, cfg] : pathPair.second)
James Feist6714a252018-09-10 15:26:18 -0700172 {
Zev Weiss054aad82022-08-18 01:37:34 -0700173 if (intf.starts_with(typeIntf))
James Feist6714a252018-09-10 15:26:18 -0700174 {
Zev Weiss79d8aef2022-08-17 21:45:44 -0700175 resp.emplace(pathPair);
James Feist6714a252018-09-10 15:26:18 -0700176 break;
177 }
178 }
James Feist6714a252018-09-10 15:26:18 -0700179 }
180 return true;
181}
182
Lei YU6a4e9732021-10-20 13:27:34 +0800183bool findFiles(const fs::path& dirPath, std::string_view matchString,
Ed Tanous8a57ec02020-10-09 12:46:52 -0700184 std::vector<fs::path>& foundPaths, int symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700185{
Lei YU6a4e9732021-10-20 13:27:34 +0800186 std::error_code ec;
187 if (!fs::exists(dirPath, ec))
Ed Tanous8a57ec02020-10-09 12:46:52 -0700188 {
James Feist6714a252018-09-10 15:26:18 -0700189 return false;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700190 }
James Feist6714a252018-09-10 15:26:18 -0700191
Lei YU6a4e9732021-10-20 13:27:34 +0800192 std::vector<std::regex> matchPieces;
193
194 size_t pos = 0;
195 std::string token;
196 // Generate the regex expressions list from the match we were given
197 while ((pos = matchString.find('/')) != std::string::npos)
198 {
199 token = matchString.substr(0, pos);
200 matchPieces.emplace_back(token);
201 matchString.remove_prefix(pos + 1);
202 }
203 matchPieces.emplace_back(std::string{matchString});
204
205 // Check if the match string contains directories, and skip the match of
206 // subdirectory if not
207 if (matchPieces.size() <= 1)
208 {
209 std::regex search(std::string{matchString});
210 std::smatch match;
211 for (auto p = fs::recursive_directory_iterator(
212 dirPath, fs::directory_options::follow_directory_symlink);
213 p != fs::recursive_directory_iterator(); ++p)
214 {
215 std::string path = p->path().string();
216 if (!is_directory(*p))
217 {
218 if (std::regex_search(path, match, search))
219 {
220 foundPaths.emplace_back(p->path());
221 }
222 }
223 if (p.depth() >= symlinkDepth)
224 {
225 p.disable_recursion_pending();
226 }
227 }
228 return true;
229 }
230
231 // The match string contains directories, verify each level of sub
232 // directories
Ed Tanous8a57ec02020-10-09 12:46:52 -0700233 for (auto p = fs::recursive_directory_iterator(
234 dirPath, fs::directory_options::follow_directory_symlink);
235 p != fs::recursive_directory_iterator(); ++p)
James Feist6714a252018-09-10 15:26:18 -0700236 {
Lei YU6a4e9732021-10-20 13:27:34 +0800237 std::vector<std::regex>::iterator matchPiece = matchPieces.begin();
238 fs::path::iterator pathIt = p->path().begin();
239 for (const fs::path& dir : dirPath)
240 {
241 if (dir.empty())
242 {
243 // When the path ends with '/', it gets am empty path
244 // skip such case.
245 break;
246 }
247 pathIt++;
248 }
249
250 while (pathIt != p->path().end())
251 {
252 // Found a path deeper than match.
253 if (matchPiece == matchPieces.end())
254 {
255 p.disable_recursion_pending();
256 break;
257 }
258 std::smatch match;
259 std::string component = pathIt->string();
260 std::regex regexPiece(*matchPiece);
261 if (!std::regex_match(component, match, regexPiece))
262 {
263 // path prefix doesn't match, no need to iterate further
264 p.disable_recursion_pending();
265 break;
266 }
267 matchPiece++;
268 pathIt++;
269 }
270
Ed Tanous8a57ec02020-10-09 12:46:52 -0700271 if (!is_directory(*p))
James Feist6714a252018-09-10 15:26:18 -0700272 {
Lei YU6a4e9732021-10-20 13:27:34 +0800273 if (matchPiece == matchPieces.end())
Ed Tanous8a57ec02020-10-09 12:46:52 -0700274 {
275 foundPaths.emplace_back(p->path());
276 }
James Feist6714a252018-09-10 15:26:18 -0700277 }
Lei YU6a4e9732021-10-20 13:27:34 +0800278
Ed Tanous8a57ec02020-10-09 12:46:52 -0700279 if (p.depth() >= symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700280 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700281 p.disable_recursion_pending();
James Feist6714a252018-09-10 15:26:18 -0700282 }
283 }
284 return true;
285}
286
James Feist71d31b22019-01-02 16:57:54 -0800287bool isPowerOn(void)
James Feist6714a252018-09-10 15:26:18 -0700288{
James Feist71d31b22019-01-02 16:57:54 -0800289 if (!powerMatch)
James Feist6714a252018-09-10 15:26:18 -0700290 {
James Feist71d31b22019-01-02 16:57:54 -0800291 throw std::runtime_error("Power Match Not Created");
James Feist6714a252018-09-10 15:26:18 -0700292 }
James Feist71d31b22019-01-02 16:57:54 -0800293 return powerStatusOn;
294}
295
James Feistfc94b212019-02-06 16:14:51 -0800296bool hasBiosPost(void)
297{
James Feist52497fd2019-06-07 13:01:33 -0700298 if (!postMatch)
James Feistfc94b212019-02-06 16:14:51 -0800299 {
James Feist52497fd2019-06-07 13:01:33 -0700300 throw std::runtime_error("Post Match Not Created");
James Feistfc94b212019-02-06 16:14:51 -0800301 }
302 return biosHasPost;
303}
304
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000305bool readingStateGood(const PowerState& powerState)
306{
307 if (powerState == PowerState::on && !isPowerOn())
308 {
309 return false;
310 }
311 if (powerState == PowerState::biosPost && (!hasBiosPost() || !isPowerOn()))
312 {
313 return false;
314 }
315
316 return true;
317}
318
James Feist8aeffd92020-09-14 12:08:28 -0700319static void
320 getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
321 size_t retries = 2)
322{
323 conn->async_method_call(
324 [conn, retries](boost::system::error_code ec,
325 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700326 if (ec)
327 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700328 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700329 {
Ed Tanousbb679322022-05-16 16:10:00 -0700330 auto timer = std::make_shared<boost::asio::steady_timer>(
331 conn->get_io_context());
332 timer->expires_after(std::chrono::seconds(15));
333 timer->async_wait(
334 [timer, conn, retries](boost::system::error_code) {
335 getPowerStatus(conn, retries - 1);
336 });
James Feist8aeffd92020-09-14 12:08:28 -0700337 return;
338 }
Ed Tanousbb679322022-05-16 16:10:00 -0700339
340 // we commonly come up before power control, we'll capture the
341 // property change later
342 std::cerr << "error getting power status " << ec.message() << "\n";
343 return;
344 }
Zev Weiss6c106d62022-08-17 20:50:00 -0700345 powerStatusOn = std::get<std::string>(state).ends_with(".Running");
James Feist8aeffd92020-09-14 12:08:28 -0700346 },
347 power::busname, power::path, properties::interface, properties::get,
348 power::interface, power::property);
349}
350
351static void
352 getPostStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
353 size_t retries = 2)
354{
355 conn->async_method_call(
356 [conn, retries](boost::system::error_code ec,
357 const std::variant<std::string>& state) {
Ed Tanousbb679322022-05-16 16:10:00 -0700358 if (ec)
359 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700360 if (retries != 0U)
James Feist8aeffd92020-09-14 12:08:28 -0700361 {
Ed Tanousbb679322022-05-16 16:10:00 -0700362 auto timer = std::make_shared<boost::asio::steady_timer>(
363 conn->get_io_context());
364 timer->expires_after(std::chrono::seconds(15));
365 timer->async_wait(
366 [timer, conn, retries](boost::system::error_code) {
367 getPostStatus(conn, retries - 1);
368 });
James Feist8aeffd92020-09-14 12:08:28 -0700369 return;
370 }
Ed Tanousbb679322022-05-16 16:10:00 -0700371 // we commonly come up before power control, we'll capture the
372 // property change later
373 std::cerr << "error getting post status " << ec.message() << "\n";
374 return;
375 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700376 const auto& value = std::get<std::string>(state);
Ed Tanousbb679322022-05-16 16:10:00 -0700377 biosHasPost = (value != "Inactive") &&
378 (value != "xyz.openbmc_project.State.OperatingSystem."
379 "Status.OSStatus.Inactive");
James Feist8aeffd92020-09-14 12:08:28 -0700380 },
381 post::busname, post::path, properties::interface, properties::get,
382 post::interface, post::property);
383}
384
Zev Weiss88cb29d2022-05-09 03:46:15 +0000385void setupPowerMatchCallback(
386 const std::shared_ptr<sdbusplus::asio::connection>& conn,
387 std::function<void(PowerState type, bool state)>&& hostStatusCallback)
James Feist71d31b22019-01-02 16:57:54 -0800388{
James Feist43d32fe2019-09-04 10:35:20 -0700389 static boost::asio::steady_timer timer(conn->get_io_context());
James Feist6714a252018-09-10 15:26:18 -0700390 // create a match for powergood changes, first time do a method call to
James Feist71d31b22019-01-02 16:57:54 -0800391 // cache the correct value
James Feist52497fd2019-06-07 13:01:33 -0700392 if (powerMatch)
393 {
394 return;
395 }
James Feist6714a252018-09-10 15:26:18 -0700396
Patrick Williams92f8f512022-07-22 19:26:55 -0500397 powerMatch = std::make_unique<sdbusplus::bus::match_t>(
398 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700399 "type='signal',interface='" + std::string(properties::interface) +
400 "',path='" + std::string(power::path) + "',arg0='" +
401 std::string(power::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000402 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700403 std::string objectName;
404 boost::container::flat_map<std::string, std::variant<std::string>>
405 values;
406 message.read(objectName, values);
407 auto findState = values.find(power::property);
408 if (findState != values.end())
409 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700410 bool on =
411 std::get<std::string>(findState->second).ends_with(".Running");
Ed Tanousbb679322022-05-16 16:10:00 -0700412 if (!on)
James Feist6714a252018-09-10 15:26:18 -0700413 {
Ed Tanousbb679322022-05-16 16:10:00 -0700414 timer.cancel();
415 powerStatusOn = false;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000416 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700417 return;
418 }
419 // on comes too quickly
420 timer.expires_after(std::chrono::seconds(10));
Zev Weiss88cb29d2022-05-09 03:46:15 +0000421 timer.async_wait(
422 [hostStatusCallback](boost::system::error_code ec) {
Ed Tanousbb679322022-05-16 16:10:00 -0700423 if (ec == boost::asio::error::operation_aborted)
James Feist43d32fe2019-09-04 10:35:20 -0700424 {
James Feist43d32fe2019-09-04 10:35:20 -0700425 return;
426 }
Ed Tanousbb679322022-05-16 16:10:00 -0700427 if (ec)
428 {
429 std::cerr << "Timer error " << ec.message() << "\n";
430 return;
431 }
432 powerStatusOn = true;
Zev Weiss88cb29d2022-05-09 03:46:15 +0000433 hostStatusCallback(PowerState::on, powerStatusOn);
Ed Tanousbb679322022-05-16 16:10:00 -0700434 });
435 }
James Feist52497fd2019-06-07 13:01:33 -0700436 });
437
Patrick Williams92f8f512022-07-22 19:26:55 -0500438 postMatch = std::make_unique<sdbusplus::bus::match_t>(
439 static_cast<sdbusplus::bus_t&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700440 "type='signal',interface='" + std::string(properties::interface) +
441 "',path='" + std::string(post::path) + "',arg0='" +
442 std::string(post::interface) + "'",
Zev Weiss88cb29d2022-05-09 03:46:15 +0000443 [hostStatusCallback](sdbusplus::message_t& message) {
Ed Tanousbb679322022-05-16 16:10:00 -0700444 std::string objectName;
445 boost::container::flat_map<std::string, std::variant<std::string>>
446 values;
447 message.read(objectName, values);
448 auto findState = values.find(post::property);
449 if (findState != values.end())
450 {
451 auto& value = std::get<std::string>(findState->second);
452 biosHasPost = (value != "Inactive") &&
453 (value != "xyz.openbmc_project.State.OperatingSystem."
454 "Status.OSStatus.Inactive");
Zev Weiss88cb29d2022-05-09 03:46:15 +0000455 hostStatusCallback(PowerState::biosPost, biosHasPost);
Ed Tanousbb679322022-05-16 16:10:00 -0700456 }
James Feist52497fd2019-06-07 13:01:33 -0700457 });
James Feistfc94b212019-02-06 16:14:51 -0800458
James Feist8aeffd92020-09-14 12:08:28 -0700459 getPowerStatus(conn);
460 getPostStatus(conn);
James Feist3f0e8762018-11-27 11:30:42 -0800461}
James Feist87d713a2018-12-06 16:06:24 -0800462
Zev Weiss88cb29d2022-05-09 03:46:15 +0000463void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
464{
465 setupPowerMatchCallback(conn, [](PowerState, bool) {});
466}
467
James Feist87d713a2018-12-06 16:06:24 -0800468// replaces limits if MinReading and MaxReading are found.
469void findLimits(std::pair<double, double>& limits,
470 const SensorBaseConfiguration* data)
471{
Ed Tanous2049bd22022-07-09 07:20:26 -0700472 if (data == nullptr)
James Feist87d713a2018-12-06 16:06:24 -0800473 {
474 return;
475 }
476 auto maxFind = data->second.find("MaxReading");
477 auto minFind = data->second.find("MinReading");
478
479 if (minFind != data->second.end())
480 {
James Feist3eb82622019-02-08 13:10:22 -0800481 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800482 }
483 if (maxFind != data->second.end())
484 {
James Feist3eb82622019-02-08 13:10:22 -0800485 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800486 }
James Feistfc94b212019-02-06 16:14:51 -0800487}
James Feist82bac4c2019-03-11 11:16:53 -0700488
489void createAssociation(
490 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
491 const std::string& path)
492{
493 if (association)
494 {
Lei YU6a4e9732021-10-20 13:27:34 +0800495 fs::path p(path);
James Feistd2543f82019-04-09 11:10:06 -0700496
James Feist82bac4c2019-03-11 11:16:53 -0700497 std::vector<Association> associations;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700498 associations.emplace_back("chassis", "all_sensors",
499 p.parent_path().string());
James Feist2adc95c2019-09-30 14:55:28 -0700500 association->register_property("Associations", associations);
James Feist82bac4c2019-03-11 11:16:53 -0700501 association->initialize();
502 }
James Feist43d32fe2019-09-04 10:35:20 -0700503}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800504
505void setInventoryAssociation(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700506 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
AppaRao Pulic82213c2020-02-27 01:24:58 +0530507 const std::string& path,
508 const std::vector<std::string>& chassisPaths = std::vector<std::string>())
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800509{
510 if (association)
511 {
Lei YU6a4e9732021-10-20 13:27:34 +0800512 fs::path p(path);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800513 std::vector<Association> associations;
AppaRao Pulic82213c2020-02-27 01:24:58 +0530514 std::string objPath(p.parent_path().string());
515
Ed Tanous8a57ec02020-10-09 12:46:52 -0700516 associations.emplace_back("inventory", "sensors", objPath);
517 associations.emplace_back("chassis", "all_sensors", objPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530518
519 for (const std::string& chassisPath : chassisPaths)
520 {
Ed Tanous8a57ec02020-10-09 12:46:52 -0700521 associations.emplace_back("chassis", "all_sensors", chassisPath);
AppaRao Pulic82213c2020-02-27 01:24:58 +0530522 }
523
James Feist2adc95c2019-09-30 14:55:28 -0700524 association->register_property("Associations", associations);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800525 association->initialize();
526 }
527}
528
529void createInventoryAssoc(
Ed Tanous8a57ec02020-10-09 12:46:52 -0700530 const std::shared_ptr<sdbusplus::asio::connection>& conn,
531 const std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800532 const std::string& path)
533{
534 if (!association)
535 {
536 return;
537 }
AppaRao Pulic82213c2020-02-27 01:24:58 +0530538
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800539 conn->async_method_call(
540 [association, path](const boost::system::error_code ec,
AppaRao Pulic82213c2020-02-27 01:24:58 +0530541 const std::vector<std::string>& invSysObjPaths) {
Ed Tanousbb679322022-05-16 16:10:00 -0700542 if (ec)
543 {
544 // In case of error, set the default associations and
545 // initialize the association Interface.
546 setInventoryAssociation(association, path);
547 return;
548 }
549 setInventoryAssociation(association, path, invSysObjPaths);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800550 },
551 mapper::busName, mapper::path, mapper::interface, "GetSubTreePaths",
552 "/xyz/openbmc_project/inventory/system", 2,
553 std::array<std::string, 1>{
554 "xyz.openbmc_project.Inventory.Item.System"});
555}
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200556
557std::optional<double> readFile(const std::string& thresholdFile,
558 const double& scaleFactor)
559{
560 std::string line;
561 std::ifstream labelFile(thresholdFile);
562 if (labelFile.good())
563 {
564 std::getline(labelFile, line);
565 labelFile.close();
566
567 try
568 {
569 return std::stod(line) / scaleFactor;
570 }
571 catch (const std::invalid_argument&)
572 {
573 return std::nullopt;
574 }
575 }
576 return std::nullopt;
577}
578
579std::optional<std::tuple<std::string, std::string, std::string>>
Lei YU6a4e9732021-10-20 13:27:34 +0800580 splitFileName(const fs::path& filePath)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200581{
582 if (filePath.has_filename())
583 {
584 const auto fileName = filePath.filename().string();
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200585
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200586 size_t numberPos = std::strcspn(fileName.c_str(), "1234567890");
587 size_t itemPos = std::strcspn(fileName.c_str(), "_");
588
589 if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200590 {
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200591 return std::make_optional(
592 std::make_tuple(fileName.substr(0, numberPos),
593 fileName.substr(numberPos, itemPos - numberPos),
594 fileName.substr(itemPos + 1, fileName.size())));
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200595 }
596 }
597 return std::nullopt;
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200598}
Bruce Lee1263c3d2021-06-04 15:16:33 +0800599
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530600static void handleSpecialModeChange(const std::string& manufacturingModeStatus)
601{
602 manufacturingMode = false;
603 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
604 "SpecialMode.Modes.Manufacturing")
605 {
606 manufacturingMode = true;
607 }
Ed Tanous74cffa82022-01-25 13:00:28 -0800608 if (validateUnsecureFeature == 1)
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530609 {
610 if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
611 "SpecialMode.Modes.ValidationUnsecure")
612 {
613 manufacturingMode = true;
614 }
615 }
616}
617
Bruce Lee1263c3d2021-06-04 15:16:33 +0800618void setupManufacturingModeMatch(sdbusplus::asio::connection& conn)
619{
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530620 namespace rules = sdbusplus::bus::match::rules;
621 static constexpr const char* specialModeInterface =
622 "xyz.openbmc_project.Security.SpecialMode";
623
624 const std::string filterSpecialModeIntfAdd =
625 rules::interfacesAdded() +
626 rules::argNpath(0, "/xyz/openbmc_project/security/special_mode");
Patrick Williams92f8f512022-07-22 19:26:55 -0500627 static std::unique_ptr<sdbusplus::bus::match_t> specialModeIntfMatch =
628 std::make_unique<sdbusplus::bus::match_t>(conn,
629 filterSpecialModeIntfAdd,
630 [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700631 sdbusplus::message::object_path path;
632 using PropertyMap =
633 boost::container::flat_map<std::string, std::variant<std::string>>;
634 boost::container::flat_map<std::string, PropertyMap> interfaceAdded;
635 m.read(path, interfaceAdded);
636 auto intfItr = interfaceAdded.find(specialModeInterface);
637 if (intfItr == interfaceAdded.end())
638 {
639 return;
640 }
641 PropertyMap& propertyList = intfItr->second;
642 auto itr = propertyList.find("SpecialMode");
643 if (itr == propertyList.end())
644 {
645 std::cerr << "error getting SpecialMode property "
646 << "\n";
647 return;
648 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700649 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700650 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams92f8f512022-07-22 19:26:55 -0500651 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800652
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530653 const std::string filterSpecialModeChange =
654 rules::type::signal() + rules::member("PropertiesChanged") +
655 rules::interface("org.freedesktop.DBus.Properties") +
656 rules::argN(0, specialModeInterface);
Patrick Williams92f8f512022-07-22 19:26:55 -0500657 static std::unique_ptr<sdbusplus::bus::match_t> specialModeChangeMatch =
658 std::make_unique<sdbusplus::bus::match_t>(conn, filterSpecialModeChange,
659 [](sdbusplus::message_t& m) {
Ed Tanousbb679322022-05-16 16:10:00 -0700660 std::string interfaceName;
661 boost::container::flat_map<std::string, std::variant<std::string>>
662 propertiesChanged;
Bruce Lee1263c3d2021-06-04 15:16:33 +0800663
Ed Tanousbb679322022-05-16 16:10:00 -0700664 m.read(interfaceName, propertiesChanged);
665 auto itr = propertiesChanged.find("SpecialMode");
666 if (itr == propertiesChanged.end())
667 {
668 return;
669 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700670 auto* manufacturingModeStatus = std::get_if<std::string>(&itr->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700671 handleSpecialModeChange(*manufacturingModeStatus);
Patrick Williams92f8f512022-07-22 19:26:55 -0500672 });
Bruce Lee1263c3d2021-06-04 15:16:33 +0800673
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530674 conn.async_method_call(
675 [](const boost::system::error_code ec,
676 const std::variant<std::string>& getManufactMode) {
Ed Tanousbb679322022-05-16 16:10:00 -0700677 if (ec)
678 {
679 std::cerr << "error getting SpecialMode status " << ec.message()
680 << "\n";
681 return;
682 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700683 const auto* manufacturingModeStatus =
Ed Tanousbb679322022-05-16 16:10:00 -0700684 std::get_if<std::string>(&getManufactMode);
685 handleSpecialModeChange(*manufacturingModeStatus);
Arun P. Mohanan45f844a2021-11-03 22:18:09 +0530686 },
687 "xyz.openbmc_project.SpecialMode",
688 "/xyz/openbmc_project/security/special_mode",
689 "org.freedesktop.DBus.Properties", "Get", specialModeInterface,
690 "SpecialMode");
Bruce Lee1263c3d2021-06-04 15:16:33 +0800691}
692
693bool getManufacturingMode()
694{
695 return manufacturingMode;
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000696}
Zev Weiss214d9712022-08-12 12:54:31 -0700697
698std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
699 setupPropertiesChangedMatches(
700 sdbusplus::asio::connection& bus, std::span<const char* const> types,
701 const std::function<void(sdbusplus::message_t&)>& handler)
702{
703 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches;
704 for (const char* type : types)
705 {
706 auto match = std::make_unique<sdbusplus::bus::match_t>(
707 static_cast<sdbusplus::bus_t&>(bus),
708 "type='signal',member='PropertiesChanged',path_namespace='" +
Zev Weiss054aad82022-08-18 01:37:34 -0700709 std::string(inventoryPath) + "',arg0namespace='" +
710 configInterfaceName(type) + "'",
Zev Weiss214d9712022-08-12 12:54:31 -0700711 handler);
712 matches.emplace_back(std::move(match));
713 }
714 return matches;
715}