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 66 // delete the vpd dump directory 67 l_vpdToolObj.clearVpdDumpDir(); 68 69 return l_vpdToolObj.cleanSystemVpd(!i_syncBiosAttributesFlag->empty()); 70 } 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 */ 84 int 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 { 93 std::cerr << "Given EEPROM file path doesn't exist[" + i_vpdPath << "]." 94 << std::endl; 95 if (l_ec) 96 { 97 std::cerr << "Reason: " + l_ec.message() << std::endl; 98 } 99 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 120 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 140 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 * 154 * @return On success return 0, otherwise return -1. 155 */ 156 int 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. 196 * @param[in] i_fileOption - Option to pass file path. 197 * @param[in] i_filePath - File path. 198 * 199 * @return Success if corresponding value is found against option, failure 200 * otherwise. 201 */ 202 int checkOptionValuePair(const auto& i_objectOption, const auto& i_vpdPath, 203 const auto& i_recordOption, const auto& i_recordName, 204 const auto& i_keywordOption, const auto& i_keywordName, 205 const auto& i_fileOption, const auto& i_filePath) 206 { 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 229 if (!i_fileOption->empty() && i_filePath.empty()) 230 { 231 std::cout << "File path is empty." << std::endl; 232 return vpd::constants::FAILURE; 233 } 234 235 return vpd::constants::SUCCESS; 236 } 237 238 /** 239 * @brief API to create app footer. 240 * 241 * @param[in] i_app - CLI::App object. 242 */ 243 void 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" 274 " To sync BIOS attribute related keywords with BIOS Config Manager:\n" 275 " vpd-tool --mfgClean --syncBiosAttributes\n" 276 "Dump Inventory:\n" 277 " From DBus to console in JSON format: " 278 "vpd-tool -i\n" 279 " From DBus to console in Table format: " 280 "vpd-tool -i -t\n" 281 "Force Reset:\n" 282 " vpd-tool --forceReset\n"); 283 } 284 285 int 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 304 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."); 307 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", 325 "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.") 326 ->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 354 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 358 auto l_forceResetFlag = l_app.add_flag( 359 "--forceReset, -f, -F", 360 "Force collect for hardware. CAUTION: Developer only option."); 361 362 CLI11_PARSE(l_app, argc, argv); 363 364 if (checkOptionValuePair(l_objectOption, l_vpdPath, l_recordOption, 365 l_recordName, l_keywordOption, l_keywordName, 366 l_fileOption, l_filePath) == 367 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 { 380 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 402 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 { 420 return doMfgClean(l_mfgCleanConfirmFlag, 421 l_mfgCleanSyncBiosAttributesFlag); 422 } 423 424 if (!l_dumpInventoryFlag->empty()) 425 { 426 vpd::VpdTool l_vpdToolObj; 427 return l_vpdToolObj.dumpInventory(!l_dumpInventoryTableFlag->empty()); 428 } 429 430 if (!l_forceResetFlag->empty()) 431 { 432 return forceReset(); 433 } 434 435 std::cout << l_app.help() << std::endl; 436 return vpd::constants::FAILURE; 437 } 438