Add support for LocationCode

LocationCode is needed to populate ServiceLabel by BMCWeb for Redfish
resource associated with eStorage.
LocationCode is derived from config object exported by Entity Manager
in the the following interface:
    "xyz.openbmc_project.Configuration.EmmcDevice

To surface LocationCode, the "Exposes" entry in board's Entity Manager
config can add "LocationCode" property as follows:
{
    "Name": "example_emmc",
    "Type": "EmmcDevice",
    "LocationCode": "U1000"
}

Here the LocationCode is the silk screen label.

Tested:

busctl introspect xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0  \
xyz.openbmc_project.Inventory.Decorator.LocationCode

NAME                TYPE      SIGNATURE RESULT/VALUE FLAGS
.LocationCode    property  s         "U1000"      emits-change

wget -qO- localhost:80/redfish/v1/Chassis/DCSCM/Drives/mmcblk0
{
    "@odata.id": "/redfish/v1/Chassis/DCSCM/Drives/mmcblk0",
    "@odata.type": "#Drive.v1_7_0.Drive",
    "Id": "mmcblk0",
    "Links": {
    "Chassis": {
        "@odata.id": "/redfish/v1/Chassis/DCSCM"
    }
    },
    "Name": "mmcblk0",
    "PhysicalLocation": {
    "PartLocation": {
        "LocationType": "Embedded",
        "ServiceLabel": "U1000"
    },
    "PartLocationContext": "DC_SCM"
    },
    "PredictedMediaLifeLeftPercent": 100,
    "Status": {
    "State": "Enabled"
    }
}

Change-Id: Ibf53ede5ee65787f9cef53d4bad4cb8fccba3606
Signed-off-by: Rahul Kapoor <rahulkpr@google.com>
diff --git a/src/estoraged.cpp b/src/estoraged.cpp
index 3a6a8bb..95f3057 100644
--- a/src/estoraged.cpp
+++ b/src/estoraged.cpp
@@ -37,6 +37,7 @@
                      const std::string& luksName, uint64_t size,
                      uint8_t lifeTime, const std::string& partNumber,
                      const std::string& serialNumber,
+                     const std::string& locationCode,
                      std::unique_ptr<CryptsetupInterface> cryptInterface,
                      std::unique_ptr<FilesystemInterface> fsInterface) :
     devPath(devPath),
@@ -106,6 +107,14 @@
     embeddedLocationInterface = objectServer.add_interface(
         objectPath, "xyz.openbmc_project.Inventory.Connector.Embedded");
 
+    if (!locationCode.empty())
+    {
+        locationCodeInterface = objectServer.add_interface(
+            objectPath, "xyz.openbmc_project.Inventory.Decorator.LocationCode");
+        locationCodeInterface->register_property("LocationCode", locationCode);
+        locationCodeInterface->initialize();
+    }
+
     /* Add Asset interface. */
     assetInterface = objectServer.add_interface(
         objectPath, "xyz.openbmc_project.Inventory.Decorator.Asset");
@@ -135,6 +144,11 @@
     objectServer.remove_interface(embeddedLocationInterface);
     objectServer.remove_interface(assetInterface);
     objectServer.remove_interface(association);
+
+    if (locationCodeInterface != nullptr)
+    {
+        objectServer.remove_interface(locationCodeInterface);
+    }
 }
 
 void EStoraged::formatLuks(const std::vector<uint8_t>& password,
diff --git a/src/main.cpp b/src/main.cpp
index db3173a..d278724 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -70,9 +70,10 @@
             /* Look for the device file. */
             const std::filesystem::path blockDevDir{"/sys/block"};
             std::filesystem::path deviceFile, sysfsDir;
-            std::string luksName;
-            bool found = estoraged::util::findDevice(
-                data, blockDevDir, deviceFile, sysfsDir, luksName);
+            std::string luksName, locationCode;
+            bool found = estoraged::util::findDevice(data, blockDevDir,
+                                                     deviceFile, sysfsDir,
+                                                     luksName, locationCode);
             if (!found)
             {
                 lg2::error("Device not found for path {PATH}", "PATH", path,
@@ -96,7 +97,7 @@
             /* Create the storage object. */
             storageObjects[path] = std::make_unique<estoraged::EStoraged>(
                 objectServer, path, deviceFile, luksName, size, lifeleft,
-                partNumber, serialNumber);
+                partNumber, serialNumber, locationCode);
             lg2::info("Created eStoraged object for path {PATH}", "PATH", path,
                       "REDFISH_MESSAGE_ID",
                       std::string("OpenBMC.0.1.CreateStorageObjects"));
diff --git a/src/test/estoraged_test.cpp b/src/test/estoraged_test.cpp
index ca0e21f..bd6db0d 100644
--- a/src/test/estoraged_test.cpp
+++ b/src/test/estoraged_test.cpp
@@ -44,6 +44,7 @@
     const uint8_t testLifeTime = 25;
     const std::string testPartNumber = "12345678";
     const std::string testSerialNumber = "ABCDEF1234";
+    const std::string testLocationCode = "U102020";
     std::ofstream testFile;
     std::string passwordString;
     std::vector<uint8_t> password;
@@ -88,7 +89,7 @@
         esObject = std::make_unique<estoraged::EStoraged>(
             *objectServer, testConfigPath, testFileName, testLuksDevName,
             testSize, testLifeTime, testPartNumber, testSerialNumber,
-            std::move(cryptIface), std::move(fsIface));
+            testLocationCode, std::move(cryptIface), std::move(fsIface));
     }
 
     void TearDown() override
diff --git a/src/test/util_test.cpp b/src/test/util_test.cpp
index b85fca0..5f8dca5 100644
--- a/src/test/util_test.cpp
+++ b/src/test/util_test.cpp
@@ -107,6 +107,8 @@
     data.emplace(std::string("Type"),
                  estoraged::BasicVariantType("EmmcDevice"));
     data.emplace(std::string("Name"), estoraged::BasicVariantType("emmc"));
+    data.emplace(std::string("LocationCode"),
+                 estoraged::BasicVariantType("U102020"));
 
     /* Create a dummy device. */
     std::filesystem::create_directories("abc/device");
@@ -128,14 +130,16 @@
 
     /* Look for the device file. */
     std::filesystem::path deviceFile, sysfsDir;
-    std::string luksName;
+    std::string luksName, locationCode;
     EXPECT_TRUE(estoraged::util::findDevice(data, std::filesystem::path("./"),
-                                            deviceFile, sysfsDir, luksName));
+                                            deviceFile, sysfsDir, luksName,
+                                            locationCode));
 
     /* Validate the results. */
     EXPECT_EQ("/dev/mmcblk0", deviceFile.string());
     EXPECT_EQ("./mmcblk0/device", sysfsDir.string());
     EXPECT_EQ("luks-mmcblk0", luksName);
+    EXPECT_EQ("U102020", locationCode);
 
     /* Delete the dummy files. */
     EXPECT_EQ(3U, std::filesystem::remove_all("mmcblk0"));
@@ -171,9 +175,10 @@
 
     /* Look for the device file. */
     std::filesystem::path deviceFile, sysfsDir;
-    std::string luksName;
+    std::string luksName, locationCode;
     EXPECT_FALSE(estoraged::util::findDevice(data, std::filesystem::path("./"),
-                                             deviceFile, sysfsDir, luksName));
+                                             deviceFile, sysfsDir, luksName,
+                                             locationCode));
 
     /* Delete the dummy files. */
     EXPECT_EQ(3U, std::filesystem::remove_all("mmcblk0"));
@@ -211,9 +216,10 @@
 
     /* Look for the device file. */
     std::filesystem::path deviceFile, sysfsDir;
-    std::string luksName;
+    std::string luksName, locationCode;
     EXPECT_FALSE(estoraged::util::findDevice(data, std::filesystem::path("./"),
-                                             deviceFile, sysfsDir, luksName));
+                                             deviceFile, sysfsDir, luksName,
+                                             locationCode));
 
     /* Delete the dummy files. */
     EXPECT_EQ(3U, std::filesystem::remove_all("mmcblk0"));
@@ -244,9 +250,10 @@
 
     /* Look for the device file. */
     std::filesystem::path deviceFile, sysfsDir;
-    std::string luksName;
+    std::string luksName, locationCode;
     EXPECT_FALSE(estoraged::util::findDevice(data, std::filesystem::path("./"),
-                                             deviceFile, sysfsDir, luksName));
+                                             deviceFile, sysfsDir, luksName,
+                                             locationCode));
 
     /* Delete the dummy files. */
     EXPECT_EQ(3U, std::filesystem::remove_all("abc"));
diff --git a/src/util.cpp b/src/util.cpp
index 8aad066..2f32c02 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -144,7 +144,8 @@
 
 bool findDevice(const StorageData& data, const std::filesystem::path& searchDir,
                 std::filesystem::path& deviceFile,
-                std::filesystem::path& sysfsDir, std::string& luksName)
+                std::filesystem::path& sysfsDir, std::string& luksName,
+                std::string& locationCode)
 {
     /* Check what type of storage device this is. */
     estoraged::BasicVariantType typeVariant;
@@ -160,6 +161,18 @@
         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.