xref: /openbmc/openpower-vpd-parser/vpd-tool/src/vpd_tool_main.cpp (revision 42ca494b7cb724aba0d88d04c382b8f6744621ae)
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   */
forceReset()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   */
doMfgClean(const auto & i_mfgCleanConfirmFlag,const auto & i_syncBiosAttributesFlag)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   */
writeKeyword(const auto & i_hardwareFlag,const auto & i_keywordValueOption,const std::string & i_vpdPath,const std::string & i_recordName,const std::string & i_keywordName,const std::string & i_keywordValue)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   */
readKeyword(const auto & i_hardwareFlag,const std::string & i_vpdPath,const std::string & i_recordName,const std::string & i_keywordName,const std::string & i_filePath)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   */
checkOptionValuePair(const auto & i_objectOption,const auto & i_vpdPath,const auto & i_recordOption,const auto & i_recordName,const auto & i_keywordOption,const auto & i_keywordName,const auto & i_fileOption,const auto & i_filePath)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   */
updateFooter(CLI::App & i_app)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  
main(int argc,char ** argv)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