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