blob: e0bbf7a3965bbfbe7878cc654a02254085881f50 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#include "tool_constants.hpp"
Anupama B R951d6602025-01-18 09:52:33 -06002#include "tool_utils.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05003#include "vpd_tool.hpp"
4
5#include <CLI/CLI.hpp>
6
7#include <filesystem>
8#include <iostream>
9
10/**
Anupama B R6be2c012025-01-23 02:59:27 -060011 * @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 */
22int 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/**
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050037 * @brief API to perform manufacturing clean.
38 *
39 * @param[in] i_mfgCleanConfirmFlag - Confirmation flag to perform manufacturing
40 * clean.
Souvik Roy63089422025-01-23 02:48:21 -060041 * @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.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050044 *
45 * @return Status returned by cleanSystemVpd operation, success otherwise.
46 */
Souvik Roy63089422025-01-23 02:48:21 -060047int doMfgClean(const auto& i_mfgCleanConfirmFlag,
48 const auto& i_syncBiosAttributesFlag)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050049{
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;
Souvik Roy963e8422025-05-05 02:18:22 -050065
66 // delete the vpd dump directory
67 l_vpdToolObj.clearVpdDumpDir();
68
Souvik Roy63089422025-01-23 02:48:21 -060069 return l_vpdToolObj.cleanSystemVpd(!i_syncBiosAttributesFlag->empty());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050070}
71
72/**
73 * @brief API to write keyword's value.
74 *
75 * @param[in] i_hardwareFlag - Flag to perform write on hardware.
76 * @param[in] i_keywordValueOption - Option to read keyword value from command.
77 * @param[in] i_vpdPath - DBus object path or EEPROM path.
78 * @param[in] i_recordName - Record to be updated.
79 * @param[in] i_keywordName - Keyword to be updated.
80 * @param[in] i_keywordValue - Value to be updated in keyword.
81 *
82 * @return Status of writeKeyword operation, failure otherwise.
83 */
84int writeKeyword(const auto& i_hardwareFlag, const auto& i_keywordValueOption,
85 const std::string& i_vpdPath, const std::string& i_recordName,
86 const std::string& i_keywordName,
87 const std::string& i_keywordValue)
88{
89 std::error_code l_ec;
90
91 if (!i_hardwareFlag->empty() && !std::filesystem::exists(i_vpdPath, l_ec))
92 {
Anupama B R42ca4942025-02-12 00:13:33 -060093 std::cerr << "Given EEPROM file path doesn't exist[" + i_vpdPath << "]."
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050094 << std::endl;
Anupama B R42ca4942025-02-12 00:13:33 -060095 if (l_ec)
96 {
97 std::cerr << "Reason: " + l_ec.message() << std::endl;
98 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050099 return vpd::constants::FAILURE;
100 }
101
102 if (!i_keywordValueOption->empty() && i_keywordValue.empty())
103 {
104 std::cerr
105 << "Please provide keyword value.\nUse --value/--file to give "
106 "keyword value. Refer --help."
107 << std::endl;
108 return vpd::constants::FAILURE;
109 }
110
111 if (i_keywordValueOption->empty())
112 {
113 std::cerr
114 << "Please provide keyword value.\nUse --value/--file to give "
115 "keyword value. Refer --help."
116 << std::endl;
117 return vpd::constants::FAILURE;
118 }
119
Rekha Aparna9f255f52025-04-23 05:25:07 -0500120 if (i_keywordName == vpd::constants::KwdIM)
121 {
122 if (!(i_keywordValue.substr(0, 2).compare("0x") ==
123 vpd::constants::STR_CMP_SUCCESS))
124 {
125 std::cerr << "Please provide IM value in hex format." << std::endl;
126 return vpd::constants::FAILURE;
127 }
128
129 if (std::find(vpd::constants::validImValues.begin(),
130 vpd::constants::validImValues.end(), i_keywordValue) ==
131 vpd::constants::validImValues.end())
132 {
133 std::cerr << "Given IM value [" << i_keywordValue
134 << "] doesn't match with any of the valid system type."
135 << std::endl;
136 return vpd::constants::FAILURE;
137 }
138 }
139
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500140 vpd::VpdTool l_vpdToolObj;
141 return l_vpdToolObj.writeKeyword(i_vpdPath, i_recordName, i_keywordName,
142 i_keywordValue, !i_hardwareFlag->empty());
143}
144
145/**
146 * @brief API to read keyword's value.
147 *
148 * @param[in] i_hardwareFlag - Flag to perform write on hardware.
149 * @param[in] i_vpdPath - DBus object path or EEPROM path.
150 * @param[in] i_recordName - Record to be updated.
151 * @param[in] i_keywordName - Keyword to be updated.
152 * @param[in] i_filePath - File path to save keyword's read value.
153 *
Anupama B Rd3539902025-01-20 05:10:00 -0600154 * @return On success return 0, otherwise return -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500155 */
156int readKeyword(const auto& i_hardwareFlag, const std::string& i_vpdPath,
157 const std::string& i_recordName,
158 const std::string& i_keywordName, const std::string& i_filePath)
159{
160 std::error_code l_ec;
161
162 if (!i_hardwareFlag->empty() && !std::filesystem::exists(i_vpdPath, l_ec))
163 {
164 std::string l_errMessage{
165 "Given EEPROM file path doesn't exist : " + i_vpdPath};
166
167 if (l_ec)
168 {
169 l_errMessage += ". filesystem call exists failed, reason: " +
170 l_ec.message();
171 }
172
173 std::cerr << l_errMessage << std::endl;
174 return vpd::constants::FAILURE;
175 }
176
177 bool l_isHardwareOperation = (!i_hardwareFlag->empty() ? true : false);
178
179 vpd::VpdTool l_vpdToolObj;
180 return l_vpdToolObj.readKeyword(i_vpdPath, i_recordName, i_keywordName,
181 l_isHardwareOperation, i_filePath);
182}
183
184/**
185 * @brief API to check option value pair in the tool command.
186 *
187 * In VPD tool command, some of the option(s) mandate values to be passed along
188 * with the option. This API based on option, detects those mandatory value(s).
189 *
190 * @param[in] i_objectOption - Option to pass object path.
191 * @param[in] i_vpdPath - Object path, DBus or EEPROM.
192 * @param[in] i_recordOption - Option to pass record name.
193 * @param[in] i_recordName - Record name.
194 * @param[in] i_keywordOption - Option to pass keyword name.
195 * @param[in] i_keywordName - Keyword name.
Anupama B R951d6602025-01-18 09:52:33 -0600196 * @param[in] i_fileOption - Option to pass file path.
197 * @param[in] i_filePath - File path.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500198 *
199 * @return Success if corresponding value is found against option, failure
200 * otherwise.
201 */
202int checkOptionValuePair(const auto& i_objectOption, const auto& i_vpdPath,
203 const auto& i_recordOption, const auto& i_recordName,
Anupama B R951d6602025-01-18 09:52:33 -0600204 const auto& i_keywordOption, const auto& i_keywordName,
205 const auto& i_fileOption, const auto& i_filePath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500206{
207 if (!i_objectOption->empty() && i_vpdPath.empty())
208 {
209 std::cout << "Given path is empty." << std::endl;
210 return vpd::constants::FAILURE;
211 }
212
213 if (!i_recordOption->empty() &&
214 (i_recordName.size() != vpd::constants::RECORD_SIZE))
215 {
216 std::cerr << "Record " << i_recordName << " is not supported."
217 << std::endl;
218 return vpd::constants::FAILURE;
219 }
220
221 if (!i_keywordOption->empty() &&
222 (i_keywordName.size() != vpd::constants::KEYWORD_SIZE))
223 {
224 std::cerr << "Keyword " << i_keywordName << " is not supported."
225 << std::endl;
226 return vpd::constants::FAILURE;
227 }
228
Anupama B R951d6602025-01-18 09:52:33 -0600229 if (!i_fileOption->empty() && i_filePath.empty())
230 {
231 std::cout << "File path is empty." << std::endl;
232 return vpd::constants::FAILURE;
233 }
234
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500235 return vpd::constants::SUCCESS;
236}
237
238/**
239 * @brief API to create app footer.
240 *
241 * @param[in] i_app - CLI::App object.
242 */
243void updateFooter(CLI::App& i_app)
244{
245 i_app.footer(
246 "Read:\n"
247 " IPZ Format:\n"
248 " From DBus to console: "
249 "vpd-tool -r -O <DBus Object Path> -R <Record Name> -K <Keyword Name>\n"
250 " From DBus to file: "
251 "vpd-tool -r -O <DBus Object Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
252 " From hardware to console: "
253 "vpd-tool -r -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name>\n"
254 " From hardware to file: "
255 "vpd-tool -r -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
256 "Write:\n"
257 " IPZ Format:\n"
258 " On DBus: "
259 "vpd-tool -w/-u -O <DBus Object Path> -R <Record Name> -K <Keyword Name> -V <Keyword Value>\n"
260 " On DBus, take keyword value from file:\n"
261 " vpd-tool -w/-u -O <DBus Object Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
262 " On hardware: "
263 "vpd-tool -w/-u -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name> -V <Keyword Value>\n"
264 " On hardware, take keyword value from file:\n"
265 " vpd-tool -w/-u -H -O <EEPROM Path> -R <Record Name> -K <Keyword Name> --file <File Path>\n"
266 "Dump Object:\n"
267 " From DBus to console: "
268 "vpd-tool -o -O <DBus Object Path>\n"
269 "Fix System VPD:\n"
270 " vpd-tool --fixSystemVPD\n"
271 "MfgClean:\n"
272 " Flag to clean and reset specific keywords on system VPD to its default value.\n"
273 " vpd-tool --mfgClean\n"
Souvik Roy63089422025-01-23 02:48:21 -0600274 " To sync BIOS attribute related keywords with BIOS Config Manager:\n"
275 " vpd-tool --mfgClean --syncBiosAttributes\n"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500276 "Dump Inventory:\n"
277 " From DBus to console in JSON format: "
278 "vpd-tool -i\n"
279 " From DBus to console in Table format: "
Anupama B R6be2c012025-01-23 02:59:27 -0600280 "vpd-tool -i -t\n"
281 "Force Reset:\n"
282 " vpd-tool --forceReset\n");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500283}
284
285int main(int argc, char** argv)
286{
287 CLI::App l_app{"VPD Command Line Tool"};
288
289 std::string l_vpdPath{};
290 std::string l_recordName{};
291 std::string l_keywordName{};
292 std::string l_filePath{};
293 std::string l_keywordValue{};
294
295 updateFooter(l_app);
296
297 auto l_objectOption =
298 l_app.add_option("--object, -O", l_vpdPath, "File path");
299 auto l_recordOption =
300 l_app.add_option("--record, -R", l_recordName, "Record name");
301 auto l_keywordOption =
302 l_app.add_option("--keyword, -K", l_keywordName, "Keyword name");
303
Anupama B R42914f42025-04-04 01:29:54 -0500304 auto l_fileOption = l_app.add_option(
305 "--file", l_filePath,
306 "Absolute file path,\nNote: For write operation, file should contain keyword’s value in either ascii or in hex format.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500307
308 auto l_keywordValueOption =
309 l_app.add_option("--value, -V", l_keywordValue,
310 "Keyword value in ascii/hex format."
311 " ascii ex: 01234; hex ex: 0x30313233");
312
313 auto l_hardwareFlag =
314 l_app.add_flag("--Hardware, -H", "CAUTION: Developer only option.");
315
316 auto l_readFlag = l_app.add_flag("--readKeyword, -r", "Read keyword")
317 ->needs(l_objectOption)
318 ->needs(l_recordOption)
319 ->needs(l_keywordOption);
320
321 auto l_writeFlag =
322 l_app
323 .add_flag(
324 "--writeKeyword, -w,--updateKeyword, -u",
Anupama B R42914f42025-04-04 01:29:54 -0500325 "Write keyword,\nNote: In case DBus path is provided, both EEPROM and DBus are updated with the given keyword's value.\nIn case EEPROM path is provided, only the given EEPROM is updated with the given keyword's value.")
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500326 ->needs(l_objectOption)
327 ->needs(l_recordOption)
328 ->needs(l_keywordOption);
329
330 // ToDo: Take offset value from user for hardware path.
331
332 auto l_dumpObjFlag =
333 l_app
334 .add_flag("--dumpObject, -o",
335 "Dump specific properties of an inventory object")
336 ->needs(l_objectOption);
337
338 auto l_fixSystemVpdFlag = l_app.add_flag(
339 "--fixSystemVPD",
340 "Use this option to interactively fix critical system VPD keywords");
341 auto l_dumpInventoryFlag =
342 l_app.add_flag("--dumpInventory, -i", "Dump all the inventory objects");
343
344 auto l_mfgCleanFlag = l_app.add_flag(
345 "--mfgClean", "Manufacturing clean on system VPD keyword");
346
347 auto l_mfgCleanConfirmFlag = l_app.add_flag(
348 "--yes", "Using this flag with --mfgClean option, assumes "
349 "yes to proceed without confirmation.");
350
351 auto l_dumpInventoryTableFlag =
352 l_app.add_flag("--table, -t", "Dump inventory in table format");
353
Souvik Roy63089422025-01-23 02:48:21 -0600354 auto l_mfgCleanSyncBiosAttributesFlag = l_app.add_flag(
355 "--syncBiosAttributes, -s",
356 "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");
357
Anupama B R6be2c012025-01-23 02:59:27 -0600358 auto l_forceResetFlag = l_app.add_flag(
359 "--forceReset, -f, -F",
360 "Force collect for hardware. CAUTION: Developer only option.");
361
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500362 CLI11_PARSE(l_app, argc, argv);
363
364 if (checkOptionValuePair(l_objectOption, l_vpdPath, l_recordOption,
Anupama B R951d6602025-01-18 09:52:33 -0600365 l_recordName, l_keywordOption, l_keywordName,
366 l_fileOption, l_filePath) ==
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500367 vpd::constants::FAILURE)
368 {
369 return vpd::constants::FAILURE;
370 }
371
372 if (!l_readFlag->empty())
373 {
374 return readKeyword(l_hardwareFlag, l_vpdPath, l_recordName,
375 l_keywordName, l_filePath);
376 }
377
378 if (!l_writeFlag->empty())
379 {
Anupama B R951d6602025-01-18 09:52:33 -0600380 if ((l_keywordValueOption->empty() && l_fileOption->empty()) ||
381 (!l_keywordValueOption->empty() && !l_fileOption->empty()))
382 {
383 std::cerr
384 << "Please provide keyword value.\nUse --value/--file to give "
385 "keyword value. Refer --help."
386 << std::endl;
387 return vpd::constants::FAILURE;
388 }
389
390 if (!l_fileOption->empty())
391 {
392 l_keywordValue = vpd::utils::readValueFromFile(l_filePath);
393 if (l_keywordValue.empty())
394 {
395 return vpd::constants::FAILURE;
396 }
397
398 return writeKeyword(l_hardwareFlag, l_fileOption, l_vpdPath,
399 l_recordName, l_keywordName, l_keywordValue);
400 }
401
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500402 return writeKeyword(l_hardwareFlag, l_keywordValueOption, l_vpdPath,
403 l_recordName, l_keywordName, l_keywordValue);
404 }
405
406 if (!l_dumpObjFlag->empty())
407 {
408 vpd::VpdTool l_vpdToolObj;
409 return l_vpdToolObj.dumpObject(l_vpdPath);
410 }
411
412 if (!l_fixSystemVpdFlag->empty())
413 {
414 vpd::VpdTool l_vpdToolObj;
415 return l_vpdToolObj.fixSystemVpd();
416 }
417
418 if (!l_mfgCleanFlag->empty())
419 {
Souvik Roy63089422025-01-23 02:48:21 -0600420 return doMfgClean(l_mfgCleanConfirmFlag,
421 l_mfgCleanSyncBiosAttributesFlag);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500422 }
423
424 if (!l_dumpInventoryFlag->empty())
425 {
426 vpd::VpdTool l_vpdToolObj;
427 return l_vpdToolObj.dumpInventory(!l_dumpInventoryTableFlag->empty());
428 }
429
Anupama B R6be2c012025-01-23 02:59:27 -0600430 if (!l_forceResetFlag->empty())
431 {
432 return forceReset();
433 }
434
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500435 std::cout << l_app.help() << std::endl;
436 return vpd::constants::FAILURE;
437}