xref: /openbmc/openpower-vpd-parser/vpd-manager/include/utility/common_utility.hpp (revision c6159a29119d5e08476ed85eaf1cf47ebf9bebdb)
1 #pragma once
2 
3 #include "constants.hpp"
4 #include "error_codes.hpp"
5 #include "logger.hpp"
6 
7 #include <algorithm>
8 #include <chrono>
9 #include <cstdio>
10 #include <cstdlib>
11 #include <vector>
12 
13 /**
14  * @brief Namespace to host common utility methods.
15  *
16  * A method qualifies as a common utility function if,
17  * A)It is being used by the utility namespace at the same level as well as
18  * other files directly.
19  * B) The utility should be a leaf node and should not be dependent on any other
20  * utility.
21  *                  *******************
22  *                  | Commmon Utility | - - - - - - -
23  *                  *******************              |
24  *                          /\                       |
25  *                         /  \                      |
26  *         ****************    ****************      |
27  *         | json utility |    | dbus utility |      |
28  *         ****************    ****************      |
29  *                 \                 /               |
30  *                  \               /                |
31  *               ************************            |
32  *               | Vpd specific Utility | - - - - - - -
33  *               ************************
34  */
35 
36 namespace vpd
37 {
38 
39 namespace commonUtility
40 {
41 /**
42  * @brief API to get error code message.
43  *
44  * @param[in] i_errCode - error code.
45  *
46  * @return Error message set for that error code. Otherwise empty
47  * string.
48  */
getErrCodeMsg(const uint16_t & i_errCode)49 inline std::string getErrCodeMsg(const uint16_t& i_errCode)
50 {
51     if (errorCodeMap.find(i_errCode) != errorCodeMap.end())
52     {
53         return errorCodeMap.at(i_errCode);
54     }
55 
56     return std::string{};
57 }
58 
59 /** @brief Return the hex representation of the incoming byte.
60  *
61  * @param [in] i_aByte - The input byte.
62  * @returns Null character if input byte is out of bound else returns hex
63  * representation of the byte as a character.
64  */
toHex(const size_t & i_aByte)65 constexpr auto toHex(const size_t& i_aByte) noexcept
66 {
67     constexpr auto l_map = "0123456789abcdef";
68 
69     return (i_aByte < std::strlen(l_map)) ? l_map[i_aByte] : '\0';
70 }
71 
72 /**
73  * @brief API to return null at the end of variadic template args.
74  *
75  * @return empty string.
76  */
getCommand()77 inline std::string getCommand()
78 {
79     return "";
80 }
81 
82 /**
83  * @brief API to arrange create command.
84  *
85  * @param[in] arguments to create the command
86  * @return Command string
87  */
88 template <typename T, typename... Types>
getCommand(T i_arg1,Types...i_args)89 inline std::string getCommand(T i_arg1, Types... i_args)
90 {
91     std::string l_cmd = " " + i_arg1 + getCommand(i_args...);
92 
93     return l_cmd;
94 }
95 
96 /**
97  * @brief API to create shell command and execute.
98  *
99  * @throw std::runtime_error.
100  *
101  * @param[in] arguments for command
102  * @returns output of that command
103  */
104 template <typename T, typename... Types>
executeCmd(T && i_path,Types...i_args)105 inline std::vector<std::string> executeCmd(T&& i_path, Types... i_args)
106 {
107     std::vector<std::string> l_cmdOutput;
108     std::array<char, constants::CMD_BUFFER_LENGTH> l_buffer;
109 
110     std::string l_cmd = i_path + getCommand(i_args...);
111 
112     std::unique_ptr<FILE, decltype(&pclose)> l_cmdPipe(
113         popen(l_cmd.c_str(), "r"), pclose);
114 
115     if (!l_cmdPipe)
116     {
117         logging::logMessage(
118             "popen failed with error " + std::string(strerror(errno)));
119         throw std::runtime_error("popen failed!");
120     }
121     while (fgets(l_buffer.data(), l_buffer.size(), l_cmdPipe.get()) != nullptr)
122     {
123         l_cmdOutput.emplace_back(l_buffer.data());
124     }
125 
126     return l_cmdOutput;
127 }
128 
129 /** @brief Converts string to lower case.
130  *
131  * @param [in] i_string - Input string.
132  */
toLower(std::string & i_string)133 inline void toLower(std::string& i_string)
134 {
135     std::transform(i_string.begin(), i_string.end(), i_string.begin(),
136                    [](unsigned char l_char) { return std::tolower(l_char); });
137 }
138 
139 /**
140  * @brief An API to get hex representation of the incoming bytes.
141  *
142  * The API returns the hex represented value of the given input in string format
143  * with 0x prefix.
144  *
145  * @param[in] i_keywordValue - Vector of input byte.
146  *
147  * @return - Returns the converted string value.
148  */
convertByteVectorToHex(const types::BinaryVector & i_keywordValue)149 inline std::string convertByteVectorToHex(
150     const types::BinaryVector& i_keywordValue)
151 {
152     std::ostringstream l_oss;
153     l_oss << "0x";
154     for (const auto& l_byte : i_keywordValue)
155     {
156         l_oss << std::setfill('0') << std::setw(2) << std::hex
157               << static_cast<int>(l_byte);
158     }
159 
160     return l_oss.str();
161 }
162 
163 /**
164  * @brief An API to convert binary value into ascii/hex representation.
165  *
166  * If given data contains printable characters, ASCII formated string value of
167  * the input data will be returned. Otherwise if the data has any non-printable
168  * value, returns the hex represented value of the given data in string format.
169  *
170  * @param[in] i_keywordValue - Data in binary format.
171  *
172  * @throw - Throws std::bad_alloc or std::terminate in case of error.
173  *
174  * @return - Returns the converted string value.
175  */
getPrintableValue(const types::BinaryVector & i_keywordValue)176 inline std::string getPrintableValue(const types::BinaryVector& i_keywordValue)
177 {
178     bool l_allPrintable =
179         std::all_of(i_keywordValue.begin(), i_keywordValue.end(),
180                     [](const auto& l_byte) { return std::isprint(l_byte); });
181 
182     std::ostringstream l_oss;
183     if (l_allPrintable)
184     {
185         l_oss << std::string(i_keywordValue.begin(), i_keywordValue.end());
186     }
187     else
188     {
189         l_oss << "0x";
190         for (const auto& l_byte : i_keywordValue)
191         {
192             l_oss << std::setfill('0') << std::setw(2) << std::hex
193                   << static_cast<int>(l_byte);
194         }
195     }
196 
197     return l_oss.str();
198 }
199 
200 /**
201  * @brief API to get data in binary format.
202  *
203  * This API converts given string value present in hexadecimal or decimal format
204  * into array of binary data.
205  *
206  * @param[in] i_value - Input data.
207  *
208  * @return - Array of binary data on success, throws as exception in case
209  * of any error.
210  *
211  * @throw std::runtime_error, std::out_of_range, std::bad_alloc,
212  * std::invalid_argument
213  */
convertToBinary(const std::string & i_value)214 inline types::BinaryVector convertToBinary(const std::string& i_value)
215 {
216     if (i_value.empty())
217     {
218         throw std::runtime_error("Empty input provided");
219     }
220 
221     types::BinaryVector l_binaryValue{};
222 
223     if (i_value.substr(0, 2).compare("0x") == constants::STR_CMP_SUCCESS)
224     {
225         if (i_value.length() % 2 != 0)
226         {
227             throw std::runtime_error(
228                 "Write option accepts 2 digit hex numbers. (Ex. 0x1 "
229                 "should be given as 0x01).");
230         }
231 
232         auto l_value = i_value.substr(2);
233 
234         if (l_value.empty())
235         {
236             throw std::runtime_error(
237                 "Provide a valid hexadecimal input. (Ex. 0x30313233)");
238         }
239 
240         if (l_value.find_first_not_of("0123456789abcdefABCDEF") !=
241             std::string::npos)
242         {
243             throw std::runtime_error("Provide a valid hexadecimal input.");
244         }
245 
246         for (size_t l_pos = 0; l_pos < l_value.length(); l_pos += 2)
247         {
248             uint8_t l_byte = static_cast<uint8_t>(
249                 std::stoi(l_value.substr(l_pos, 2), nullptr, 16));
250             l_binaryValue.push_back(l_byte);
251         }
252     }
253     else
254     {
255         l_binaryValue.assign(i_value.begin(), i_value.end());
256     }
257     return l_binaryValue;
258 }
259 
260 /**
261  * @brief API to get current time stamp since Epoch.
262  *
263  * @return time stamp in seconds.
264  */
getCurrentTimeSinceEpoch()265 inline size_t getCurrentTimeSinceEpoch() noexcept
266 {
267     // Use high_resolution_clock for better precision
268     const auto l_now = std::chrono::high_resolution_clock::now();
269     auto l_durationSinceEpoch = l_now.time_since_epoch();
270 
271     auto l_timeStampSeconds =
272         std::chrono::duration_cast<std::chrono::seconds>(l_durationSinceEpoch)
273             .count();
274     return static_cast<size_t>(l_timeStampSeconds);
275 }
276 
277 } // namespace commonUtility
278 } // namespace vpd
279