1 #include "config.h" 2 3 #include "defines.hpp" 4 #include "ipz_parser.hpp" 5 #include "keyword_vpd_parser.hpp" 6 #include "memory_vpd_parser.hpp" 7 #include "parser_factory.hpp" 8 #include "utils.hpp" 9 #include "vpd_exceptions.hpp" 10 11 #include <ctype.h> 12 13 #include <CLI/CLI.hpp> 14 #include <algorithm> 15 #include <cstdarg> 16 #include <exception> 17 #include <filesystem> 18 #include <fstream> 19 #include <gpiod.hpp> 20 #include <iostream> 21 #include <iterator> 22 #include <nlohmann/json.hpp> 23 #include <phosphor-logging/log.hpp> 24 25 using namespace std; 26 using namespace openpower::vpd; 27 using namespace CLI; 28 using namespace vpd::keyword::parser; 29 using namespace openpower::vpd::constants; 30 namespace fs = filesystem; 31 using json = nlohmann::json; 32 using namespace openpower::vpd::parser::factory; 33 using namespace openpower::vpd::inventory; 34 using namespace openpower::vpd::memory::parser; 35 using namespace openpower::vpd::parser::interface; 36 using namespace openpower::vpd::exceptions; 37 using namespace phosphor::logging; 38 39 static const deviceTreeMap deviceTreeSystemTypeMap = { 40 {RAINIER_2U, "conf@aspeed-bmc-ibm-rainier.dtb"}, 41 {RAINIER_4U, "conf@aspeed-bmc-ibm-rainier-4u.dtb"}, 42 {EVEREST, "conf@aspeed-bmc-ibm-everest.dtb"}}; 43 44 /** 45 * @brief Returns the power state for chassis0 46 */ 47 static auto getPowerState() 48 { 49 // TODO: How do we handle multiple chassis? 50 string powerState{}; 51 auto bus = sdbusplus::bus::new_default(); 52 auto properties = 53 bus.new_method_call("xyz.openbmc_project.State.Chassis", 54 "/xyz/openbmc_project/state/chassis0", 55 "org.freedesktop.DBus.Properties", "Get"); 56 properties.append("xyz.openbmc_project.State.Chassis"); 57 properties.append("CurrentPowerState"); 58 auto result = bus.call(properties); 59 if (!result.is_method_error()) 60 { 61 variant<string> val; 62 result.read(val); 63 if (auto pVal = get_if<string>(&val)) 64 { 65 powerState = *pVal; 66 } 67 } 68 cout << "Power state is: " << powerState << endl; 69 return powerState; 70 } 71 72 /** 73 * @brief Expands location codes 74 */ 75 static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap, 76 bool isSystemVpd) 77 { 78 auto expanded{unexpanded}; 79 static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard"; 80 static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN"; 81 static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS"; 82 size_t idx = expanded.find("fcs"); 83 try 84 { 85 if (idx != string::npos) 86 { 87 string fc{}; 88 string se{}; 89 if (isSystemVpd) 90 { 91 const auto& fcData = vpdMap.at("VCEN").at("FC"); 92 const auto& seData = vpdMap.at("VCEN").at("SE"); 93 fc = string(fcData.data(), fcData.size()); 94 se = string(seData.data(), seData.size()); 95 } 96 else 97 { 98 fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC"); 99 se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE"); 100 } 101 102 // TODO: See if ND1 can be placed in the JSON 103 expanded.replace(idx, 3, fc.substr(0, 4) + ".ND1." + se); 104 } 105 else 106 { 107 idx = expanded.find("mts"); 108 if (idx != string::npos) 109 { 110 string mt{}; 111 string se{}; 112 if (isSystemVpd) 113 { 114 const auto& mtData = vpdMap.at("VSYS").at("TM"); 115 const auto& seData = vpdMap.at("VSYS").at("SE"); 116 mt = string(mtData.data(), mtData.size()); 117 se = string(seData.data(), seData.size()); 118 } 119 else 120 { 121 mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM"); 122 se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE"); 123 } 124 125 replace(mt.begin(), mt.end(), '-', '.'); 126 expanded.replace(idx, 3, mt + "." + se); 127 } 128 } 129 } 130 catch (exception& e) 131 { 132 cerr << "Failed to expand location code with exception: " << e.what() 133 << "\n"; 134 } 135 return expanded; 136 } 137 138 /** 139 * @brief Populate FRU specific interfaces. 140 * 141 * This is a common method which handles both 142 * ipz and keyword specific interfaces thus, 143 * reducing the code redundancy. 144 * @param[in] map - Reference to the innermost keyword-value map. 145 * @param[in] preIntrStr - Reference to the interface string. 146 * @param[out] interfaces - Reference to interface map. 147 */ 148 template <typename T> 149 static void populateFruSpecificInterfaces(const T& map, 150 const string& preIntrStr, 151 inventory::InterfaceMap& interfaces) 152 { 153 inventory::PropertyMap prop; 154 155 for (const auto& kwVal : map) 156 { 157 vector<uint8_t> vec(kwVal.second.begin(), kwVal.second.end()); 158 159 auto kw = kwVal.first; 160 161 if (kw[0] == '#') 162 { 163 kw = string("PD_") + kw[1]; 164 } 165 else if (isdigit(kw[0])) 166 { 167 kw = string("N_") + kw; 168 } 169 prop.emplace(move(kw), move(vec)); 170 } 171 172 interfaces.emplace(preIntrStr, move(prop)); 173 } 174 175 /** 176 * @brief Populate Interfaces. 177 * 178 * This method populates common and extra interfaces to dbus. 179 * @param[in] js - json object 180 * @param[out] interfaces - Reference to interface map 181 * @param[in] vpdMap - Reference to the parsed vpd map. 182 * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD. 183 */ 184 template <typename T> 185 static void populateInterfaces(const nlohmann::json& js, 186 inventory::InterfaceMap& interfaces, 187 const T& vpdMap, bool isSystemVpd) 188 { 189 for (const auto& ifs : js.items()) 190 { 191 string inf = ifs.key(); 192 inventory::PropertyMap props; 193 194 for (const auto& itr : ifs.value().items()) 195 { 196 const string& busProp = itr.key(); 197 198 if (itr.value().is_boolean()) 199 { 200 props.emplace(busProp, itr.value().get<bool>()); 201 } 202 else if (itr.value().is_string()) 203 { 204 if constexpr (is_same<T, Parsed>::value) 205 { 206 if (busProp == "LocationCode" && 207 inf == "com.ibm.ipzvpd.Location") 208 { 209 auto prop = expandLocationCode( 210 itr.value().get<string>(), vpdMap, isSystemVpd); 211 props.emplace(busProp, prop); 212 } 213 else 214 { 215 props.emplace(busProp, itr.value().get<string>()); 216 } 217 } 218 else 219 { 220 props.emplace(busProp, itr.value().get<string>()); 221 } 222 } 223 else if (itr.value().is_object()) 224 { 225 const string& rec = itr.value().value("recordName", ""); 226 const string& kw = itr.value().value("keywordName", ""); 227 const string& encoding = itr.value().value("encoding", ""); 228 229 if constexpr (is_same<T, Parsed>::value) 230 { 231 if (!rec.empty() && !kw.empty() && vpdMap.count(rec) && 232 vpdMap.at(rec).count(kw)) 233 { 234 auto encoded = 235 encodeKeyword(vpdMap.at(rec).at(kw), encoding); 236 props.emplace(busProp, encoded); 237 } 238 } 239 else if constexpr (is_same<T, KeywordVpdMap>::value) 240 { 241 if (!kw.empty() && vpdMap.count(kw)) 242 { 243 auto prop = 244 string(vpdMap.at(kw).begin(), vpdMap.at(kw).end()); 245 auto encoded = encodeKeyword(prop, encoding); 246 props.emplace(busProp, encoded); 247 } 248 } 249 } 250 } 251 interfaces.emplace(inf, move(props)); 252 } 253 } 254 255 static Binary getVpdDataInVector(const nlohmann::json& js, const string& file) 256 { 257 uint32_t offset = 0; 258 // check if offset present? 259 for (const auto& item : js["frus"][file]) 260 { 261 if (item.find("offset") != item.end()) 262 { 263 offset = item["offset"]; 264 } 265 } 266 267 // TODO: Figure out a better way to get max possible VPD size. 268 Binary vpdVector; 269 vpdVector.resize(65504); 270 ifstream vpdFile; 271 vpdFile.open(file, ios::binary); 272 273 vpdFile.seekg(offset, ios_base::cur); 274 vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), 65504); 275 vpdVector.resize(vpdFile.gcount()); 276 277 return vpdVector; 278 } 279 280 /* It does nothing. Just an empty function to return null 281 * at the end of variadic template args 282 */ 283 static string getCommand() 284 { 285 return ""; 286 } 287 288 /* This function to arrange all arguments to make command 289 */ 290 template <typename T, typename... Types> 291 static string getCommand(T arg1, Types... args) 292 { 293 string cmd = " " + arg1 + getCommand(args...); 294 295 return cmd; 296 } 297 298 /* This API takes arguments and run that command 299 * returns output of that command 300 */ 301 template <typename T, typename... Types> 302 static vector<string> executeCmd(T&& path, Types... args) 303 { 304 vector<string> stdOutput; 305 array<char, 128> buffer; 306 307 string cmd = path + getCommand(args...); 308 309 unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose); 310 if (!pipe) 311 { 312 throw runtime_error("popen() failed!"); 313 } 314 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) 315 { 316 stdOutput.emplace_back(buffer.data()); 317 } 318 319 return stdOutput; 320 } 321 322 /** This API will be called at the end of VPD collection to perform any post 323 * actions. 324 * 325 * @param[in] json - json object 326 * @param[in] file - eeprom file path 327 */ 328 static void postFailAction(const nlohmann::json& json, const string& file) 329 { 330 if ((json["frus"][file].at(0)).find("postActionFail") == 331 json["frus"][file].at(0).end()) 332 { 333 return; 334 } 335 336 uint8_t pinValue = 0; 337 string pinName; 338 339 for (const auto& postAction : 340 (json["frus"][file].at(0))["postActionFail"].items()) 341 { 342 if (postAction.key() == "pin") 343 { 344 pinName = postAction.value(); 345 } 346 else if (postAction.key() == "value") 347 { 348 // Get the value to set 349 pinValue = postAction.value(); 350 } 351 } 352 353 cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl; 354 355 try 356 { 357 gpiod::line outputLine = gpiod::find_line(pinName); 358 359 if (!outputLine) 360 { 361 cout << "Couldn't find output line:" << pinName 362 << " on GPIO. Skipping...\n"; 363 364 return; 365 } 366 outputLine.request( 367 {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 368 pinValue); 369 } 370 catch (system_error&) 371 { 372 cerr << "Failed to set post-action GPIO" << endl; 373 } 374 } 375 376 /** Performs any pre-action needed to get the FRU setup for collection. 377 * 378 * @param[in] json - json object 379 * @param[in] file - eeprom file path 380 */ 381 static void preAction(const nlohmann::json& json, const string& file) 382 { 383 if ((json["frus"][file].at(0)).find("preAction") == 384 json["frus"][file].at(0).end()) 385 { 386 return; 387 } 388 389 uint8_t pinValue = 0; 390 string pinName; 391 392 for (const auto& postAction : 393 (json["frus"][file].at(0))["preAction"].items()) 394 { 395 if (postAction.key() == "pin") 396 { 397 pinName = postAction.value(); 398 } 399 else if (postAction.key() == "value") 400 { 401 // Get the value to set 402 pinValue = postAction.value(); 403 } 404 } 405 406 cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl; 407 try 408 { 409 gpiod::line outputLine = gpiod::find_line(pinName); 410 411 if (!outputLine) 412 { 413 cout << "Couldn't find output line:" << pinName 414 << " on GPIO. Skipping...\n"; 415 416 return; 417 } 418 outputLine.request( 419 {"FRU pre-action", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 420 pinValue); 421 } 422 catch (system_error&) 423 { 424 cerr << "Failed to set pre-action GPIO" << endl; 425 return; 426 } 427 428 // Now bind the device 429 string bind = json["frus"][file].at(0).value("bind", ""); 430 cout << "Binding device " << bind << endl; 431 string bindCmd = string("echo \"") + bind + 432 string("\" > /sys/bus/i2c/drivers/at24/bind"); 433 cout << bindCmd << endl; 434 executeCmd(bindCmd); 435 436 // Check if device showed up (test for file) 437 if (!fs::exists(file)) 438 { 439 cout << "EEPROM " << file << " does not exist. Take failure action" 440 << endl; 441 // If not, then take failure postAction 442 postFailAction(json, file); 443 } 444 } 445 446 /** 447 * @brief Prime the Inventory 448 * Prime the inventory by populating only the location code, 449 * type interface and the inventory object for the frus 450 * which are not system vpd fru. 451 * 452 * @param[in] jsObject - Reference to vpd inventory json object 453 * @param[in] vpdMap - Reference to the parsed vpd map 454 * 455 * @returns Map of items in extraInterface. 456 */ 457 template <typename T> 458 inventory::ObjectMap primeInventory(const nlohmann::json& jsObject, 459 const T& vpdMap) 460 { 461 inventory::ObjectMap objects; 462 463 for (auto& itemFRUS : jsObject["frus"].items()) 464 { 465 // Take pre actions 466 preAction(jsObject, itemFRUS.key()); 467 for (auto& itemEEPROM : itemFRUS.value()) 468 { 469 inventory::InterfaceMap interfaces; 470 auto isSystemVpd = itemEEPROM.value("isSystemVpd", false); 471 inventory::Object object(itemEEPROM.at("inventoryPath")); 472 473 if (!isSystemVpd && !itemEEPROM.value("noprime", false)) 474 { 475 if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end()) 476 { 477 for (const auto& eI : itemEEPROM["extraInterfaces"].items()) 478 { 479 inventory::PropertyMap props; 480 if (eI.key() == 481 openpower::vpd::constants::LOCATION_CODE_INF) 482 { 483 if constexpr (std::is_same<T, Parsed>::value) 484 { 485 for (auto& lC : eI.value().items()) 486 { 487 auto propVal = expandLocationCode( 488 lC.value().get<string>(), vpdMap, true); 489 490 props.emplace(move(lC.key()), 491 move(propVal)); 492 interfaces.emplace(move(eI.key()), 493 move(props)); 494 } 495 } 496 } 497 else if (eI.key().find("Inventory.Item.") != 498 string::npos) 499 { 500 interfaces.emplace(move(eI.key()), move(props)); 501 } 502 } 503 } 504 objects.emplace(move(object), move(interfaces)); 505 } 506 } 507 } 508 return objects; 509 } 510 511 /** 512 * @brief This API executes command to set environment variable 513 * And then reboot the system 514 * @param[in] key -env key to set new value 515 * @param[in] value -value to set. 516 */ 517 void setEnvAndReboot(const string& key, const string& value) 518 { 519 // set env and reboot and break. 520 executeCmd("/sbin/fw_setenv", key, value); 521 log<level::INFO>("Rebooting BMC to pick up new device tree"); 522 // make dbus call to reboot 523 auto bus = sdbusplus::bus::new_default_system(); 524 auto method = bus.new_method_call( 525 "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 526 "org.freedesktop.systemd1.Manager", "Reboot"); 527 bus.call_noreply(method); 528 } 529 530 /* 531 * @brief This API checks for env var fitconfig. 532 * If not initialised OR updated as per the current system type, 533 * update this env var and reboot the system. 534 * 535 * @param[in] systemType IM kwd in vpd tells about which system type it is. 536 * */ 537 void setDevTreeEnv(const string& systemType) 538 { 539 string newDeviceTree; 540 541 if (deviceTreeSystemTypeMap.find(systemType) != 542 deviceTreeSystemTypeMap.end()) 543 { 544 newDeviceTree = deviceTreeSystemTypeMap.at(systemType); 545 } 546 547 string readVarValue; 548 bool envVarFound = false; 549 550 vector<string> output = executeCmd("/sbin/fw_printenv"); 551 for (const auto& entry : output) 552 { 553 size_t pos = entry.find("="); 554 string key = entry.substr(0, pos); 555 if (key != "fitconfig") 556 { 557 continue; 558 } 559 560 envVarFound = true; 561 if (pos + 1 < entry.size()) 562 { 563 readVarValue = entry.substr(pos + 1); 564 if (readVarValue.find(newDeviceTree) != string::npos) 565 { 566 // fitconfig is Updated. No action needed 567 break; 568 } 569 } 570 // set env and reboot and break. 571 setEnvAndReboot(key, newDeviceTree); 572 exit(0); 573 } 574 575 // check If env var Not found 576 if (!envVarFound) 577 { 578 setEnvAndReboot("fitconfig", newDeviceTree); 579 } 580 } 581 582 /** 583 * @brief Populate Dbus. 584 * This method invokes all the populateInterface functions 585 * and notifies PIM about dbus object. 586 * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the 587 * input. 588 * @param[in] js - Inventory json object 589 * @param[in] filePath - Path of the vpd file 590 * @param[in] preIntrStr - Interface string 591 */ 592 template <typename T> 593 static void populateDbus(const T& vpdMap, nlohmann::json& js, 594 const string& filePath) 595 { 596 inventory::InterfaceMap interfaces; 597 inventory::ObjectMap objects; 598 inventory::PropertyMap prop; 599 600 bool isSystemVpd = false; 601 for (const auto& item : js["frus"][filePath]) 602 { 603 const auto& objectPath = item["inventoryPath"]; 604 sdbusplus::message::object_path object(objectPath); 605 isSystemVpd = item.value("isSystemVpd", false); 606 // Populate the VPD keywords and the common interfaces only if we 607 // are asked to inherit that data from the VPD, else only add the 608 // extraInterfaces. 609 if (item.value("inherit", true)) 610 { 611 if constexpr (is_same<T, Parsed>::value) 612 { 613 // Each record in the VPD becomes an interface and all 614 // keyword within the record are properties under that 615 // interface. 616 for (const auto& record : vpdMap) 617 { 618 populateFruSpecificInterfaces( 619 record.second, ipzVpdInf + record.first, interfaces); 620 } 621 } 622 else if constexpr (is_same<T, KeywordVpdMap>::value) 623 { 624 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces); 625 } 626 if (js.find("commonInterfaces") != js.end()) 627 { 628 populateInterfaces(js["commonInterfaces"], interfaces, vpdMap, 629 isSystemVpd); 630 } 631 } 632 else 633 { 634 // Check if we have been asked to inherit specific record(s) 635 if constexpr (is_same<T, Parsed>::value) 636 { 637 if (item.find("copyRecords") != item.end()) 638 { 639 for (const auto& record : item["copyRecords"]) 640 { 641 const string& recordName = record; 642 if (vpdMap.find(recordName) != vpdMap.end()) 643 { 644 populateFruSpecificInterfaces( 645 vpdMap.at(recordName), ipzVpdInf + recordName, 646 interfaces); 647 } 648 } 649 } 650 } 651 } 652 653 if (item.value("inheritEI", true)) 654 { 655 // Populate interfaces and properties that are common to every FRU 656 // and additional interface that might be defined on a per-FRU 657 // basis. 658 if (item.find("extraInterfaces") != item.end()) 659 { 660 populateInterfaces(item["extraInterfaces"], interfaces, vpdMap, 661 isSystemVpd); 662 } 663 } 664 objects.emplace(move(object), move(interfaces)); 665 } 666 667 if (isSystemVpd) 668 { 669 vector<uint8_t> imVal; 670 if constexpr (is_same<T, Parsed>::value) 671 { 672 auto property = vpdMap.find("VSBP"); 673 if (property != vpdMap.end()) 674 { 675 auto value = (property->second).find("IM"); 676 if (value != (property->second).end()) 677 { 678 copy(value->second.begin(), value->second.end(), 679 back_inserter(imVal)); 680 } 681 } 682 } 683 684 fs::path target; 685 fs::path link = INVENTORY_JSON_SYM_LINK; 686 687 ostringstream oss; 688 for (auto& i : imVal) 689 { 690 oss << setw(2) << setfill('0') << hex << static_cast<int>(i); 691 } 692 string imValStr = oss.str(); 693 694 if (imValStr == RAINIER_4U) // 4U 695 { 696 target = INVENTORY_JSON_4U; 697 } 698 else if (imValStr == RAINIER_2U) // 2U 699 { 700 target = INVENTORY_JSON_2U; 701 } 702 else if (imValStr == EVEREST) 703 { 704 target = INVENTORY_JSON_EVEREST; 705 } 706 707 // Create the directory for hosting the symlink 708 fs::create_directories(VPD_FILES_PATH); 709 // unlink the symlink previously created (if any) 710 remove(INVENTORY_JSON_SYM_LINK); 711 // create a new symlink based on the system 712 fs::create_symlink(target, link); 713 714 // Reloading the json 715 ifstream inventoryJson(link); 716 auto js = json::parse(inventoryJson); 717 inventoryJson.close(); 718 719 inventory::ObjectMap primeObject = primeInventory(js, vpdMap); 720 objects.insert(primeObject.begin(), primeObject.end()); 721 722 // set the U-boot environment variable for device-tree 723 setDevTreeEnv(imValStr); 724 } 725 726 // Notify PIM 727 inventory::callPIM(move(objects)); 728 } 729 730 int main(int argc, char** argv) 731 { 732 int rc = 0; 733 string file{}; 734 json js{}; 735 736 // map to hold additional data in case of logging pel 737 PelAdditionalData additionalData{}; 738 739 // this is needed to hold base fru inventory path in case there is ECC or 740 // vpd exception while parsing the file 741 std::string baseFruInventoryPath = {}; 742 743 try 744 { 745 App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store " 746 "in DBUS"}; 747 string file{}; 748 749 app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)") 750 ->required(); 751 752 CLI11_PARSE(app, argc, argv); 753 754 auto jsonToParse = INVENTORY_JSON_DEFAULT; 755 756 // If the symlink exists, it means it has been setup for us, switch the 757 // path 758 if (fs::exists(INVENTORY_JSON_SYM_LINK)) 759 { 760 jsonToParse = INVENTORY_JSON_SYM_LINK; 761 } 762 763 // Make sure that the file path we get is for a supported EEPROM 764 ifstream inventoryJson(jsonToParse); 765 if (!inventoryJson) 766 { 767 throw( 768 (VpdJsonException("Failed to access Json path", jsonToParse))); 769 } 770 771 try 772 { 773 js = json::parse(inventoryJson); 774 } 775 catch (json::parse_error& ex) 776 { 777 throw((VpdJsonException("Json parsing failed", jsonToParse))); 778 } 779 780 if ((js.find("frus") == js.end()) || 781 (js["frus"].find(file) == js["frus"].end())) 782 { 783 cout << "Device path not in JSON, ignoring" << endl; 784 return 0; 785 } 786 787 if (!fs::exists(file)) 788 { 789 cout << "Device path: " << file 790 << " does not exist. Spurious udev event? Exiting." << endl; 791 return 0; 792 } 793 794 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"]; 795 // Check if we can read the VPD file based on the power state 796 if (js["frus"][file].at(0).value("powerOffOnly", false)) 797 { 798 if ("xyz.openbmc_project.State.Chassis.PowerState.On" == 799 getPowerState()) 800 { 801 cout << "This VPD cannot be read when power is ON" << endl; 802 return 0; 803 } 804 } 805 806 Binary vpdVector = getVpdDataInVector(js, file); 807 ParserInterface* parser = ParserFactory::getParser(move(vpdVector)); 808 809 variant<KeywordVpdMap, Store> parseResult; 810 parseResult = parser->parse(); 811 812 try 813 { 814 Binary vpdVector = getVpdDataInVector(js, file); 815 ParserInterface* parser = ParserFactory::getParser(move(vpdVector)); 816 817 variant<KeywordVpdMap, Store> parseResult; 818 parseResult = parser->parse(); 819 if (auto pVal = get_if<Store>(&parseResult)) 820 { 821 populateDbus(pVal->getVpdMap(), js, file); 822 } 823 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult)) 824 { 825 populateDbus(*pVal, js, file); 826 } 827 828 // release the parser object 829 ParserFactory::freeParser(parser); 830 } 831 catch (exception& e) 832 { 833 postFailAction(js, file); 834 throw e; 835 } 836 } 837 catch (const VpdJsonException& ex) 838 { 839 additionalData.emplace("JSON_PATH", ex.getJsonPath()); 840 additionalData.emplace("DESCRIPTION", ex.what()); 841 createPEL(additionalData, errIntfForJsonFailure); 842 843 cerr << ex.what() << "\n"; 844 rc = -1; 845 } 846 catch (const VpdEccException& ex) 847 { 848 additionalData.emplace("DESCRIPTION", "ECC check failed"); 849 additionalData.emplace("CALLOUT_INVENTORY_PATH", 850 INVENTORY_PATH + baseFruInventoryPath); 851 createPEL(additionalData, errIntfForEccCheckFail); 852 853 cerr << ex.what() << "\n"; 854 rc = -1; 855 } 856 catch (const VpdDataException& ex) 857 { 858 additionalData.emplace("DESCRIPTION", "Invalid VPD data"); 859 additionalData.emplace("CALLOUT_INVENTORY_PATH", 860 INVENTORY_PATH + baseFruInventoryPath); 861 createPEL(additionalData, errIntfForInvalidVPD); 862 863 cerr << ex.what() << "\n"; 864 rc = -1; 865 } 866 catch (exception& e) 867 { 868 cerr << e.what() << "\n"; 869 rc = -1; 870 } 871 872 return rc; 873 } 874