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 */
doMfgClean(const auto & i_mfgCleanConfirmFlag)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 */
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)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 */
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)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 */
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)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 */
updateFooter(CLI::App & i_app)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
main(int argc,char ** argv)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