1 #include "vpd_tool_impl.hpp" 2 3 #include <CLI/CLI.hpp> 4 5 #include <filesystem> 6 #include <fstream> 7 #include <iostream> 8 9 using namespace CLI; 10 using namespace std; 11 namespace fs = std::filesystem; 12 using namespace openpower::vpd; 13 using json = nlohmann::json; 14 15 int main(int argc, char** argv) 16 { 17 int rc = 0; 18 App app{"VPD Command line tool to dump the inventory and to read and " 19 "update the keywords"}; 20 21 string objectPath{}; 22 string recordName{}; 23 string keyword{}; 24 string val{}; 25 uint32_t offset = 0; 26 27 auto object = app.add_option("--object, -O", objectPath, 28 "Enter the Object Path"); 29 auto record = app.add_option("--record, -R", recordName, 30 "Enter the Record Name"); 31 auto kw = app.add_option("--keyword, -K", keyword, "Enter the Keyword"); 32 auto valOption = app.add_option( 33 "--value, -V", val, 34 "Enter the value. The value to be updated should be either in ascii or " 35 "in hex. ascii eg: 01234; hex eg: 0x30313233"); 36 app.add_option("--seek, -s", offset, 37 "User can provide VPD offset using this option. Default " 38 "offset value is 0. Using --seek is optional and is valid " 39 "only while using --Hardware/-H option."); 40 41 auto dumpObjFlag = 42 app.add_flag("--dumpObject, -o", 43 "Dump the given object from the inventory. { " 44 "vpd-tool-exe --dumpObject/-o --object/-O object-name }") 45 ->needs(object); 46 47 auto dumpInvFlag = app.add_flag( 48 "--dumpInventory, -i", "Dump all the inventory objects. { vpd-tool-exe " 49 "--dumpInventory/-i }"); 50 51 auto readFlag = 52 app.add_flag("--readKeyword, -r", 53 "Read the data of the given keyword. { " 54 "vpd-tool-exe --readKeyword/-r --object/-O " 55 "\"object-name\" --record/-R \"record-name\" --keyword/-K " 56 "\"keyword-name\" }") 57 ->needs(object) 58 ->needs(record) 59 ->needs(kw); 60 61 auto writeFlag = 62 app.add_flag( 63 "--writeKeyword, -w, --updateKeyword, -u", 64 "Update the value. { vpd-tool-exe " 65 "--writeKeyword/-w/--updateKeyword/-u " 66 "--object/-O object-name --record/-R record-name --keyword/-K " 67 "keyword-name --value/-V (or) --file }. Value can be given " 68 "directly via console using --value or via file using --file") 69 ->needs(object) 70 ->needs(record) 71 ->needs(kw); 72 73 auto fileOption = app.add_option( 74 "--file", val, 75 "Enter the file name with its absolute path. This option can be used " 76 "in read and write operations. When used in read, the read value will " 77 "be saved to this file and when used in write, the value to be written " 78 "will be taken from this file."); 79 80 auto forceResetFlag = 81 app.add_flag("--forceReset, -f, -F", 82 "Force Collect for Hardware. CAUTION: Developer Only " 83 "Option. { vpd-tool-exe --forceReset/-f/-F }"); 84 85 auto Hardware = app.add_flag( 86 "--Hardware, -H", 87 "This is a supplementary flag to read/write directly from/to hardware. " 88 "User should provide valid hardware/eeprom path (and not dbus object " 89 "path) in the -O/--object path. CAUTION: Developer Only Option"); 90 91 auto fixSystemVPDFlag = app.add_flag( 92 "--fixSystemVPD", "Use this option to interactively fix critical " 93 "system VPD keywords {vpd-tool-exe --fixSystemVPD}"); 94 95 auto mfgClean = app.add_flag("--mfgClean", 96 "Flag to clean and reset specific keywords " 97 "on system VPD to its default value."); 98 99 auto confirm = 100 app.add_flag("--yes", "Using this flag with --mfgClean option, assumes " 101 "yes to proceed without confirmation."); 102 103 CLI11_PARSE(app, argc, argv); 104 105 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK); 106 auto jsObject = json::parse(inventoryJson); 107 108 try 109 { 110 if ((*kw) && (keyword.size() != 2)) 111 { 112 throw runtime_error("Keyword " + keyword + " not supported."); 113 } 114 115 if (*Hardware) 116 { 117 if (!fs::exists(objectPath)) // if dbus object path is given or 118 // invalid eeprom path is given 119 { 120 string errorMsg = "Invalid EEPROM path : "; 121 errorMsg += objectPath; 122 errorMsg += 123 ". The given EEPROM path doesn't exist. Provide valid " 124 "EEPROM path when -H flag is used. Refer help option. "; 125 throw runtime_error(errorMsg); 126 } 127 } 128 129 if (*writeFlag) 130 { 131 if ((!*fileOption) && (!*valOption)) 132 { 133 throw runtime_error("Please provide the data that needs to be " 134 "updated. Use --value/--file to " 135 "input data. Refer --help."); 136 } 137 138 if ((*fileOption) && (!fs::exists(val))) 139 { 140 throw runtime_error("Please provide a valid file with absolute " 141 "path in --file."); 142 } 143 } 144 145 if (*dumpObjFlag) 146 { 147 VpdTool vpdToolObj(move(objectPath)); 148 vpdToolObj.dumpObject(jsObject); 149 } 150 151 else if (*dumpInvFlag) 152 { 153 VpdTool vpdToolObj; 154 vpdToolObj.dumpInventory(jsObject); 155 } 156 157 else if (*readFlag && !*Hardware) 158 { 159 VpdTool vpdToolObj(move(objectPath), move(recordName), 160 move(keyword), move(val)); 161 vpdToolObj.readKeyword(); 162 } 163 164 else if (*writeFlag && !*Hardware) 165 { 166 VpdTool vpdToolObj(move(objectPath), move(recordName), 167 move(keyword), move(val)); 168 rc = vpdToolObj.updateKeyword(); 169 } 170 171 else if (*forceResetFlag) 172 { 173 // Force reset the BMC only if the CEC is powered OFF. 174 if (getPowerState() == 175 "xyz.openbmc_project.State.Chassis.PowerState.Off") 176 { 177 VpdTool vpdToolObj; 178 vpdToolObj.forceReset(jsObject); 179 } 180 else 181 { 182 std::cerr << "The chassis power state is not Off. Force reset " 183 "operation is not allowed."; 184 return -1; 185 } 186 } 187 188 else if (*writeFlag && *Hardware) 189 { 190 VpdTool vpdToolObj(move(objectPath), move(recordName), 191 move(keyword), move(val)); 192 rc = vpdToolObj.updateHardware(offset); 193 } 194 else if (*readFlag && *Hardware) 195 { 196 VpdTool vpdToolObj(move(objectPath), move(recordName), 197 move(keyword), move(val)); 198 vpdToolObj.readKwFromHw(offset); 199 } 200 else if (*fixSystemVPDFlag) 201 { 202 std::string backupEepromPath; 203 std::string backupInvPath; 204 findBackupVPDPaths(backupEepromPath, backupInvPath, jsObject); 205 VpdTool vpdToolObj; 206 207 if (backupEepromPath.empty()) 208 { 209 rc = vpdToolObj.fixSystemVPD(); 210 } 211 else 212 { 213 rc = vpdToolObj.fixSystemBackupVPD(backupEepromPath, 214 backupInvPath); 215 } 216 } 217 else if (*mfgClean) 218 { 219 if (!*confirm) 220 { 221 std::string confirmation{}; 222 std::cout << "\nThis option resets some of the system VPD " 223 "keywords to their default values. Do you really " 224 "wish to proceed further?[yes/no]: "; 225 std::cin >> confirmation; 226 227 if (confirmation != "yes") 228 { 229 return 0; 230 } 231 } 232 VpdTool vpdToolObj; 233 rc = vpdToolObj.cleanSystemVPD(); 234 } 235 else 236 { 237 throw runtime_error("One of the valid options is required. Refer " 238 "--help for list of options."); 239 } 240 } 241 242 catch (const exception& e) 243 { 244 cerr << e.what(); 245 rc = -1; 246 } 247 248 return rc; 249 } 250