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