fru-device: move Adding and updating a property into a helper

Adds updating and adding properties to a helper function
that's divorced from dbus logic. This allows other code
to modify a fru buffer.

Tested:
Called updateproperty on nvl32-obmc. Result was correct

Change-Id: I432f89003cf5608900c018f72edef877534bfe40
Signed-off-by: Marc Olberding <molberding@nvidia.com>
diff --git a/src/fru_device/fru_device.cpp b/src/fru_device/fru_device.cpp
index 1b2de93..324afcd 100644
--- a/src/fru_device/fru_device.cpp
+++ b/src/fru_device/fru_device.cpp
@@ -1212,16 +1212,6 @@
         "updateFruProperty called: FieldName = {NAME}, FieldValue = {VALUE}",
         "NAME", propertyName, "VALUE", propertyValue);
 
-    // Validate field length: must be 2–63 characters
-    const size_t len = propertyValue.length();
-    if (len == 1 || len > 63)
-    {
-        lg2::error(
-            "FRU field data must be 0 or between 2 and 63 characters. Invalid Length: {LEN}",
-            "LEN", len);
-        return false;
-    }
-
     std::vector<uint8_t> fruData;
     if (!getFruData(fruData, bus, address))
     {
@@ -1230,69 +1220,12 @@
         return false;
     }
 
-    if (fruData.empty())
+    bool success = updateAddProperty(propertyValue, propertyName, fruData);
+    if (!success)
     {
-        lg2::error("Empty FRU data\n");
-        return false;
-    }
-
-    // Extract area name (prefix before underscore)
-    std::string areaName = propertyName.substr(0, propertyName.find('_'));
-    auto areaIterator =
-        std::find(fruAreaNames.begin(), fruAreaNames.end(), areaName);
-    if (areaIterator == fruAreaNames.end())
-    {
-        lg2::error("Failed to get FRU area for property: {AREA}", "AREA",
-                   areaName);
-        return false;
-    }
-
-    fruAreas fruAreaToUpdate = static_cast<fruAreas>(
-        std::distance(fruAreaNames.begin(), areaIterator));
-
-    std::vector<std::vector<uint8_t>> areasData;
-    if (!disassembleFruData(fruData, areasData))
-    {
-        lg2::error("Failed to disassemble Fru Data");
-        return false;
-    }
-
-    std::vector<uint8_t>& areaData =
-        areasData[static_cast<size_t>(fruAreaToUpdate)];
-    if (areaData.empty())
-    {
-        // If ENABLE_FRU_AREA_RESIZE is not defined then return with failure
-#ifndef ENABLE_FRU_AREA_RESIZE
         lg2::error(
-            "FRU area {AREA} not present and ENABLE_FRU_AREA_RESIZE is not set. "
-            "Returning failure.",
-            "AREA", areaName);
-        return false;
-#endif
-        if (!createDummyArea(fruAreaToUpdate, areaData))
-        {
-            lg2::error("Failed to create dummy area for {AREA}", "AREA",
-                       areaName);
-            return false;
-        }
-    }
-
-    if (!setField(fruAreaToUpdate, areaData, propertyName, propertyValue))
-    {
-        lg2::error("Failed to set field value for property: {PROPERTY}",
-                   "PROPERTY", propertyName);
-        return false;
-    }
-
-    if (!assembleFruData(fruData, areasData))
-    {
-        lg2::error("Failed to reassemble FRU data");
-        return false;
-    }
-
-    if (fruData.empty())
-    {
-        lg2::error("FRU data is empty after assembly");
+            "Failed to update the property on bus {BUS}, address {ADDRESS}",
+            "BUS", bus, "ADDRESS", address);
         return false;
     }
 
diff --git a/src/fru_device/fru_utils.cpp b/src/fru_device/fru_utils.cpp
index 385ea72..c9669de 100644
--- a/src/fru_device/fru_utils.cpp
+++ b/src/fru_device/fru_utils.cpp
@@ -1667,3 +1667,86 @@
     // Match against editable fields
     return std::ranges::contains(editableFields, subField);
 }
+
+bool updateAddProperty(const std::string& propertyValue,
+                       const std::string& propertyName,
+                       std::vector<uint8_t>& fruData)
+{
+    // Validate field length: must be 2–63 characters
+    const size_t len = propertyValue.length();
+    if (len == 1 || len > 63)
+    {
+        lg2::error(
+            "FRU field data must be 0 or between 2 and 63 characters. Invalid Length: {LEN}",
+            "LEN", len);
+        return false;
+    }
+
+    if (fruData.empty())
+    {
+        lg2::error("Empty FRU data\n");
+        return false;
+    }
+
+    // Extract area name (prefix before underscore)
+    std::string areaName = propertyName.substr(0, propertyName.find('_'));
+    auto areaIterator =
+        std::find(fruAreaNames.begin(), fruAreaNames.end(), areaName);
+    if (areaIterator == fruAreaNames.end())
+    {
+        lg2::error("Failed to get FRU area for property: {AREA}", "AREA",
+                   areaName);
+        return false;
+    }
+
+    fruAreas fruAreaToUpdate = static_cast<fruAreas>(
+        std::distance(fruAreaNames.begin(), areaIterator));
+
+    std::vector<std::vector<uint8_t>> areasData;
+    if (!disassembleFruData(fruData, areasData))
+    {
+        lg2::error("Failed to disassemble Fru Data");
+        return false;
+    }
+
+    std::vector<uint8_t>& areaData =
+        areasData[static_cast<size_t>(fruAreaToUpdate)];
+    if (areaData.empty())
+    {
+        // If ENABLE_FRU_AREA_RESIZE is not defined then return with failure
+#ifndef ENABLE_FRU_AREA_RESIZE
+        lg2::error(
+            "FRU area {AREA} not present and ENABLE_FRU_AREA_RESIZE is not set. "
+            "Returning failure.",
+            "AREA", areaName);
+        return false;
+#endif
+        if (!createDummyArea(fruAreaToUpdate, areaData))
+        {
+            lg2::error("Failed to create dummy area for {AREA}", "AREA",
+                       areaName);
+            return false;
+        }
+    }
+
+    if (!setField(fruAreaToUpdate, areaData, propertyName, propertyValue))
+    {
+        lg2::error("Failed to set field value for property: {PROPERTY}",
+                   "PROPERTY", propertyName);
+        return false;
+    }
+
+    if (!assembleFruData(fruData, areasData))
+    {
+        lg2::error("Failed to reassemble FRU data");
+        return false;
+    }
+
+    if (fruData.empty())
+    {
+        lg2::error("FRU data is empty after assembly");
+        return false;
+    }
+
+    return true;
+}
diff --git a/src/fru_device/fru_utils.hpp b/src/fru_device/fru_utils.hpp
index 2b32362..0491b30 100644
--- a/src/fru_device/fru_utils.hpp
+++ b/src/fru_device/fru_utils.hpp
@@ -226,3 +226,7 @@
 
 bool setField(const fruAreas& fruAreaToUpdate, std::vector<uint8_t>& areaData,
               const std::string& propertyName, const std::string& value);
+
+bool updateAddProperty(const std::string& propertyValue,
+                       const std::string& propertyName,
+                       std::vector<uint8_t>& data);