fw-update: Add StartUpdate D-Bus API support for firmware updates

This commit adds support for the StartUpdate D-Bus API to enable FW
updates through the xyz.openbmc_project.Software.Update interface. The
user would need to enable `fw-update-pkg-inotify` meson option to
switch to inotify mechanism.

The existing inotify mechanism has critical limitations:
- Race condition between a BMC code updater and PLDM updater when
  accessing images from /tmp/images directory
- Lack of a standard D-Bus interface for firmware operations
- No proper error handling or status reporting

This implementation follows the upstream design for device & component
level inventory & update, based on the proposed code-update design
document [1]. The FW Update is triggered at the top-level i.e. all valid
targets will be updated with a single StartUpdate call.

Key changes:
- Add Update class implementing the Software.Update D-Bus interface
- Add startUpdate method that accepts file descriptors and processes
  firmware packages via streams
- Refactor UpdateManager to support both file path and stream-based
  package processing

Tests:
- Successful FW Update with both inotify and startUpdate flows on
  gb200nvl-obmc platform with multiple components (GPU + SMA)
- FW Update failure case by modifying the package size. The Redfish task
  immediately fails with Exception after creation.

[1]: https://gerrit.openbmc.org/c/openbmc/docs/+/76645

Change-Id: Ic2ca74431316161de844f6a3966f612760f5c298
Signed-off-by: P Arun Kumar Reddy <arunpapannagari23@gmail.com>
diff --git a/fw-update/update.cpp b/fw-update/update.cpp
new file mode 100644
index 0000000..5423cf8
--- /dev/null
+++ b/fw-update/update.cpp
@@ -0,0 +1,50 @@
+#include "update.hpp"
+
+#include "update_manager.hpp"
+
+namespace pldm
+{
+namespace fw_update
+{
+
+sdbusplus::message::object_path Update::startUpdate(
+    sdbusplus::message::unix_fd image,
+    ApplyTimeIntf::RequestedApplyTimes applyTime [[maybe_unused]])
+{
+    namespace software = sdbusplus::xyz::openbmc_project::Software::server;
+    // If a firmware activation of a package is in progress, don't proceed with
+    // package processing
+    if (updateManager->activation)
+    {
+        if (updateManager->activation->activation() ==
+            software::Activation::Activations::Activating)
+        {
+            throw sdbusplus::xyz::openbmc_project::Common::Error::Unavailable();
+        }
+        else
+        {
+            updateManager->clearActivationInfo();
+        }
+    }
+
+    info("Starting update for image {FD}", "FD", image.fd);
+    char buffer[4096];
+    ssize_t bytesRead;
+    imageStream.str(std::string());
+
+    while ((bytesRead = read(image, buffer, sizeof(buffer))) > 0)
+    {
+        imageStream.write(buffer, bytesRead);
+    }
+
+    if (bytesRead < 0)
+    {
+        throw std::runtime_error("Failed to read image file descriptor");
+    }
+
+    return sdbusplus::message::object_path(updateManager->processStreamDefer(
+        imageStream, imageStream.str().size()));
+}
+
+} // namespace fw_update
+} // namespace pldm