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