xref: /openbmc/openpower-vpd-parser/vpd-tool/src/vpd_tool_main.cpp (revision 022112bc235c7f91ee998bb131f06e212dee1f6a)
1 #include "tool_constants.hpp"
2 #include "tool_utils.hpp"
3 #include "vpd_tool.hpp"
4 
5 #include <CLI/CLI.hpp>
6 
7 #include <filesystem>
8 #include <iostream>
9 
10 /**
11  * @brief Resets the VPD on DBus for all the Frus.
12  *
13  * API clears the inventory persisted data and restarts the phosphor inventory
14  * manager(PIM) DBus service and the VPD manager service. VPD manager service
15  * collects the VPD for all the FRU's listed on the system config JSON and calls
16  * PIM to publish VPD on DBus.
17  *
18  * Note: Force reset only happens if chassis is powered off.
19  *
20  * @return On success returns 0, otherwise returns -1.
21  */
22 int forceReset()
23 {
24     if (vpd::utils::isChassisPowerOff())
25     {
26         vpd::VpdTool l_vpdToolObj;
27         return l_vpdToolObj.resetVpdOnDbus();
28     }
29 
30     std::cerr
31         << "The chassis power state is not Off. Force reset operation is not allowed."
32         << std::endl;
33     return vpd::constants::FAILURE;
34 }
35 
36 /**
37  * @brief API to perform manufacturing clean.
38  *
39  * @param[in] i_mfgCleanConfirmFlag - Confirmation flag to perform manufacturing
40  * clean.
41  * @param[in] i_syncBiosAttributesFlag - Flag which specifies whether
42  * BIOS attribute related keywords need to be synced from BIOS Config Manager
43  * instead of being reset to default value.
44  *
45  * @return Status returned by cleanSystemVpd operation, success otherwise.
46  */
47 int doMfgClean(const auto& i_mfgCleanConfirmFlag,
48                const auto& i_syncBiosAttributesFlag)
49 {
50     if (i_mfgCleanConfirmFlag->empty())
51     {
52         constexpr auto MAX_CONFIRMATION_STR_LENGTH{3};
53         std::string l_confirmation{};
54         std::cout
55             << "This option resets some of the system VPD keywords to their default values. Do you really wish to proceed further?[yes/no]:";
56         std::cin >> std::setw(MAX_CONFIRMATION_STR_LENGTH) >> l_confirmation;
57 
58         if (l_confirmation != "yes")
59         {
60             return vpd::constants::SUCCESS;
61         }
62     }
63 
64     vpd::VpdTool l_vpdToolObj;
65     return l_vpdToolObj.cleanSystemVpd(!i_syncBiosAttributesFlag->empty());
66 }
67 
68 /**
69  * @brief API to write keyword's value.
70  *
71  * @param[in] i_hardwareFlag - Flag to perform write on hardware.
72  * @param[in] i_keywordValueOption - Option to read keyword value from command.
73  * @param[in] i_vpdPath - DBus object path or EEPROM path.
74  * @param[in] i_recordName - Record to be updated.
75  * @param[in] i_keywordName - Keyword to be updated.
76  * @param[in] i_keywordValue - Value to be updated in keyword.
77  *
78  * @return Status of writeKeyword operation, failure otherwise.
79  */
80 int writeKeyword(const auto& i_hardwareFlag, const auto& i_keywordValueOption,
81                  const std::string& i_vpdPath, const std::string& i_recordName,
82                  const std::string& i_keywordName,
83                  const std::string& i_keywordValue)
84 {
85     std::error_code l_ec;
86 
87     if (!i_hardwareFlag->empty() && !std::filesystem::exists(i_vpdPath, l_ec))
88     {
89         std::cerr << "Given EEPROM file path doesn't exist[" + i_vpdPath << "]."
90                   << std::endl;
91         if (l_ec)
92         {
93             std::cerr << "Reason: " + l_ec.message() << std::endl;
94         }
95         return vpd::constants::FAILURE;
96     }
97 
98     if (!i_keywordValueOption->empty() && i_keywordValue.empty())
99     {
100         std::cerr
101             << "Please provide keyword value.\nUse --value/--file to give "
102                "keyword value. Refer --help."
103             << std::endl;
104         return vpd::constants::FAILURE;
105     }
106 
107     if (i_keywordValueOption->empty())
108     {
109         std::cerr
110             << "Please provide keyword value.\nUse --value/--file to give "
111                "keyword value. Refer --help."
112             << std::endl;
113         return vpd::constants::FAILURE;
114     }
115 
116     vpd::VpdTool l_vpdToolObj;
117     return l_vpdToolObj.writeKeyword(i_vpdPath, i_recordName, i_keywordName,
118                                      i_keywordValue, !i_hardwareFlag->empty());
119 }
120 
121 /**
122  * @brief API to read keyword's value.
123  *
124  * @param[in] i_hardwareFlag - Flag to perform write on hardware.
125  * @param[in] i_vpdPath - DBus object path or EEPROM path.
126  * @param[in] i_recordName - Record to be updated.
127  * @param[in] i_keywordName - Keyword to be updated.
128  * @param[in] i_filePath - File path to save keyword's read value.
129  *
130  * @return On success return 0, otherwise return -1.
131  */
132 int readKeyword(const auto& i_hardwareFlag, const std::string& i_vpdPath,
133                 const std::string& i_recordName,
134                 const std::string& i_keywordName, const std::string& i_filePath)
135 {
136     std::error_code l_ec;
137 
138     if (!i_hardwareFlag->empty() && !std::filesystem::exists(i_vpdPath, l_ec))
139     {
140         std::string l_errMessage{
141             "Given EEPROM file path doesn't exist : " + i_vpdPath};
142 
143         if (l_ec)
144         {
145             l_errMessage += ". filesystem call exists failed, reason: " +
146                             l_ec.message();
147         }
148 
149         std::cerr << l_errMessage << std::endl;
150         return vpd::constants::FAILURE;
151     }
152 
153     bool l_isHardwareOperation = (!i_hardwareFlag->empty() ? true : false);
154 
155     vpd::VpdTool l_vpdToolObj;
156     return l_vpdToolObj.readKeyword(i_vpdPath, i_recordName, i_keywordName,
157                                     l_isHardwareOperation, i_filePath);
158 }
159 
160 /**
161  * @brief API to check option value pair in the tool command.
162  *
163  * In VPD tool command, some of the option(s) mandate values to be passed along
164  * with the option. This API based on option, detects those mandatory value(s).
165  *
166  * @param[in] i_objectOption - Option to pass object path.
167  * @param[in] i_vpdPath - Object path, DBus or EEPROM.
168  * @param[in] i_recordOption - Option to pass record name.
169  * @param[in] i_recordName - Record name.
170  * @param[in] i_keywordOption - Option to pass keyword name.
171  * @param[in] i_keywordName - Keyword name.
172  * @param[in] i_fileOption - Option to pass file path.
173  * @param[in] i_filePath - File path.
174  *
175  * @return Success if corresponding value is found against option, failure
176  * otherwise.
177  */
178 int checkOptionValuePair(const auto& i_objectOption, const auto& i_vpdPath,
179                          const auto& i_recordOption, const auto& i_recordName,
180                          const auto& i_keywordOption, const auto& i_keywordName,
181                          const auto& i_fileOption, const auto& i_filePath)
182 {
183     if (!i_objectOption->empty() && i_vpdPath.empty())
184     {
185         std::cout << "Given path is empty." << std::endl;
186         return vpd::constants::FAILURE;
187     }
188 
189     if (!i_recordOption->empty() &&
190         (i_recordName.size() != vpd::constants::RECORD_SIZE))
191     {
192         std::cerr << "Record " << i_recordName << " is not supported."
193                   << std::endl;
194         return vpd::constants::FAILURE;
195     }
196 
197     if (!i_keywordOption->empty() &&
198         (i_keywordName.size() != vpd::constants::KEYWORD_SIZE))
199     {
200         std::cerr << "Keyword " << i_keywordName << " is not supported."
201                   << std::endl;
202         return vpd::constants::FAILURE;
203     }
204 
205     if (!i_fileOption->empty() && i_filePath.empty())
206     {
207         std::cout << "File path is empty." << std::endl;
208         return vpd::constants::FAILURE;
209     }
210 
211     return vpd::constants::SUCCESS;
212 }
213 
214 /**
215  * @brief API to create app footer.
216  *
217  * @param[in] i_app - CLI::App object.
218  */
219 void updateFooter(CLI::App& i_app)
220 {
221     i_app.footer(
222         "Read:\n"
223         "    IPZ Format:\n"
224         "        From DBus to console: "
225         "vpd-tool -r -O <DBus Object Path> -R <Record Name> -K <Keyword Name>\n"
226         "        From DBus to file: "
227         "vpd-tool -r -O <DBus Object Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
228         "        From hardware to console: "
229         "vpd-tool -r -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name>\n"
230         "        From hardware to file: "
231         "vpd-tool -r -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
232         "Write:\n"
233         "    IPZ Format:\n"
234         "        On DBus: "
235         "vpd-tool -w/-u -O <DBus Object Path> -R <Record Name> -K <Keyword Name> -V <Keyword Value>\n"
236         "        On DBus, take keyword value from file:\n"
237         "              vpd-tool -w/-u -O <DBus Object Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
238         "        On hardware: "
239         "vpd-tool -w/-u -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name> -V <Keyword Value>\n"
240         "        On hardware, take keyword value from file:\n"
241         "              vpd-tool -w/-u -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
242         "Dump Object:\n"
243         "    From DBus to console: "
244         "vpd-tool -o -O <DBus Object Path>\n"
245         "Fix System VPD:\n"
246         "    vpd-tool --fixSystemVPD\n"
247         "MfgClean:\n"
248         "        Flag to clean and reset specific keywords on system VPD to its default value.\n"
249         "        vpd-tool --mfgClean\n"
250         "        To sync BIOS attribute related keywords with BIOS Config Manager:\n"
251         "        vpd-tool --mfgClean --syncBiosAttributes\n"
252         "Dump Inventory:\n"
253         "   From DBus to console in JSON format: "
254         "vpd-tool -i\n"
255         "   From DBus to console in Table format: "
256         "vpd-tool -i -t\n"
257         "Force Reset:\n"
258         "   vpd-tool --forceReset\n");
259 }
260 
261 int main(int argc, char** argv)
262 {
263     CLI::App l_app{"VPD Command Line Tool"};
264 
265     std::string l_vpdPath{};
266     std::string l_recordName{};
267     std::string l_keywordName{};
268     std::string l_filePath{};
269     std::string l_keywordValue{};
270 
271     updateFooter(l_app);
272 
273     auto l_objectOption =
274         l_app.add_option("--object, -O", l_vpdPath, "File path");
275     auto l_recordOption =
276         l_app.add_option("--record, -R", l_recordName, "Record name");
277     auto l_keywordOption =
278         l_app.add_option("--keyword, -K", l_keywordName, "Keyword name");
279 
280     auto l_fileOption =
281         l_app.add_option("--file", l_filePath, "Absolute file path");
282 
283     auto l_keywordValueOption =
284         l_app.add_option("--value, -V", l_keywordValue,
285                          "Keyword value in ascii/hex format."
286                          " ascii ex: 01234; hex ex: 0x30313233");
287 
288     auto l_hardwareFlag =
289         l_app.add_flag("--Hardware, -H", "CAUTION: Developer only option.");
290 
291     auto l_readFlag = l_app.add_flag("--readKeyword, -r", "Read keyword")
292                           ->needs(l_objectOption)
293                           ->needs(l_recordOption)
294                           ->needs(l_keywordOption);
295 
296     auto l_writeFlag =
297         l_app
298             .add_flag(
299                 "--writeKeyword, -w,--updateKeyword, -u",
300                 "Write keyword, Note: Irrespective of DBus or hardware path provided, primary and backup, redundant EEPROM(if any) paths will get updated with given key value")
301             ->needs(l_objectOption)
302             ->needs(l_recordOption)
303             ->needs(l_keywordOption);
304 
305     // ToDo: Take offset value from user for hardware path.
306 
307     auto l_dumpObjFlag =
308         l_app
309             .add_flag("--dumpObject, -o",
310                       "Dump specific properties of an inventory object")
311             ->needs(l_objectOption);
312 
313     auto l_fixSystemVpdFlag = l_app.add_flag(
314         "--fixSystemVPD",
315         "Use this option to interactively fix critical system VPD keywords");
316     auto l_dumpInventoryFlag =
317         l_app.add_flag("--dumpInventory, -i", "Dump all the inventory objects");
318 
319     auto l_mfgCleanFlag = l_app.add_flag(
320         "--mfgClean", "Manufacturing clean on system VPD keyword");
321 
322     auto l_mfgCleanConfirmFlag = l_app.add_flag(
323         "--yes", "Using this flag with --mfgClean option, assumes "
324                  "yes to proceed without confirmation.");
325 
326     auto l_dumpInventoryTableFlag =
327         l_app.add_flag("--table, -t", "Dump inventory in table format");
328 
329     auto l_mfgCleanSyncBiosAttributesFlag = l_app.add_flag(
330         "--syncBiosAttributes, -s",
331         "Using this flag with --mfgClean option, Syncs the BIOS attribute related keywords from BIOS Config Manager service instead resetting keyword's value to default value");
332 
333     auto l_forceResetFlag = l_app.add_flag(
334         "--forceReset, -f, -F",
335         "Force collect for hardware. CAUTION: Developer only option.");
336 
337     CLI11_PARSE(l_app, argc, argv);
338 
339     if (checkOptionValuePair(l_objectOption, l_vpdPath, l_recordOption,
340                              l_recordName, l_keywordOption, l_keywordName,
341                              l_fileOption, l_filePath) ==
342         vpd::constants::FAILURE)
343     {
344         return vpd::constants::FAILURE;
345     }
346 
347     if (!l_readFlag->empty())
348     {
349         return readKeyword(l_hardwareFlag, l_vpdPath, l_recordName,
350                            l_keywordName, l_filePath);
351     }
352 
353     if (!l_writeFlag->empty())
354     {
355         if ((l_keywordValueOption->empty() && l_fileOption->empty()) ||
356             (!l_keywordValueOption->empty() && !l_fileOption->empty()))
357         {
358             std::cerr
359                 << "Please provide keyword value.\nUse --value/--file to give "
360                    "keyword value. Refer --help."
361                 << std::endl;
362             return vpd::constants::FAILURE;
363         }
364 
365         if (!l_fileOption->empty())
366         {
367             l_keywordValue = vpd::utils::readValueFromFile(l_filePath);
368             if (l_keywordValue.empty())
369             {
370                 return vpd::constants::FAILURE;
371             }
372 
373             return writeKeyword(l_hardwareFlag, l_fileOption, l_vpdPath,
374                                 l_recordName, l_keywordName, l_keywordValue);
375         }
376 
377         return writeKeyword(l_hardwareFlag, l_keywordValueOption, l_vpdPath,
378                             l_recordName, l_keywordName, l_keywordValue);
379     }
380 
381     if (!l_dumpObjFlag->empty())
382     {
383         vpd::VpdTool l_vpdToolObj;
384         return l_vpdToolObj.dumpObject(l_vpdPath);
385     }
386 
387     if (!l_fixSystemVpdFlag->empty())
388     {
389         vpd::VpdTool l_vpdToolObj;
390         return l_vpdToolObj.fixSystemVpd();
391     }
392 
393     if (!l_mfgCleanFlag->empty())
394     {
395         return doMfgClean(l_mfgCleanConfirmFlag,
396                           l_mfgCleanSyncBiosAttributesFlag);
397     }
398 
399     if (!l_dumpInventoryFlag->empty())
400     {
401         vpd::VpdTool l_vpdToolObj;
402         return l_vpdToolObj.dumpInventory(!l_dumpInventoryTableFlag->empty());
403     }
404 
405     if (!l_forceResetFlag->empty())
406     {
407         return forceReset();
408     }
409 
410     std::cout << l_app.help() << std::endl;
411     return vpd::constants::FAILURE;
412 }
413