| #include "util.hpp" |
| |
| #include "getConfig.hpp" |
| |
| #include <linux/fs.h> |
| |
| #include <phosphor-logging/lg2.hpp> |
| #include <stdplus/fd/create.hpp> |
| #include <stdplus/fd/managed.hpp> |
| #include <stdplus/handle/managed.hpp> |
| #include <xyz/openbmc_project/Common/error.hpp> |
| |
| #include <filesystem> |
| #include <fstream> |
| #include <iostream> |
| #include <string> |
| |
| 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<uint8_t>(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, |
| std::string& locationCode) |
| { |
| /* 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; |
| } |
| |
| /* Check if location code/ silkscreen name is provided for the drive. */ |
| auto findLocationCode = data.find("LocationCode"); |
| if (findLocationCode != data.end()) |
| { |
| const std::string* locationCodePtr = |
| std::get_if<std::string>(&findLocationCode->second); |
| if (locationCodePtr != nullptr) |
| { |
| locationCode = *locationCodePtr; |
| } |
| } |
| |
| /* |
| * Currently, we only support eMMC, so report an error for any other device |
| * types. |
| */ |
| std::string type = std::get<std::string>(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 (const auto& 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 || devType.compare("SD") == 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 |