15e0dcb39SLei YU #include "config.h"
25e0dcb39SLei YU
35e0dcb39SLei YU #include "utils.hpp"
45e0dcb39SLei YU
50b7c7b3aSGeorge Liu #include <openssl/evp.h>
6ad90ad51SLei YU
7*5670b188SPatrick Williams #include <phosphor-logging/log.hpp>
8*5670b188SPatrick Williams
94b9ac392SLei YU #include <algorithm>
105e0dcb39SLei YU #include <fstream>
115f3584d4SLei YU #include <sstream>
12f77189f7SLei YU
13f77189f7SLei YU using namespace phosphor::logging;
145e0dcb39SLei YU
155e0dcb39SLei YU namespace utils
165e0dcb39SLei YU {
175e0dcb39SLei YU
185e0dcb39SLei YU namespace // anonymous
195e0dcb39SLei YU {
205e0dcb39SLei YU constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
215e0dcb39SLei YU constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
225e0dcb39SLei YU constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
235e0dcb39SLei YU } // namespace
245e0dcb39SLei YU
255f3584d4SLei YU namespace internal
265f3584d4SLei YU {
275f3584d4SLei YU template <typename... Ts>
concat_string(const Ts &...ts)28*5670b188SPatrick Williams std::string concat_string(const Ts&... ts)
295f3584d4SLei YU {
305f3584d4SLei YU std::stringstream s;
315f3584d4SLei YU ((s << ts << " "), ...) << std::endl;
325f3584d4SLei YU return s.str();
335f3584d4SLei YU }
345f3584d4SLei YU
355f3584d4SLei YU // Helper function to run command
365f3584d4SLei YU // Returns return code and the stdout
375f3584d4SLei YU template <typename... Ts>
exec(const Ts &...ts)38*5670b188SPatrick Williams std::pair<int, std::string> exec(const Ts&... ts)
395f3584d4SLei YU {
405f3584d4SLei YU std::array<char, 512> buffer;
415f3584d4SLei YU std::string cmd = concat_string(ts...);
425f3584d4SLei YU std::stringstream result;
435f3584d4SLei YU int rc;
445f3584d4SLei YU FILE* pipe = popen(cmd.c_str(), "r");
455f3584d4SLei YU if (!pipe)
465f3584d4SLei YU {
475f3584d4SLei YU throw std::runtime_error("popen() failed!");
485f3584d4SLei YU }
495f3584d4SLei YU while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
505f3584d4SLei YU {
515f3584d4SLei YU result << buffer.data();
525f3584d4SLei YU }
535f3584d4SLei YU rc = pclose(pipe);
545f3584d4SLei YU return {rc, result.str()};
555f3584d4SLei YU }
565f3584d4SLei YU
575f3584d4SLei YU } // namespace internal
getUtils()58f77189f7SLei YU const UtilsInterface& getUtils()
59f77189f7SLei YU {
60f77189f7SLei YU static Utils utils;
61f77189f7SLei YU return utils;
62f77189f7SLei YU }
63f77189f7SLei YU
getPSUInventoryPath(sdbusplus::bus_t & bus) const64374fae56SPatrick Williams std::vector<std::string> Utils::getPSUInventoryPath(sdbusplus::bus_t& bus) const
655e0dcb39SLei YU {
665e0dcb39SLei YU std::vector<std::string> paths;
675e0dcb39SLei YU auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
685e0dcb39SLei YU MAPPER_INTERFACE, "GetSubTreePaths");
695e0dcb39SLei YU method.append(PSU_INVENTORY_PATH_BASE);
705e0dcb39SLei YU method.append(0); // Depth 0 to search all
715e0dcb39SLei YU method.append(std::vector<std::string>({PSU_INVENTORY_IFACE}));
725e0dcb39SLei YU auto reply = bus.call(method);
735e0dcb39SLei YU
745e0dcb39SLei YU reply.read(paths);
755e0dcb39SLei YU return paths;
765e0dcb39SLei YU }
775e0dcb39SLei YU
getService(sdbusplus::bus_t & bus,const char * path,const char * interface) const78374fae56SPatrick Williams std::string Utils::getService(sdbusplus::bus_t& bus, const char* path,
79f77189f7SLei YU const char* interface) const
80ad90ad51SLei YU {
81d0bbfa9eSLei YU auto services = getServices(bus, path, interface);
82d0bbfa9eSLei YU if (services.empty())
83d0bbfa9eSLei YU {
84d0bbfa9eSLei YU return {};
85d0bbfa9eSLei YU }
86d0bbfa9eSLei YU return services[0];
87d0bbfa9eSLei YU }
88d0bbfa9eSLei YU
getServices(sdbusplus::bus_t & bus,const char * path,const char * interface) const89374fae56SPatrick Williams std::vector<std::string> Utils::getServices(sdbusplus::bus_t& bus,
90d0bbfa9eSLei YU const char* path,
91d0bbfa9eSLei YU const char* interface) const
92d0bbfa9eSLei YU {
93ad90ad51SLei YU auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
94ad90ad51SLei YU MAPPER_INTERFACE, "GetObject");
95ad90ad51SLei YU
96ad90ad51SLei YU mapper.append(path, std::vector<std::string>({interface}));
97ad90ad51SLei YU try
98ad90ad51SLei YU {
99ad90ad51SLei YU auto mapperResponseMsg = bus.call(mapper);
100ad90ad51SLei YU
101ad90ad51SLei YU std::vector<std::pair<std::string, std::vector<std::string>>>
102ad90ad51SLei YU mapperResponse;
103ad90ad51SLei YU mapperResponseMsg.read(mapperResponse);
104ad90ad51SLei YU if (mapperResponse.empty())
105ad90ad51SLei YU {
106ad90ad51SLei YU log<level::ERR>("Error reading mapper response");
107ad90ad51SLei YU throw std::runtime_error("Error reading mapper response");
108ad90ad51SLei YU }
109d0bbfa9eSLei YU std::vector<std::string> ret;
110d0bbfa9eSLei YU for (const auto& i : mapperResponse)
111ad90ad51SLei YU {
112d0bbfa9eSLei YU ret.emplace_back(i.first);
113ad90ad51SLei YU }
114d0bbfa9eSLei YU return ret;
115ad90ad51SLei YU }
116374fae56SPatrick Williams catch (const sdbusplus::exception_t& ex)
117ad90ad51SLei YU {
1182d156252SLei YU log<level::ERR>("GetObject call failed", entry("PATH=%s", path),
119ad90ad51SLei YU entry("INTERFACE=%s", interface));
1202d156252SLei YU throw std::runtime_error("GetObject call failed");
121ad90ad51SLei YU }
122ad90ad51SLei YU }
123ad90ad51SLei YU
getVersionId(const std::string & version) const124f77189f7SLei YU std::string Utils::getVersionId(const std::string& version) const
125ad90ad51SLei YU {
126ad90ad51SLei YU if (version.empty())
127ad90ad51SLei YU {
128ad90ad51SLei YU log<level::ERR>("Error version is empty");
129ad90ad51SLei YU return {};
130ad90ad51SLei YU }
131ad90ad51SLei YU
1320b7c7b3aSGeorge Liu using EVP_MD_CTX_Ptr =
1330b7c7b3aSGeorge Liu std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_free)>;
1340b7c7b3aSGeorge Liu
1350b7c7b3aSGeorge Liu std::array<unsigned char, EVP_MAX_MD_SIZE> digest{};
1360b7c7b3aSGeorge Liu EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_new(), &::EVP_MD_CTX_free);
1370b7c7b3aSGeorge Liu
1380b7c7b3aSGeorge Liu EVP_DigestInit(ctx.get(), EVP_sha512());
1390b7c7b3aSGeorge Liu EVP_DigestUpdate(ctx.get(), version.c_str(), strlen(version.c_str()));
1400b7c7b3aSGeorge Liu EVP_DigestFinal(ctx.get(), digest.data(), nullptr);
141ad90ad51SLei YU
142ad90ad51SLei YU // Only need 8 hex digits.
1430b7c7b3aSGeorge Liu char mdString[9];
1440b7c7b3aSGeorge Liu snprintf(mdString, sizeof(mdString), "%02x%02x%02x%02x",
1450b7c7b3aSGeorge Liu (unsigned int)digest[0], (unsigned int)digest[1],
1460b7c7b3aSGeorge Liu (unsigned int)digest[2], (unsigned int)digest[3]);
1470b7c7b3aSGeorge Liu
1480b7c7b3aSGeorge Liu return mdString;
149ad90ad51SLei YU }
150ad90ad51SLei YU
getVersion(const std::string & inventoryPath) const1515f3584d4SLei YU std::string Utils::getVersion(const std::string& inventoryPath) const
1525f3584d4SLei YU {
1535f3584d4SLei YU // Invoke vendor-specify tool to get the version string, e.g.
1545f3584d4SLei YU // psutils get-version
1555f3584d4SLei YU // /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0
1565f3584d4SLei YU auto [rc, r] = internal::exec(PSU_VERSION_UTIL, inventoryPath);
1575f3584d4SLei YU return (rc == 0) ? r : "";
1585f3584d4SLei YU }
1595f3584d4SLei YU
getLatestVersion(const std::set<std::string> & versions) const1606520748dSLei YU std::string Utils::getLatestVersion(const std::set<std::string>& versions) const
1616520748dSLei YU {
1626520748dSLei YU if (versions.empty())
1636520748dSLei YU {
1646520748dSLei YU return {};
1656520748dSLei YU }
1666520748dSLei YU std::stringstream args;
1676520748dSLei YU for (const auto& s : versions)
1686520748dSLei YU {
1696520748dSLei YU args << s << " ";
1706520748dSLei YU }
1716520748dSLei YU auto [rc, r] = internal::exec(PSU_VERSION_COMPARE_UTIL, args.str());
1726520748dSLei YU return (rc == 0) ? r : "";
1736520748dSLei YU }
1746520748dSLei YU
isAssociated(const std::string & psuInventoryPath,const AssociationList & assocs) const1754b9ac392SLei YU bool Utils::isAssociated(const std::string& psuInventoryPath,
1764b9ac392SLei YU const AssociationList& assocs) const
1774b9ac392SLei YU {
1784b9ac392SLei YU return std::find_if(assocs.begin(), assocs.end(),
1794b9ac392SLei YU [&psuInventoryPath](const auto& assoc) {
1804b9ac392SLei YU return psuInventoryPath == std::get<2>(assoc);
1814b9ac392SLei YU }) != assocs.end();
1824b9ac392SLei YU }
1834b9ac392SLei YU
getPropertyImpl(sdbusplus::bus_t & bus,const char * service,const char * path,const char * interface,const char * propertyName) const184374fae56SPatrick Williams any Utils::getPropertyImpl(sdbusplus::bus_t& bus, const char* service,
185f77189f7SLei YU const char* path, const char* interface,
186f77189f7SLei YU const char* propertyName) const
187f77189f7SLei YU {
188f77189f7SLei YU auto method = bus.new_method_call(service, path,
189f77189f7SLei YU "org.freedesktop.DBus.Properties", "Get");
190f77189f7SLei YU method.append(interface, propertyName);
191f77189f7SLei YU try
192f77189f7SLei YU {
193f77189f7SLei YU PropertyType value{};
194f77189f7SLei YU auto reply = bus.call(method);
195f77189f7SLei YU reply.read(value);
196f77189f7SLei YU return any(value);
197f77189f7SLei YU }
198374fae56SPatrick Williams catch (const sdbusplus::exception_t& ex)
199f77189f7SLei YU {
200f77189f7SLei YU log<level::ERR>("GetProperty call failed", entry("PATH=%s", path),
201f77189f7SLei YU entry("INTERFACE=%s", interface),
202f77189f7SLei YU entry("PROPERTY=%s", propertyName));
203f77189f7SLei YU throw std::runtime_error("GetProperty call failed");
204f77189f7SLei YU }
205f77189f7SLei YU }
206f77189f7SLei YU
2075e0dcb39SLei YU } // namespace utils
208