bios_setting: Add a read handler

Tested:
```
~# echo -n "01234567" > /run/oem_bios_setting
~# ipmitool raw 0x2e 0x32 0x79 0x2b 0x00 0x18
 79 2b 00 18 08 30 31 32 33 34 35 36 37
~# rm /run/oem_bios_setting
~# ipmitool raw 0x2e 0x32 0x79 0x2b 0x00 0x18
Unable to send RAW command (channel=0x0 netfn=0x2e lun=0x0 cmd=0x32 rsp=0xca): Cannot return number of requested data bytes
```

Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: Icde2de4799a751634f56a580351bf10254dd7e4f
diff --git a/bios_setting.cpp b/bios_setting.cpp
new file mode 100644
index 0000000..d92f786
--- /dev/null
+++ b/bios_setting.cpp
@@ -0,0 +1,76 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "bios_setting.hpp"
+
+#include "commands.hpp"
+#include "errors.hpp"
+#include "handler.hpp"
+
+#include <ipmid/api-types.hpp>
+#include <stdplus/fd/create.hpp>
+#include <stdplus/fd/managed.hpp>
+#include <stdplus/fd/ops.hpp>
+#include <stdplus/print.hpp>
+
+#include <filesystem>
+#include <fstream>
+#include <span>
+#include <vector>
+
+namespace google
+{
+namespace ipmi
+{
+
+std::vector<uint8_t> readBiosSettingFromFile(const std::string& biosSettingPath)
+{
+    std::vector<uint8_t> biosSettings;
+    try
+    {
+        stdplus::ManagedFd managedFd = stdplus::fd::open(
+            biosSettingPath,
+            stdplus::fd::OpenFlags(stdplus::fd::OpenAccess::ReadOnly));
+        biosSettings = stdplus::fd::readAll<std::vector<uint8_t>>(managedFd);
+    }
+    catch (const std::exception& e)
+    {
+        stdplus::print(stderr, "Read unsuccessful: {}\n", e.what());
+        return {};
+    }
+    return biosSettings;
+}
+
+Resp readBiosSetting(std::span<const uint8_t>, HandlerInterface*,
+                     const std::string& biosSettingPath)
+{
+    std::vector<uint8_t> biosSettings =
+        readBiosSettingFromFile(biosSettingPath);
+    size_t settingsLength = biosSettings.size();
+    if (settingsLength == 0)
+    {
+        return ::ipmi::responseRetBytesUnavailable();
+    }
+
+    // Reply format is: Length of the payload (1 byte) + payload
+    std::vector<std::uint8_t> reply;
+    reply.reserve(1 + settingsLength);
+    reply.emplace_back(static_cast<uint8_t>(settingsLength));
+    reply.insert(reply.end(), biosSettings.begin(), biosSettings.end());
+
+    return ::ipmi::responseSuccess(SysOEMCommands::SysReadBiosSetting, reply);
+}
+
+} // namespace ipmi
+} // namespace google