1 #pragma once
2 
3 #include "const.hpp"
4 #include "store.hpp"
5 #include "types.hpp"
6 
7 #include <iostream>
8 #include <nlohmann/json.hpp>
9 #include <optional>
10 
11 namespace openpower
12 {
13 namespace vpd
14 {
15 
16 // Map to hold record, kwd pair which can be re-stored at standby.
17 // The list of keywords for VSYS record is as per the S0 system. Should
18 // be updated for another type of systems
19 static const std::unordered_map<std::string, std::vector<std::string>>
20     svpdKwdMap{{"VSYS", {"BR", "TM", "SE", "SU", "RB", "WN", "RG", "FV"}},
21                {"VCEN", {"FC", "SE"}},
22                {"LXR0", {"LX"}},
23                {"UTIL", {"D0"}}};
24 
25 /** @brief Return the hex representation of the incoming byte
26  *
27  * @param [in] c - The input byte
28  * @returns The hex representation of the byte as a character.
29  */
30 constexpr auto toHex(size_t c)
31 {
32     constexpr auto map = "0123456789abcdef";
33     return map[c];
34 }
35 
36 namespace inventory
37 {
38 /** @brief API to obtain a dictionary of path -> services
39  * where path is in subtree and services is of the type
40  * returned by the GetObject method.
41  *
42  * @param [in] root - Root path for object subtree
43  * @param [in] depth - Maximum subtree depth required
44  * @param [in] interfaces - Array to interfaces for which
45  * result is required.
46  * @return A dictionary of Path -> services
47  */
48 MapperResponse
49     getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth,
50                                   const std::vector<std::string>& interfaces);
51 
52 } // namespace inventory
53 
54 /**@brief This API reads 2 Bytes of data and swap the read data
55  * @param[in] iterator- Pointer pointing to the data to be read
56  * @return returns 2 Byte data read at the given pointer
57  */
58 openpower::vpd::constants::LE2ByteData
59     readUInt16LE(Binary::const_iterator iterator);
60 
61 /** @brief Encodes a keyword for D-Bus.
62  *  @param[in] kw - kwd data in string format
63  *  @param[in] encoding - required for kwd data
64  */
65 std::string encodeKeyword(const std::string& kw, const std::string& encoding);
66 
67 /** @brief Reads a property from the inventory manager given object path,
68  *         intreface and property.
69  *  @param[in] obj - object path
70  *  @param[in] inf - interface
71  *  @param[in] prop - property whose value is fetched
72  *  @return [out] - value of the property
73  */
74 std::string readBusProperty(const std::string& obj, const std::string& inf,
75                             const std::string& prop);
76 
77 /** @brief A templated function to read D-Bus properties.
78  *
79  *  @param[in] service - Service path
80  *  @param[in] object - object path
81  *  @param[in] inf - interface
82  *  @param[in] prop - property whose value is fetched
83  *  @return The property value of its own type.
84  */
85 template <typename T>
86 T readDBusProperty(const std::string& service, const std::string& object,
87                    const std::string& inf, const std::string& prop)
88 {
89     T retVal{};
90     try
91     {
92         auto bus = sdbusplus::bus::new_default();
93         auto properties =
94             bus.new_method_call(service.c_str(), object.c_str(),
95                                 "org.freedesktop.DBus.Properties", "Get");
96         properties.append(inf);
97         properties.append(prop);
98         auto result = bus.call(properties);
99         result.read(retVal);
100     }
101     catch (const sdbusplus::exception::SdBusError& e)
102     {
103         std::cerr << e.what();
104     }
105     return retVal;
106 }
107 
108 /** @brief A templated method to get all D-Bus properties
109  *
110  * @param[in] service - Service path
111  * @param[in] object - Object path
112  * @param[in] inf - Interface
113  *
114  * @return All properties under the given interface.
115  */
116 template <typename T>
117 T getAllDBusProperty(const std::string& service, const std::string& object,
118                      const std::string& inf)
119 {
120     T retVal{};
121     try
122     {
123         auto bus = sdbusplus::bus::new_default();
124         auto allProperties =
125             bus.new_method_call(service.c_str(), object.c_str(),
126                                 "org.freedesktop.DBus.Properties", "GetAll");
127         allProperties.append(inf);
128 
129         auto result = bus.call(allProperties);
130         result.read(retVal);
131     }
132     catch (const sdbusplus::exception::SdBusError& e)
133     {
134         std::cerr << e.what();
135     }
136     return retVal;
137 }
138 
139 /**
140  * @brief API to create PEL entry
141  * @param[in] additionalData - Map holding the additional data
142  * @param[in] sev - Severity
143  * @param[in] errIntf - error interface
144  */
145 void createPEL(const std::map<std::string, std::string>& additionalData,
146                const constants::PelSeverity& sev, const std::string& errIntf);
147 
148 /**
149  * @brief getVpdFilePath
150  * Get vpd file path corresponding to the given object path.
151  * @param[in] - json file path
152  * @param[in] - Object path
153  * @return - Vpd file path
154  */
155 inventory::VPDfilepath getVpdFilePath(const std::string& jsonFile,
156                                       const std::string& ObjPath);
157 
158 /**
159  * @brief isPathInJson
160  * API which checks for the presence of the given eeprom path in the given json.
161  * @param[in] - eepromPath
162  * @return - true if the eeprom is present in the json; false otherwise
163  */
164 bool isPathInJson(const std::string& eepromPath);
165 
166 /**
167  * @brief isRecKwInDbusJson
168  * API which checks whether the given keyword under the given record is to be
169  * published on dbus or not. Checks against the keywords present in
170  * dbus_property.json.
171  * @param[in] - record name
172  * @param[in] - keyword name
173  * @return - true if the record-keyword pair is present in dbus_property.json;
174  * false otherwise.
175  */
176 bool isRecKwInDbusJson(const std::string& record, const std::string& keyword);
177 
178 /**
179  * @brief Check the type of VPD.
180  *
181  * Checks the type of vpd based on the start tag.
182  * @param[in] vector - Vpd data in vector format
183  *
184  * @return enum of type vpdType
185  */
186 constants::vpdType vpdTypeCheck(const Binary& vector);
187 
188 /*
189  * @brief This method does nothing. Just an empty function to return null
190  * at the end of variadic template args
191  */
192 inline std::string getCommand()
193 {
194     return "";
195 }
196 
197 /**
198  * @brief This function to arrange all arguments to make commandy
199  * @param[in] arguments to create the command
200  * @return cmd - command string
201  */
202 template <typename T, typename... Types>
203 inline std::string getCommand(T arg1, Types... args)
204 {
205     std::string cmd = " " + arg1 + getCommand(args...);
206 
207     return cmd;
208 }
209 
210 /**
211  * @brief This API takes arguments, creates a shell command line and executes
212  * them.
213  * @param[in] arguments for command
214  * @returns output of that command
215  */
216 template <typename T, typename... Types>
217 inline std::vector<std::string> executeCmd(T&& path, Types... args)
218 {
219     std::vector<std::string> stdOutput;
220     std::array<char, 128> buffer;
221 
222     std::string cmd = path + getCommand(args...);
223 
224     std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"),
225                                                   pclose);
226     if (!pipe)
227     {
228         throw std::runtime_error("popen() failed!");
229     }
230     while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
231     {
232         stdOutput.emplace_back(buffer.data());
233     }
234 
235     return stdOutput;
236 }
237 
238 /** @brief This API checks for IM and HW keywords, and based
239  *         on these values decides which system json to be used.
240  *  @param[in] vpdMap -  parsed vpd
241  *  @returns System json path
242  */
243 std::string getSystemsJson(const Parsed& vpdMap);
244 
245 /** @brief Reads HW Keyword from the vpd
246  *  @param[in] vpdMap -  parsed vpd
247  *  @returns value of HW Keyword
248  */
249 const std::string getHW(const Parsed& vpdMap);
250 
251 /** @brief Reads IM Keyword from the vpd
252  *  @param[in] vpdMap -  parsed vpd
253  *  @returns value of IM Keyword
254  */
255 const std::string getIM(const Parsed& vpdMap);
256 
257 /** @brief Translate udev event generated path to a generic /sys/bus eeprom path
258  *  @param[io] file - path generated from udev event.
259  */
260 void udevToGenericPath(std::string& file);
261 
262 /**
263  * @brief API to generate a vpd name in some pattern.
264  * This vpd-name denotes name of the bad vpd file.
265  * For i2c eeproms - the pattern of the vpd-name will be
266  * i2c-<bus-number>-<eeprom-address>. For spi eeproms - the pattern of the
267  * vpd-name will be spi-<spi-number>.
268  *
269  * @param[in] file - file path of the vpd
270  * @return the vpd-name.
271  */
272 std::string getBadVpdName(const std::string& file);
273 
274 /**
275  * @brief API which dumps the broken/bad vpd in a directory
276  * When the vpd is bad, this api places  the bad vpd file inside
277  * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user
278  * initiated BMC dump.
279  *
280  * @param[in] file - bad vpd file path
281  * @param[in] vpdVector - bad vpd vector
282  */
283 void dumpBadVpd(const std::string& file, const Binary& vpdVector);
284 
285 /*
286  * @brief This function fetches the value for given keyword in the given record
287  *        from vpd data and returns this value.
288  *
289  * @param[in] vpdMap - vpd to find out the data
290  * @param[in] rec - Record under which desired keyword exists
291  * @param[in] kwd - keyword to read the data from
292  *
293  * @returns keyword value if record/keyword combination found
294  *          empty string if record or keyword is not found.
295  */
296 const std::string getKwVal(const Parsed& vpdMap, const std::string& rec,
297                            const std::string& kwd);
298 
299 /** @brief This creates a complete command using all it's input parameters,
300  *         to bind or unbind the driver.
301  *  @param[in] devNameAddr - device address on that bus
302  *  @param[in] busType - i2c, spi
303  *  @param[in] driverType - type of driver like at24
304  *  @param[in] bindOrUnbind - either bind or unbind
305  *  @returns  Command to bind or unbind the driver.
306  */
307 inline std::string createBindUnbindDriverCmnd(const std::string& devNameAddr,
308                                               const std::string& busType,
309                                               const std::string& driverType,
310                                               const std::string& bindOrUnbind)
311 {
312     return ("echo " + devNameAddr + " > /sys/bus/" + busType + "/drivers/" +
313             driverType + "/" + bindOrUnbind);
314 }
315 
316 /**
317  * @brief Get Printable Value
318  *
319  * Checks if the vector value has non printable characters.
320  * Returns hex value if non printable char is found else
321  * returns ascii value.
322  *
323  * @param[in] vector - Reference of the Binary vector
324  * @return printable value - either in hex or in ascii.
325  */
326 std::string getPrintableValue(const Binary& vec);
327 
328 /**
329  * @brief Convert byte array to hex string.
330  * @param[in] vec - byte array
331  * @return hexadecimal string of bytes.
332  */
333 std::string byteArrayToHexString(const Binary& vec);
334 
335 /**
336  * @brief Return presence of the FRU.
337  *
338  * This API returns the presence information of the FRU corresponding to the
339  * given EEPROM. If the JSON contains no information about presence detect, this
340  * will return an empty optional. Else it will get the presence GPIO information
341  * from the JSON and return the appropriate present status.
342  * In case of GPIO find/read errors, it will return false.
343  *
344  * @param[in] json - The VPD JSON
345  * @param[in] file - EEPROM file path
346  * @return Empty optional if there is no presence info. Else returns presence
347  * based on the GPIO read.
348  */
349 std::optional<bool> isPresent(const nlohmann::json& json,
350                               const std::string& file);
351 
352 /**
353  * @brief Performs any pre-action needed to get the FRU setup for
354  * collection.
355  *
356  * @param[in] json - json object
357  * @param[in] file - eeprom file path
358  * @return - success or failure
359  */
360 bool executePreAction(const nlohmann::json& json, const std::string& file);
361 
362 /**
363  * @brief This API will be called at the end of VPD collection to perform any
364  * post actions.
365  *
366  * @param[in] json - json object
367  * @param[in] file - eeprom file path
368  */
369 void executePostFailAction(const nlohmann::json& json, const std::string& file);
370 
371 /**
372  * @brief Helper function to insert or merge in map.
373  *
374  * This method checks in the given inventory::InterfaceMap if the given
375  * interface key is existing or not. If the interface key already exists, given
376  * property map is inserted into it. If the key does'nt exist then given
377  * interface and property map pair is newly created. If the property present in
378  * propertymap already exist in the InterfaceMap, then the new property value is
379  * ignored.
380  *
381  * @param[in,out] map - map object of type inventory::InterfaceMap only.
382  * @param[in] interface - Interface name.
383  * @param[in] property - new property map that needs to be emplaced.
384  */
385 void insertOrMerge(inventory::InterfaceMap& map,
386                    const inventory::Interface& interface,
387                    inventory::PropertyMap&& property);
388 
389 /**
390  * @brief Utility API to set a D-Bus property
391  *
392  * This calls org.freedesktop.DBus.Properties;Set method with the supplied
393  * arguments
394  *
395  * @tparam T Template type of the D-Bus property
396  * @param service[in] - The D-Bus service name.
397  * @param object[in] - The D-Bus object on which the property is to be set.
398  * @param interface[in] - The D-Bus interface to which the property belongs.
399  * @param propertyName[in] - The name of the property to set.
400  * @param propertyValue[in] - The value of the property.
401  */
402 template <typename T>
403 void setBusProperty(const std::string& service, const std::string& object,
404                     const std::string& interface,
405                     const std::string& propertyName,
406                     const std::variant<T>& propertyValue)
407 {
408     try
409     {
410         auto bus = sdbusplus::bus::new_default();
411         auto method =
412             bus.new_method_call(service.c_str(), object.c_str(),
413                                 "org.freedesktop.DBus.Properties", "Set");
414         method.append(interface);
415         method.append(propertyName);
416         method.append(propertyValue);
417 
418         bus.call(method);
419     }
420     catch (const sdbusplus::exception::SdBusError& e)
421     {
422         std::cerr << e.what() << std::endl;
423     }
424 }
425 
426 /**
427  * @brief Reads BIOS Attribute by name.
428  *
429  * @param attrName[in] - The BIOS attribute name.
430  * @return std::variant<int64_t, std::string> - The BIOS attribute value.
431  */
432 std::variant<int64_t, std::string>
433     readBIOSAttribute(const std::string& attrName);
434 
435 /**
436  * @brief Returns the power state for chassis0
437  * @return The chassis power state.
438  */
439 std::string getPowerState();
440 
441 /**
442  * @brief Reads VPD from the supplied EEPROM
443  *
444  * This function reads the given VPD EEPROM file and returns its contents as a
445  * byte array. It handles any offsets into the file that need to be taken care
446  * of by looking up the VPD JSON for a possible offset key.
447  *
448  * @param js[in] - The VPD JSON Object
449  * @param file[in] - The path to the EEPROM to read
450  * @return A byte array containing the raw VPD.
451  */
452 Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file);
453 } // namespace vpd
454 } // namespace openpower