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
main(int argc,char ** argv)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 =
28 app.add_option("--object, -O", objectPath, "Enter the Object Path");
29 auto record =
30 app.add_option("--record, -R", recordName, "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 =
96 app.add_flag("--mfgClean", "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 (*object && objectPath.empty())
111 {
112 throw runtime_error("Given path is empty.");
113 }
114
115 if (*record && (recordName.size() != 4))
116 {
117 throw runtime_error("Record " + recordName + " not supported.");
118 }
119
120 if ((*kw) && (keyword.size() != 2))
121 {
122 throw runtime_error("Keyword " + keyword + " not supported.");
123 }
124
125 if (*Hardware)
126 {
127 if (!fs::exists(objectPath)) // if dbus object path is given or
128 // invalid eeprom path is given
129 {
130 string errorMsg = "Invalid EEPROM path : ";
131 errorMsg += objectPath;
132 errorMsg +=
133 ". The given EEPROM path doesn't exist. Provide valid "
134 "EEPROM path when -H flag is used. Refer help option. ";
135 throw runtime_error(errorMsg);
136 }
137 }
138
139 if (*writeFlag)
140 {
141 if (isReadOnlyEEPROM(objectPath, jsObject))
142 {
143 throw runtime_error("Read only EEPROM. Update not allowed.");
144 }
145
146 if ((!*fileOption) && (!*valOption))
147 {
148 throw runtime_error("Please provide the data that needs to be "
149 "updated. Use --value/--file to "
150 "input data. Refer --help.");
151 }
152
153 if ((*fileOption) && (!fs::exists(val)))
154 {
155 throw runtime_error("Please provide a valid file with absolute "
156 "path in --file.");
157 }
158 }
159
160 if (*dumpObjFlag)
161 {
162 VpdTool vpdToolObj(move(objectPath));
163 vpdToolObj.dumpObject(jsObject);
164 }
165
166 else if (*dumpInvFlag)
167 {
168 VpdTool vpdToolObj;
169 vpdToolObj.dumpInventory(jsObject);
170 }
171
172 else if (*readFlag && !*Hardware)
173 {
174 VpdTool vpdToolObj(move(objectPath), move(recordName),
175 move(keyword), move(val));
176 vpdToolObj.readKeyword();
177 }
178
179 else if (*writeFlag && !*Hardware)
180 {
181 VpdTool vpdToolObj(move(objectPath), move(recordName),
182 move(keyword), move(val));
183 rc = vpdToolObj.updateKeyword();
184 }
185
186 else if (*forceResetFlag)
187 {
188 // Force reset the BMC only if the CEC is powered OFF.
189 if (getPowerState() ==
190 "xyz.openbmc_project.State.Chassis.PowerState.Off")
191 {
192 VpdTool vpdToolObj;
193 vpdToolObj.forceReset(jsObject);
194 }
195 else
196 {
197 std::cerr << "The chassis power state is not Off. Force reset "
198 "operation is not allowed.";
199 return -1;
200 }
201 }
202
203 else if (*writeFlag && *Hardware)
204 {
205 VpdTool vpdToolObj(move(objectPath), move(recordName),
206 move(keyword), move(val));
207 rc = vpdToolObj.updateHardware(offset);
208 }
209 else if (*readFlag && *Hardware)
210 {
211 VpdTool vpdToolObj(move(objectPath), move(recordName),
212 move(keyword), move(val));
213 vpdToolObj.readKwFromHw(offset);
214 }
215 else if (*fixSystemVPDFlag)
216 {
217 std::string backupEepromPath;
218 std::string backupInvPath;
219 findBackupVPDPaths(backupEepromPath, backupInvPath, jsObject);
220 VpdTool vpdToolObj;
221
222 if (backupEepromPath.empty())
223 {
224 rc = vpdToolObj.fixSystemVPD();
225 }
226 else
227 {
228 rc = vpdToolObj.fixSystemBackupVPD(backupEepromPath,
229 backupInvPath);
230 }
231 }
232 else if (*mfgClean)
233 {
234 if (!*confirm)
235 {
236 std::string confirmation{};
237 std::cout << "\nThis option resets some of the system VPD "
238 "keywords to their default values. Do you really "
239 "wish to proceed further?[yes/no]: ";
240 std::cin >> confirmation;
241
242 if (confirmation != "yes")
243 {
244 return 0;
245 }
246 }
247 VpdTool vpdToolObj;
248 rc = vpdToolObj.cleanSystemVPD();
249 }
250 else
251 {
252 throw runtime_error("One of the valid options is required. Refer "
253 "--help for list of options.");
254 }
255 }
256
257 catch (const exception& e)
258 {
259 cerr << e.what();
260 rc = -1;
261 }
262
263 return rc;
264 }
265