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