#include "util.hpp" #include "getConfig.hpp" #include #include #include #include #include #include #include #include #include #include namespace estoraged { namespace util { using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; using ::stdplus::fd::ManagedFd; uint64_t findSizeOfBlockDevice(const std::string& devPath) { ManagedFd fd; uint64_t bytes = 0; try { // open block dev fd = stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly); // get block size fd.ioctl(BLKGETSIZE64, &bytes); } catch (...) { lg2::error("erase unable to open blockdev", "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.DriveEraseFailure"), "REDFISH_MESSAGE_ARGS", std::to_string(fd.get())); throw InternalFailure(); } return bytes; } uint8_t findPredictedMediaLifeLeftPercent(const std::string& sysfsPath) { // The eMMC spec defines two estimates for the life span of the device // in the extended CSD field 269 and 268, named estimate A and estimate B. // Linux exposes the values in the /life_time node. // estimate A is for A type memory // estimate B is for B type memory // // the estimate are encoded as such // 0x01 <=> 0% - 10% device life time used // 0x02 <=> 10% -20% device life time used // ... // 0x0A <=> 90% - 100% device life time used // 0x0B <=> Exceeded its maximum estimated device life time uint16_t estA = 0, estB = 0; std::ifstream lifeTimeFile; try { lifeTimeFile.open(sysfsPath + "/life_time", std::ios_base::in); lifeTimeFile >> std::hex >> estA; lifeTimeFile >> std::hex >> estB; if ((estA == 0) || (estA > 11) || (estB == 0) || (estB > 11)) { throw InternalFailure(); } } catch (...) { lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.DriveEraseFailure")); lifeTimeFile.close(); return 255; } lifeTimeFile.close(); // we are returning lowest LifeLeftPercent uint8_t maxLifeUsed = 0; if (estA > estB) { maxLifeUsed = estA; } else { maxLifeUsed = estB; } return static_cast(11 - maxLifeUsed) * 10; } std::string getPartNumber(const std::filesystem::path& sysfsPath) { std::ifstream partNameFile; std::string partName; try { std::filesystem::path namePath(sysfsPath); namePath /= "name"; partNameFile.open(namePath, std::ios_base::in); partNameFile >> partName; } catch (...) { lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.PartNumberFailure")); } partNameFile.close(); if (partName.empty()) { partName = "unknown"; } return partName; } std::string getSerialNumber(const std::filesystem::path& sysfsPath) { std::ifstream serialNumberFile; std::string serialNumber; try { std::filesystem::path serialPath(sysfsPath); serialPath /= "serial"; serialNumberFile.open(serialPath, std::ios_base::in); serialNumberFile >> serialNumber; } catch (...) { lg2::error("Unable to read sysfs", "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.SerialNumberFailure")); } serialNumberFile.close(); if (serialNumber.empty()) { serialNumber = "unknown"; } return serialNumber; } bool findDevice(const StorageData& data, const std::filesystem::path& searchDir, std::filesystem::path& deviceFile, std::filesystem::path& sysfsDir, std::string& luksName) { /* Check what type of storage device this is. */ estoraged::BasicVariantType typeVariant; try { /* The EntityManager config should have this property set. */ typeVariant = data.at("Type"); } catch (const boost::container::out_of_range& e) { lg2::error("Could not read device type", "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.FindDeviceFail")); return false; } /* * Currently, we only support eMMC, so report an error for any other device * types. */ std::string type = std::get(typeVariant); if (type.compare("EmmcDevice") != 0) { lg2::error("Unsupported device type {TYPE}", "TYPE", type, "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.FindDeviceFail")); return false; } /* Look for the eMMC in the specified searchDir directory. */ for (auto const& dirEntry : std::filesystem::directory_iterator{searchDir}) { /* * We will look at the 'type' file to determine if this is an MMC * device. */ std::filesystem::path curPath(dirEntry.path()); curPath /= "device/type"; if (!std::filesystem::exists(curPath)) { /* The 'type' file doesn't exist. This must not be an eMMC. */ continue; } try { std::ifstream typeFile(curPath, std::ios_base::in); std::string devType; typeFile >> devType; if (devType.compare("MMC") == 0) { /* Found it. Get the sysfs directory and device file. */ std::filesystem::path deviceName(dirEntry.path().filename()); sysfsDir = dirEntry.path(); sysfsDir /= "device"; deviceFile = "/dev"; deviceFile /= deviceName; luksName = "luks-" + deviceName.string(); return true; } } catch (...) { lg2::error("Failed to read device type for {PATH}", "PATH", curPath, "REDFISH_MESSAGE_ID", std::string("OpenBMC.0.1.FindDeviceFail")); /* * We will still continue searching, though. Maybe this wasn't the * device we were looking for, anyway. */ } } /* Device wasn't found. */ return false; } } // namespace util } // namespace estoraged