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