1 #include "version.hpp"
2 
3 #include "item_updater.hpp"
4 #include "xyz/openbmc_project/Common/error.hpp"
5 
6 #include <openssl/sha.h>
7 
8 #include <phosphor-logging/elog-errors.hpp>
9 #include <phosphor-logging/log.hpp>
10 
11 #include <fstream>
12 #include <iostream>
13 #include <sstream>
14 #include <stdexcept>
15 #include <string>
16 
17 namespace openpower
18 {
19 namespace software
20 {
21 namespace updater
22 {
23 
24 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
25 using namespace phosphor::logging;
26 using Argument = xyz::openbmc_project::Common::InvalidArgument;
27 
28 std::string Version::getId(const std::string& version)
29 {
30 
31     if (version.empty())
32     {
33         log<level::ERR>("Error version is empty");
34         return {};
35     }
36 
37     unsigned char digest[SHA512_DIGEST_LENGTH];
38     SHA512_CTX ctx;
39     SHA512_Init(&ctx);
40     SHA512_Update(&ctx, version.c_str(), strlen(version.c_str()));
41     SHA512_Final(digest, &ctx);
42     char mdString[SHA512_DIGEST_LENGTH * 2 + 1];
43     for (int i = 0; i < SHA512_DIGEST_LENGTH; i++)
44     {
45         snprintf(&mdString[i * 2], 3, "%02x", (unsigned int)digest[i]);
46     }
47 
48     // Only need 8 hex digits.
49     std::string hexId = std::string(mdString);
50     return (hexId.substr(0, 8));
51 }
52 
53 std::map<std::string, std::string>
54     Version::getValue(const std::string& filePath,
55                       std::map<std::string, std::string> keys)
56 {
57     if (filePath.empty())
58     {
59         log<level::ERR>("Error filePath is empty");
60         elog<InvalidArgument>(Argument::ARGUMENT_NAME("FilePath"),
61                               Argument::ARGUMENT_VALUE(filePath.c_str()));
62     }
63 
64     std::ifstream efile;
65     std::string line;
66     efile.exceptions(std::ifstream::failbit | std::ifstream::badbit |
67                      std::ifstream::eofbit);
68 
69     try
70     {
71         efile.open(filePath);
72         while (getline(efile, line))
73         {
74             for (auto& key : keys)
75             {
76                 auto value = key.first + "=";
77                 auto keySize = value.length();
78                 if (line.compare(0, keySize, value) == 0)
79                 {
80                     key.second = line.substr(keySize);
81                     break;
82                 }
83             }
84         }
85         efile.close();
86     }
87     catch (const std::exception& e)
88     {
89         if (!efile.eof())
90         {
91             log<level::ERR>("Error in reading file");
92         }
93         efile.close();
94     }
95 
96     return keys;
97 }
98 
99 std::pair<std::string, std::string>
100     Version::getVersions(const std::string& versionPart)
101 {
102     // versionPart contains strings like below:
103     // open-power-romulus-v2.2-rc1-48-g268344f-dirty
104     //     buildroot-2018.11.1-7-g5d7cc8c
105     //     skiboot-v6.2
106     std::istringstream iss(versionPart);
107     std::string line;
108     std::string version;
109     std::stringstream ss;
110     std::string extendedVersion;
111 
112     if (!std::getline(iss, line))
113     {
114         log<level::ERR>("Unable to read from version",
115                         entry("VERSION=%s", versionPart.c_str()));
116         return {};
117     }
118     version = line;
119 
120     while (std::getline(iss, line))
121     {
122         // Each line starts with a tab, let's trim it
123         line.erase(line.begin(),
124                    std::find_if(line.begin(), line.end(),
125                                 [](int c) { return !std::isspace(c); }));
126         ss << line << ',';
127     }
128     extendedVersion = ss.str();
129 
130     // Erase the last ',', if there is one
131     if (!extendedVersion.empty())
132     {
133         extendedVersion.pop_back();
134     }
135     return {version, extendedVersion};
136 }
137 
138 void Delete::delete_()
139 {
140     if (parent.eraseCallback)
141     {
142         parent.eraseCallback(parent.getId(parent.version()));
143     }
144 }
145 
146 void Version::updateDeleteInterface(sdbusplus::message::message& msg)
147 {
148     std::string interface, chassisState;
149     std::map<std::string, std::variant<std::string>> properties;
150 
151     msg.read(interface, properties);
152 
153     for (const auto& p : properties)
154     {
155         if (p.first == "CurrentPowerState")
156         {
157             chassisState = std::get<std::string>(p.second);
158         }
159     }
160     if (chassisState.empty())
161     {
162         // The chassis power state property did not change, return.
163         return;
164     }
165 
166     if ((parent.isVersionFunctional(this->versionId)) &&
167         (chassisState != CHASSIS_STATE_OFF))
168     {
169         if (deleteObject)
170         {
171             deleteObject.reset(nullptr);
172         }
173     }
174     else
175     {
176         if (!deleteObject)
177         {
178             deleteObject = std::make_unique<Delete>(bus, objPath, *this);
179         }
180     }
181 }
182 
183 } // namespace updater
184 } // namespace software
185 } // namespace openpower
186