blob: 7a968b767aed4211ff8374af98665c2887cd0bb4 [file] [log] [blame]
Lei YU5e0dcb32019-08-02 18:04:34 +08001#include "config.h"
2
3#include "utils.hpp"
4
Lei YUad90ad52019-08-06 11:19:28 +08005#include <openssl/sha.h>
6
Lei YU5e0dcb32019-08-02 18:04:34 +08007#include <fstream>
Lei YUf77189f2019-08-07 14:26:30 +08008#include <phosphor-logging/log.hpp>
Lei YU5f3584d2019-08-27 16:28:53 +08009#include <sstream>
Lei YUf77189f2019-08-07 14:26:30 +080010
11using namespace phosphor::logging;
Lei YU5e0dcb32019-08-02 18:04:34 +080012
13namespace utils
14{
15
16namespace // anonymous
17{
18constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
19constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
20constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
21} // namespace
22
Lei YU5f3584d2019-08-27 16:28:53 +080023namespace internal
24{
25template <typename... Ts>
26std::string concat_string(Ts const&... ts)
27{
28 std::stringstream s;
29 ((s << ts << " "), ...) << std::endl;
30 return s.str();
31}
32
33// Helper function to run command
34// Returns return code and the stdout
35template <typename... Ts>
36std::pair<int, std::string> exec(Ts const&... ts)
37{
38 std::array<char, 512> buffer;
39 std::string cmd = concat_string(ts...);
40 std::stringstream result;
41 int rc;
42 FILE* pipe = popen(cmd.c_str(), "r");
43 if (!pipe)
44 {
45 throw std::runtime_error("popen() failed!");
46 }
47 while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
48 {
49 result << buffer.data();
50 }
51 rc = pclose(pipe);
52 return {rc, result.str()};
53}
54
55} // namespace internal
Lei YUf77189f2019-08-07 14:26:30 +080056const UtilsInterface& getUtils()
57{
58 static Utils utils;
59 return utils;
60}
61
62std::vector<std::string>
63 Utils::getPSUInventoryPath(sdbusplus::bus::bus& bus) const
Lei YU5e0dcb32019-08-02 18:04:34 +080064{
65 std::vector<std::string> paths;
66 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
67 MAPPER_INTERFACE, "GetSubTreePaths");
68 method.append(PSU_INVENTORY_PATH_BASE);
69 method.append(0); // Depth 0 to search all
70 method.append(std::vector<std::string>({PSU_INVENTORY_IFACE}));
71 auto reply = bus.call(method);
72
73 reply.read(paths);
74 return paths;
75}
76
Lei YUf77189f2019-08-07 14:26:30 +080077std::string Utils::getService(sdbusplus::bus::bus& bus, const char* path,
78 const char* interface) const
Lei YUad90ad52019-08-06 11:19:28 +080079{
80 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
81 MAPPER_INTERFACE, "GetObject");
82
83 mapper.append(path, std::vector<std::string>({interface}));
84 try
85 {
86 auto mapperResponseMsg = bus.call(mapper);
87
88 std::vector<std::pair<std::string, std::vector<std::string>>>
89 mapperResponse;
90 mapperResponseMsg.read(mapperResponse);
91 if (mapperResponse.empty())
92 {
93 log<level::ERR>("Error reading mapper response");
94 throw std::runtime_error("Error reading mapper response");
95 }
96 if (mapperResponse.size() < 1)
97 {
98 return "";
99 }
100 return mapperResponse[0].first;
101 }
102 catch (const sdbusplus::exception::SdBusError& ex)
103 {
104 log<level::ERR>("Mapper call failed", entry("METHOD=%d", "GetObject"),
105 entry("PATH=%s", path),
106 entry("INTERFACE=%s", interface));
107 throw std::runtime_error("Mapper call failed");
108 }
109}
110
Lei YUf77189f2019-08-07 14:26:30 +0800111std::string Utils::getVersionId(const std::string& version) const
Lei YUad90ad52019-08-06 11:19:28 +0800112{
113 if (version.empty())
114 {
115 log<level::ERR>("Error version is empty");
116 return {};
117 }
118
119 unsigned char digest[SHA512_DIGEST_LENGTH];
120 SHA512_CTX ctx;
121 SHA512_Init(&ctx);
122 SHA512_Update(&ctx, version.c_str(), strlen(version.c_str()));
123 SHA512_Final(digest, &ctx);
124 char mdString[SHA512_DIGEST_LENGTH * 2 + 1];
125 for (int i = 0; i < SHA512_DIGEST_LENGTH; i++)
126 {
127 snprintf(&mdString[i * 2], 3, "%02x", (unsigned int)digest[i]);
128 }
129
130 // Only need 8 hex digits.
131 std::string hexId = std::string(mdString);
132 return (hexId.substr(0, 8));
133}
134
Lei YU5f3584d2019-08-27 16:28:53 +0800135std::string Utils::getVersion(const std::string& inventoryPath) const
136{
137 // Invoke vendor-specify tool to get the version string, e.g.
138 // psutils get-version
139 // /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0
140 auto [rc, r] = internal::exec(PSU_VERSION_UTIL, inventoryPath);
141 return (rc == 0) ? r : "";
142}
143
Lei YUf77189f2019-08-07 14:26:30 +0800144any Utils::getPropertyImpl(sdbusplus::bus::bus& bus, const char* service,
145 const char* path, const char* interface,
146 const char* propertyName) const
147{
148 auto method = bus.new_method_call(service, path,
149 "org.freedesktop.DBus.Properties", "Get");
150 method.append(interface, propertyName);
151 try
152 {
153 PropertyType value{};
154 auto reply = bus.call(method);
155 reply.read(value);
156 return any(value);
157 }
158 catch (const sdbusplus::exception::SdBusError& ex)
159 {
160 log<level::ERR>("GetProperty call failed", entry("PATH=%s", path),
161 entry("INTERFACE=%s", interface),
162 entry("PROPERTY=%s", propertyName));
163 throw std::runtime_error("GetProperty call failed");
164 }
165}
166
Lei YU5e0dcb32019-08-02 18:04:34 +0800167} // namespace utils