blob: 369926471b4bb9e46051ce7bf636d6f260680978 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
Jennifer Lee729dae72018-04-24 15:59:34 -07004#pragma once
5
Tejas Patild61e5192021-06-04 15:49:35 +05306#include "bmcweb_config.h"
7
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08008#include "app.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -08009#include "async_resp.hpp"
10#include "dbus_singleton.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011#include "dbus_utility.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070012#include "error_messages.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080013#include "generated/enums/resource.hpp"
Ed Tanous757178a2024-04-03 14:32:38 -070014#include "generated/enums/update_service.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080015#include "http_request.hpp"
16#include "http_response.hpp"
Ed Tanousd98a2f92025-02-06 17:36:31 -080017#include "io_context_singleton.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080018#include "logging.hpp"
George Liu0ed80c82020-05-12 16:06:27 +080019#include "multipart_parser.hpp"
Ed Tanous2c6ffdb2023-06-28 11:28:38 -070020#include "ossl_random.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include "query.hpp"
22#include "registries/privilege_registry.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080023#include "str_utility.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080024#include "task.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070025#include "task_messages.hpp"
Ed Tanousd7857202025-01-28 15:32:26 -080026#include "utility.hpp"
John Edward Broadbent08d81ad2022-05-17 20:00:23 -070027#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080028#include "utils/dbus_utils.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070029#include "utils/json_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080030#include "utils/sw_utils.hpp"
31
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070032#include <sys/mman.h>
Ed Tanousd7857202025-01-28 15:32:26 -080033#include <unistd.h>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070034
Ed Tanousd7857202025-01-28 15:32:26 -080035#include <boost/asio/error.hpp>
36#include <boost/asio/steady_timer.hpp>
37#include <boost/beast/http/fields.hpp>
38#include <boost/beast/http/status.hpp>
39#include <boost/beast/http/verb.hpp>
George Liue99073f2022-12-09 11:06:16 +080040#include <boost/system/error_code.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080041#include <boost/system/result.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070042#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080043#include <boost/url/parse.hpp>
44#include <boost/url/url.hpp>
45#include <boost/url/url_view.hpp>
46#include <boost/url/url_view_base.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070047#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080048#include <sdbusplus/bus/match.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080049#include <sdbusplus/message.hpp>
50#include <sdbusplus/message/native_types.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020051#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050052
George Liu2b731192023-01-11 16:27:13 +080053#include <array>
Ed Tanousd7857202025-01-28 15:32:26 -080054#include <chrono>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070055#include <cstddef>
Ed Tanousd7857202025-01-28 15:32:26 -080056#include <cstdint>
57#include <cstdio>
George Liu0ed80c82020-05-12 16:06:27 +080058#include <filesystem>
Ed Tanousd7857202025-01-28 15:32:26 -080059#include <format>
60#include <fstream>
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -070061#include <functional>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070062#include <memory>
Ed Tanous7cb59f62022-05-05 11:48:31 -070063#include <optional>
64#include <string>
George Liu2b731192023-01-11 16:27:13 +080065#include <string_view>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070066#include <unordered_map>
Ed Tanousd7857202025-01-28 15:32:26 -080067#include <utility>
68#include <variant>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070069#include <vector>
George Liu2b731192023-01-11 16:27:13 +080070
Ed Tanous1abe55e2018-09-05 08:30:59 -070071namespace redfish
72{
Ed Tanous27826b52018-10-29 11:40:58 -070073
Andrew Geissler0e7de462019-03-04 19:11:54 -060074// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080075// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050076static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080077// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050078static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060079// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080080// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060081static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050082// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080083// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070084static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050085
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070086struct MemoryFileDescriptor
87{
88 int fd = -1;
89
90 explicit MemoryFileDescriptor(const std::string& filename) :
91 fd(memfd_create(filename.c_str(), 0))
92 {}
93
94 MemoryFileDescriptor(const MemoryFileDescriptor&) = default;
95 MemoryFileDescriptor(MemoryFileDescriptor&& other) noexcept : fd(other.fd)
96 {
97 other.fd = -1;
98 }
99 MemoryFileDescriptor& operator=(const MemoryFileDescriptor&) = delete;
100 MemoryFileDescriptor& operator=(MemoryFileDescriptor&&) = default;
101
102 ~MemoryFileDescriptor()
103 {
104 if (fd != -1)
105 {
106 close(fd);
107 }
108 }
109
110 bool rewind() const
111 {
112 if (lseek(fd, 0, SEEK_SET) == -1)
113 {
114 BMCWEB_LOG_ERROR("Failed to seek to beginning of image memfd");
115 return false;
116 }
117 return true;
118 }
119};
120
Ed Tanousdf254f22024-04-01 13:25:46 -0700121inline void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -0500122{
123 fwUpdateInProgress = false;
124 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -0700125 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500126}
Ed Tanousdf254f22024-04-01 13:25:46 -0700127
128inline void activateImage(const std::string& objPath,
129 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500130{
Ed Tanous62598e32023-07-17 17:06:25 -0700131 BMCWEB_LOG_DEBUG("Activate image for {} {}", objPath, service);
George Liu9ae226f2023-06-21 17:56:46 +0800132 sdbusplus::asio::setProperty(
133 *crow::connections::systemBus, service, objPath,
134 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
135 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
Ed Tanous8b242752023-06-27 17:17:13 -0700136 [](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400137 if (ec)
138 {
139 BMCWEB_LOG_DEBUG("error_code = {}", ec);
140 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
141 }
142 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500143}
Andrew Geissler0554c982019-04-23 14:40:12 -0500144
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -0700145inline bool handleCreateTask(const boost::system::error_code& ec2,
146 sdbusplus::message_t& msg,
147 const std::shared_ptr<task::TaskData>& taskData)
148{
149 if (ec2)
150 {
151 return task::completed;
152 }
153
154 std::string iface;
155 dbus::utility::DBusPropertiesMap values;
156
157 std::string index = std::to_string(taskData->index);
158 msg.read(iface, values);
159
160 if (iface == "xyz.openbmc_project.Software.Activation")
161 {
162 const std::string* state = nullptr;
163 for (const auto& property : values)
164 {
165 if (property.first == "Activation")
166 {
167 state = std::get_if<std::string>(&property.second);
168 if (state == nullptr)
169 {
170 taskData->messages.emplace_back(messages::internalError());
171 return task::completed;
172 }
173 }
174 }
175
176 if (state == nullptr)
177 {
178 return !task::completed;
179 }
180
181 if (state->ends_with("Invalid") || state->ends_with("Failed"))
182 {
183 taskData->state = "Exception";
184 taskData->status = "Warning";
185 taskData->messages.emplace_back(messages::taskAborted(index));
186 return task::completed;
187 }
188
189 if (state->ends_with("Staged"))
190 {
191 taskData->state = "Stopping";
192 taskData->messages.emplace_back(messages::taskPaused(index));
193
194 // its staged, set a long timer to
195 // allow them time to complete the
196 // update (probably cycle the
197 // system) if this expires then
198 // task will be canceled
199 taskData->extendTimer(std::chrono::hours(5));
200 return !task::completed;
201 }
202
203 if (state->ends_with("Active"))
204 {
205 taskData->messages.emplace_back(messages::taskCompletedOK(index));
206 taskData->state = "Completed";
207 return task::completed;
208 }
209 }
210 else if (iface == "xyz.openbmc_project.Software.ActivationProgress")
211 {
212 const uint8_t* progress = nullptr;
213 for (const auto& property : values)
214 {
215 if (property.first == "Progress")
216 {
217 progress = std::get_if<uint8_t>(&property.second);
218 if (progress == nullptr)
219 {
220 taskData->messages.emplace_back(messages::internalError());
221 return task::completed;
222 }
223 }
224 }
225
226 if (progress == nullptr)
227 {
228 return !task::completed;
229 }
230 taskData->percentComplete = *progress;
231 taskData->messages.emplace_back(
232 messages::taskProgressChanged(index, *progress));
233
234 // if we're getting status updates it's
235 // still alive, update timer
236 taskData->extendTimer(std::chrono::minutes(5));
237 }
238
239 // as firmware update often results in a
240 // reboot, the task may never "complete"
241 // unless it is an error
242
243 return !task::completed;
244}
245
246inline void createTask(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
247 task::Payload&& payload,
248 const sdbusplus::message::object_path& objPath)
249{
250 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
251 std::bind_front(handleCreateTask),
252 "type='signal',interface='org.freedesktop.DBus.Properties',"
253 "member='PropertiesChanged',path='" +
254 objPath.str + "'");
255 task->startTimer(std::chrono::minutes(5));
256 task->populateResp(asyncResp->res);
257 task->payload.emplace(std::move(payload));
258}
259
Andrew Geissler0554c982019-04-23 14:40:12 -0500260// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
261// then no asyncResp updates will occur
Patrick Williams504af5a2025-02-03 14:29:03 -0500262inline void softwareInterfaceAdded(
263 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
264 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500265{
Michael Shen80f79a42023-08-24 13:41:53 +0000266 dbus::utility::DBusInterfacesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500267
268 sdbusplus::message::object_path objPath;
269
270 m.read(objPath, interfacesProperties);
271
Ed Tanous62598e32023-07-17 17:06:25 -0700272 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
Ed Tanouse3eb3d62022-12-21 11:56:07 -0800273 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500274 {
Ed Tanous62598e32023-07-17 17:06:25 -0700275 BMCWEB_LOG_DEBUG("interface = {}", interface.first);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500276
277 if (interface.first == "xyz.openbmc_project.Software.Activation")
278 {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500279 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +0800280 constexpr std::array<std::string_view, 1> interfaces = {
281 "xyz.openbmc_project.Software.Activation"};
282 dbus::utility::getDbusObject(
283 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -0700284 [objPath, asyncResp, payload(std::move(payload))](
Ed Tanous8b242752023-06-27 17:17:13 -0700285 const boost::system::error_code& ec,
Ed Tanousa3e65892021-09-16 14:13:20 -0700286 const std::vector<
287 std::pair<std::string, std::vector<std::string>>>&
288 objInfo) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400289 if (ec)
Andrew Geissler0554c982019-04-23 14:40:12 -0500290 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400291 BMCWEB_LOG_DEBUG("error_code = {}", ec);
292 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
293 if (asyncResp)
294 {
295 messages::internalError(asyncResp->res);
296 }
297 cleanUp();
298 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700299 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400300 // Ensure we only got one service back
301 if (objInfo.size() != 1)
Ed Tanous002d39b2022-05-31 08:59:27 -0700302 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400303 BMCWEB_LOG_ERROR("Invalid Object Size {}",
304 objInfo.size());
305 if (asyncResp)
306 {
307 messages::internalError(asyncResp->res);
308 }
309 cleanUp();
310 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700311 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400312 // cancel timer only when
313 // xyz.openbmc_project.Software.Activation interface
314 // is added
315 fwAvailableTimer = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700316
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400317 activateImage(objPath.str, objInfo[0].first);
318 if (asyncResp)
319 {
320 createTask(asyncResp, std::move(payload), objPath);
321 }
322 fwUpdateInProgress = false;
323 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500324
325 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500326 }
327 }
328}
329
Myung Bae8549b952023-08-16 15:18:19 -0400330inline void afterAvailbleTimerAsyncWait(
331 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
332 const boost::system::error_code& ec)
333{
334 cleanUp();
335 if (ec == boost::asio::error::operation_aborted)
336 {
337 // expected, we were canceled before the timer completed.
338 return;
339 }
340 BMCWEB_LOG_ERROR("Timed out waiting for firmware object being created");
341 BMCWEB_LOG_ERROR("FW image may has already been uploaded to server");
342 if (ec)
343 {
344 BMCWEB_LOG_ERROR("Async_wait failed{}", ec);
345 return;
346 }
347 if (asyncResp)
348 {
349 redfish::messages::internalError(asyncResp->res);
350 }
351}
352
Patrick Williams504af5a2025-02-03 14:29:03 -0500353inline void handleUpdateErrorType(
354 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& url,
355 const std::string& type)
Myung Bae8549b952023-08-16 15:18:19 -0400356{
Ed Tanousc87294a2024-11-16 22:17:12 -0800357 // NOLINTBEGIN(bugprone-branch-clone)
Myung Bae8549b952023-08-16 15:18:19 -0400358 if (type == "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
359 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800360 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400361 }
362 else if (type ==
363 "xyz.openbmc_project.Software.Image.Error.ManifestFileFailure")
364 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800365 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400366 }
367 else if (type == "xyz.openbmc_project.Software.Image.Error.ImageFailure")
368 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800369 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400370 }
371 else if (type == "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
372 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800373 messages::resourceAlreadyExists(asyncResp->res, "UpdateService",
374 "Version", "uploaded version");
Myung Bae8549b952023-08-16 15:18:19 -0400375 }
376 else if (type == "xyz.openbmc_project.Software.Image.Error.BusyFailure")
377 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800378 messages::serviceTemporarilyUnavailable(asyncResp->res, url);
Myung Bae8549b952023-08-16 15:18:19 -0400379 }
Myung Bae4034a652023-08-17 08:47:35 -0400380 else if (type == "xyz.openbmc_project.Software.Version.Error.Incompatible")
Myung Bae8549b952023-08-16 15:18:19 -0400381 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800382 messages::internalError(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400383 }
384 else if (type ==
385 "xyz.openbmc_project.Software.Version.Error.ExpiredAccessKey")
386 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800387 messages::internalError(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400388 }
389 else if (type ==
390 "xyz.openbmc_project.Software.Version.Error.InvalidSignature")
391 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800392 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400393 }
394 else if (type ==
395 "xyz.openbmc_project.Software.Image.Error.InternalFailure" ||
396 type == "xyz.openbmc_project.Software.Version.Error.HostFile")
397 {
398 BMCWEB_LOG_ERROR("Software Image Error type={}", type);
Ed Tanous48fb20b2024-11-17 11:51:13 -0800399 messages::internalError(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400400 }
Myung Bae4034a652023-08-17 08:47:35 -0400401 else
402 {
403 // Unrelated error types. Ignored
404 BMCWEB_LOG_INFO("Non-Software-related Error type={}. Ignored", type);
405 return;
406 }
Ed Tanousc87294a2024-11-16 22:17:12 -0800407 // NOLINTEND(bugprone-branch-clone)
Myung Bae4034a652023-08-17 08:47:35 -0400408 // Clear the timer
409 fwAvailableTimer = nullptr;
Myung Bae8549b952023-08-16 15:18:19 -0400410}
411
Patrick Williams504af5a2025-02-03 14:29:03 -0500412inline void afterUpdateErrorMatcher(
413 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& url,
414 sdbusplus::message_t& m)
Myung Bae8549b952023-08-16 15:18:19 -0400415{
Michael Shen80f79a42023-08-24 13:41:53 +0000416 dbus::utility::DBusInterfacesMap interfacesProperties;
Myung Bae8549b952023-08-16 15:18:19 -0400417 sdbusplus::message::object_path objPath;
418 m.read(objPath, interfacesProperties);
419 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
420 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
421 interface : interfacesProperties)
422 {
423 if (interface.first == "xyz.openbmc_project.Logging.Entry")
424 {
425 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
426 value : interface.second)
427 {
428 if (value.first != "Message")
429 {
430 continue;
431 }
432 const std::string* type =
433 std::get_if<std::string>(&value.second);
434 if (type == nullptr)
435 {
436 // if this was our message, timeout will cover it
437 return;
438 }
Myung Bae8549b952023-08-16 15:18:19 -0400439 handleUpdateErrorType(asyncResp, url, *type);
440 }
441 }
442 }
443}
444
Andrew Geissler0554c982019-04-23 14:40:12 -0500445// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
446// then no asyncResp updates will occur
Ed Tanousf5139332024-04-03 13:25:04 -0700447inline void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800448 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
449 const crow::Request& req, const std::string& url,
Gunnar Mills19406772025-03-04 14:42:46 -0600450 int timeoutTimeSeconds = 50)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500451{
452 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800453 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500454 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500455 if (asyncResp)
456 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500457 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
458 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500459 return;
460 }
461
Andrew Geissler0554c982019-04-23 14:40:12 -0500462 fwAvailableTimer =
Ed Tanousd98a2f92025-02-06 17:36:31 -0800463 std::make_unique<boost::asio::steady_timer>(getIoContext());
Andrew Geissler86adcd62019-04-18 10:58:05 -0500464
Ed Tanous271584a2019-07-09 16:24:22 -0700465 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500466
467 fwAvailableTimer->async_wait(
Myung Bae8549b952023-08-16 15:18:19 -0400468 std::bind_front(afterAvailbleTimerAsyncWait, asyncResp));
469
Ed Tanousa3e65892021-09-16 14:13:20 -0700470 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500471 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -0700472 BMCWEB_LOG_DEBUG("Match fired");
Ed Tanousa3e65892021-09-16 14:13:20 -0700473 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500474 };
475
476 fwUpdateInProgress = true;
477
Patrick Williams59d494e2022-07-22 19:26:55 -0500478 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500479 *crow::connections::systemBus,
480 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
481 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
482 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700483
Patrick Williams59d494e2022-07-22 19:26:55 -0500484 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700485 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800486 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
487 "member='InterfacesAdded',"
488 "path='/xyz/openbmc_project/logging'",
Myung Bae8549b952023-08-16 15:18:19 -0400489 std::bind_front(afterUpdateErrorMatcher, asyncResp, url));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500490}
Jennifer Lee729dae72018-04-24 15:59:34 -0700491
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400492inline std::optional<boost::urls::url> parseSimpleUpdateUrl(
493 std::string imageURI, std::optional<std::string> transferProtocol,
494 crow::Response& res)
Ed Tanousf86bcc82023-08-25 09:34:07 -0700495{
496 if (imageURI.find("://") == std::string::npos)
497 {
498 if (imageURI.starts_with("/"))
499 {
500 messages::actionParameterValueTypeError(
501 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
502 return std::nullopt;
503 }
504 if (!transferProtocol)
505 {
506 messages::actionParameterValueTypeError(
507 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
508 return std::nullopt;
509 }
Ed Tanous6a371402024-12-03 14:01:25 -0800510 // OpenBMC currently only supports HTTPS
511 if (*transferProtocol == "HTTPS")
Ed Tanouse5cf7772024-04-03 13:45:31 -0700512 {
513 imageURI = "https://" + imageURI;
514 }
Ed Tanous757178a2024-04-03 14:32:38 -0700515 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700516 {
517 messages::actionParameterNotSupported(res, "TransferProtocol",
518 *transferProtocol);
519 BMCWEB_LOG_ERROR("Request incorrect protocol parameter: {}",
520 *transferProtocol);
521 return std::nullopt;
522 }
Ed Tanousf86bcc82023-08-25 09:34:07 -0700523 }
524
525 boost::system::result<boost::urls::url> url =
526 boost::urls::parse_absolute_uri(imageURI);
527 if (!url)
528 {
529 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
530 "UpdateService.SimpleUpdate");
531
532 return std::nullopt;
533 }
534 url->normalize();
535
Ed Tanous757178a2024-04-03 14:32:38 -0700536 if (url->scheme() == "tftp")
537 {
538 if (url->encoded_path().size() < 2)
539 {
540 messages::actionParameterNotSupported(res, "ImageURI",
541 url->buffer());
542 return std::nullopt;
543 }
544 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700545 else if (url->scheme() == "https")
546 {
547 // Empty paths default to "/"
548 if (url->encoded_path().empty())
549 {
550 url->set_encoded_path("/");
551 }
552 }
Ed Tanous757178a2024-04-03 14:32:38 -0700553 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700554 {
555 messages::actionParameterNotSupported(res, "ImageURI", imageURI);
556 return std::nullopt;
557 }
Ed Tanous757178a2024-04-03 14:32:38 -0700558
559 if (url->encoded_path().empty())
Ed Tanousf86bcc82023-08-25 09:34:07 -0700560 {
Ed Tanous757178a2024-04-03 14:32:38 -0700561 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
562 "UpdateService.SimpleUpdate");
Ed Tanousf86bcc82023-08-25 09:34:07 -0700563 return std::nullopt;
564 }
Ed Tanous757178a2024-04-03 14:32:38 -0700565
566 return *url;
Ed Tanousf86bcc82023-08-25 09:34:07 -0700567}
568
Ed Tanouse5cf7772024-04-03 13:45:31 -0700569inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
570 const boost::urls::url_view_base& url)
571{
572 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
573 url.buffer());
574}
575
Ed Tanousf5139332024-04-03 13:25:04 -0700576inline void handleUpdateServiceSimpleUpdateAction(
577 crow::App& app, const crow::Request& req,
578 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Andrew Geissler0554c982019-04-23 14:40:12 -0500579{
Ed Tanousf5139332024-04-03 13:25:04 -0700580 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
581 {
582 return;
583 }
584
585 std::optional<std::string> transferProtocol;
586 std::string imageURI;
587
588 BMCWEB_LOG_DEBUG("Enter UpdateService.SimpleUpdate doPost");
589
590 // User can pass in both TransferProtocol and ImageURI parameters or
591 // they can pass in just the ImageURI with the transfer protocol
592 // embedded within it.
593 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
594 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
595
Patrick Williams504af5a2025-02-03 14:29:03 -0500596 if (!json_util::readJsonAction( //
597 req, asyncResp->res, //
598 "ImageURI", imageURI, //
Myung Baeafc474a2024-10-09 00:53:29 -0700599 "TransferProtocol", transferProtocol //
600 ))
Ed Tanousf5139332024-04-03 13:25:04 -0700601 {
602 BMCWEB_LOG_DEBUG("Missing TransferProtocol or ImageURI parameter");
603 return;
604 }
605
Ed Tanous757178a2024-04-03 14:32:38 -0700606 std::optional<boost::urls::url> url =
607 parseSimpleUpdateUrl(imageURI, transferProtocol, asyncResp->res);
608 if (!url)
Ed Tanousf5139332024-04-03 13:25:04 -0700609 {
610 return;
611 }
Jagpal Singh Gill4e338b22024-06-14 14:24:56 -0700612 if (url->scheme() == "https")
Ed Tanouse5cf7772024-04-03 13:45:31 -0700613 {
614 doHttpsUpdate(asyncResp, *url);
615 }
Ed Tanous757178a2024-04-03 14:32:38 -0700616 else
617 {
618 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
619 url->buffer());
620 return;
621 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700622
Ed Tanousf5139332024-04-03 13:25:04 -0700623 BMCWEB_LOG_DEBUG("Exit UpdateService.SimpleUpdate doPost");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700624}
625
George Liu0ed80c82020-05-12 16:06:27 +0800626inline void uploadImageFile(crow::Response& res, std::string_view body)
627{
Ed Tanous2c6ffdb2023-06-28 11:28:38 -0700628 std::filesystem::path filepath("/tmp/images/" + bmcweb::getRandomUUID());
629
Ed Tanous62598e32023-07-17 17:06:25 -0700630 BMCWEB_LOG_DEBUG("Writing file to {}", filepath.string());
George Liu0ed80c82020-05-12 16:06:27 +0800631 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
632 std::ofstream::trunc);
633 // set the permission of the file to 640
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400634 std::filesystem::perms permission =
635 std::filesystem::perms::owner_read | std::filesystem::perms::group_read;
George Liu0ed80c82020-05-12 16:06:27 +0800636 std::filesystem::permissions(filepath, permission);
637 out << body;
638
639 if (out.bad())
640 {
641 messages::internalError(res);
642 cleanUp();
643 }
644}
645
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700646// Convert the Request Apply Time to the D-Bus value
647inline bool convertApplyTime(crow::Response& res, const std::string& applyTime,
648 std::string& applyTimeNewVal)
649{
650 if (applyTime == "Immediate")
651 {
652 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700653 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700654 }
655 else if (applyTime == "OnReset")
656 {
657 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700658 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700659 }
660 else
661 {
662 BMCWEB_LOG_WARNING(
663 "ApplyTime value {} is not in the list of acceptable values",
664 applyTime);
665 messages::propertyValueNotInList(res, applyTime, "ApplyTime");
666 return false;
667 }
668 return true;
669}
670
George Liu0ed80c82020-05-12 16:06:27 +0800671inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
672 const std::string& applyTime)
673{
674 std::string applyTimeNewVal;
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700675 if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
George Liu0ed80c82020-05-12 16:06:27 +0800676 {
George Liu0ed80c82020-05-12 16:06:27 +0800677 return;
678 }
679
Ginu Georgee93abac2024-06-14 17:35:27 +0530680 setDbusProperty(asyncResp, "ApplyTime", "xyz.openbmc_project.Settings",
Ed Tanousd02aad32024-02-13 14:43:34 -0800681 sdbusplus::message::object_path(
682 "/xyz/openbmc_project/software/apply_time"),
683 "xyz.openbmc_project.Software.ApplyTime",
Ginu Georgee93abac2024-06-14 17:35:27 +0530684 "RequestedApplyTime", applyTimeNewVal);
George Liu0ed80c82020-05-12 16:06:27 +0800685}
686
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700687struct MultiPartUpdateParameters
George Liu0ed80c82020-05-12 16:06:27 +0800688{
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700689 std::optional<std::string> applyTime;
690 std::string uploadData;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700691 std::vector<std::string> targets;
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700692};
693
Patrick Williams504af5a2025-02-03 14:29:03 -0500694inline std::optional<std::string> processUrl(
695 boost::system::result<boost::urls::url_view>& url)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700696{
697 if (!url)
698 {
699 return std::nullopt;
700 }
701 if (crow::utility::readUrlSegments(*url, "redfish", "v1", "Managers",
702 BMCWEB_REDFISH_MANAGER_URI_NAME))
703 {
704 return std::make_optional(std::string(BMCWEB_REDFISH_MANAGER_URI_NAME));
705 }
706 if constexpr (!BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
707 {
708 return std::nullopt;
709 }
710 std::string firmwareId;
711 if (!crow::utility::readUrlSegments(*url, "redfish", "v1", "UpdateService",
712 "FirmwareInventory",
713 std::ref(firmwareId)))
714 {
715 return std::nullopt;
716 }
717
718 return std::make_optional(firmwareId);
719}
720
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700721inline std::optional<MultiPartUpdateParameters>
722 extractMultipartUpdateParameters(
723 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
724 MultipartParser parser)
725{
726 MultiPartUpdateParameters multiRet;
727 for (FormPart& formpart : parser.mime_fields)
George Liu0ed80c82020-05-12 16:06:27 +0800728 {
729 boost::beast::http::fields::const_iterator it =
730 formpart.fields.find("Content-Disposition");
731 if (it == formpart.fields.end())
732 {
Ed Tanous62598e32023-07-17 17:06:25 -0700733 BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700734 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800735 }
Ed Tanous62598e32023-07-17 17:06:25 -0700736 BMCWEB_LOG_INFO("Parsing value {}", it->value());
George Liu0ed80c82020-05-12 16:06:27 +0800737
738 // The construction parameters of param_list must start with `;`
739 size_t index = it->value().find(';');
740 if (index == std::string::npos)
741 {
742 continue;
743 }
744
Patrick Williams89492a12023-05-10 07:51:34 -0500745 for (const auto& param :
George Liu0ed80c82020-05-12 16:06:27 +0800746 boost::beast::http::param_list{it->value().substr(index)})
747 {
748 if (param.first != "name" || param.second.empty())
749 {
750 continue;
751 }
752
753 if (param.second == "UpdateParameters")
754 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700755 std::vector<std::string> tempTargets;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400756 nlohmann::json content =
757 nlohmann::json::parse(formpart.content, nullptr, false);
Ed Tanousac1e1242024-07-10 22:10:14 -0700758 if (content.is_discarded())
759 {
760 return std::nullopt;
761 }
Ed Tanous7cb59f62022-05-05 11:48:31 -0700762 nlohmann::json::object_t* obj =
763 content.get_ptr<nlohmann::json::object_t*>();
764 if (obj == nullptr)
765 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700766 messages::propertyValueTypeError(
767 asyncResp->res, formpart.content, "UpdateParameters");
768 return std::nullopt;
Ed Tanous7cb59f62022-05-05 11:48:31 -0700769 }
770
Patrick Williams504af5a2025-02-03 14:29:03 -0500771 if (!json_util::readJsonObject( //
772 *obj, asyncResp->res, //
Myung Baeafc474a2024-10-09 00:53:29 -0700773 "@Redfish.OperationApplyTime", multiRet.applyTime, //
Patrick Williams504af5a2025-02-03 14:29:03 -0500774 "Targets", tempTargets //
Myung Baeafc474a2024-10-09 00:53:29 -0700775 ))
George Liu0ed80c82020-05-12 16:06:27 +0800776 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700777 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800778 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700779
780 for (size_t urlIndex = 0; urlIndex < tempTargets.size();
781 urlIndex++)
George Liu0ed80c82020-05-12 16:06:27 +0800782 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700783 const std::string& target = tempTargets[urlIndex];
784 boost::system::result<boost::urls::url_view> url =
785 boost::urls::parse_origin_form(target);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700786 auto res = processUrl(url);
787 if (!res.has_value())
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700788 {
789 messages::propertyValueFormatError(
790 asyncResp->res, target,
791 std::format("Targets/{}", urlIndex));
792 return std::nullopt;
793 }
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700794 multiRet.targets.emplace_back(res.value());
George Liu0ed80c82020-05-12 16:06:27 +0800795 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700796 if (multiRet.targets.size() != 1)
George Liu0ed80c82020-05-12 16:06:27 +0800797 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700798 messages::propertyValueFormatError(
799 asyncResp->res, multiRet.targets, "Targets");
800 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800801 }
George Liu0ed80c82020-05-12 16:06:27 +0800802 }
803 else if (param.second == "UpdateFile")
804 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700805 multiRet.uploadData = std::move(formpart.content);
George Liu0ed80c82020-05-12 16:06:27 +0800806 }
807 }
808 }
809
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700810 if (multiRet.uploadData.empty())
George Liu0ed80c82020-05-12 16:06:27 +0800811 {
Ed Tanous62598e32023-07-17 17:06:25 -0700812 BMCWEB_LOG_ERROR("Upload data is NULL");
George Liu0ed80c82020-05-12 16:06:27 +0800813 messages::propertyMissing(asyncResp->res, "UpdateFile");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700814 return std::nullopt;
815 }
816 if (multiRet.targets.empty())
817 {
818 messages::propertyMissing(asyncResp->res, "Targets");
819 return std::nullopt;
820 }
821 return multiRet;
822}
823
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400824inline void handleStartUpdate(
825 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
826 const std::string& objectPath, const boost::system::error_code& ec,
827 const sdbusplus::message::object_path& retPath)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700828{
829 if (ec)
830 {
831 BMCWEB_LOG_ERROR("error_code = {}", ec);
832 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
833 messages::internalError(asyncResp->res);
834 return;
835 }
836
Jagpal Singh Gill587090c2024-08-12 00:24:16 -0700837 BMCWEB_LOG_INFO("Call to StartUpdate on {} Success, retPath = {}",
838 objectPath, retPath.str);
839 createTask(asyncResp, std::move(payload), retPath);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700840}
841
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400842inline void startUpdate(
843 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
844 const MemoryFileDescriptor& memfd, const std::string& applyTime,
845 const std::string& objectPath, const std::string& serviceName)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700846{
Ed Tanous177612a2025-02-14 15:16:09 -0800847 dbus::utility::async_method_call(
848 asyncResp,
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700849 [asyncResp, payload = std::move(payload),
850 objectPath](const boost::system::error_code& ec1,
851 const sdbusplus::message::object_path& retPath) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400852 handleStartUpdate(asyncResp, std::move(payload), objectPath, ec1,
853 retPath);
854 },
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700855 serviceName, objectPath, "xyz.openbmc_project.Software.Update",
856 "StartUpdate", sdbusplus::message::unix_fd(memfd.fd), applyTime);
857}
858
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700859inline void getSwInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
860 task::Payload payload, const MemoryFileDescriptor& memfd,
861 const std::string& applyTime, const std::string& target,
862 const boost::system::error_code& ec,
863 const dbus::utility::MapperGetSubTreeResponse& subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700864{
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700865 using SwInfoMap = std::unordered_map<
866 std::string, std::pair<sdbusplus::message::object_path, std::string>>;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700867 SwInfoMap swInfoMap;
868
869 if (ec)
870 {
871 BMCWEB_LOG_ERROR("error_code = {}", ec);
872 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
873 messages::internalError(asyncResp->res);
874 return;
875 }
876 BMCWEB_LOG_DEBUG("Found {} software version paths", subtree.size());
877
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700878 for (const auto& entry : subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700879 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700880 sdbusplus::message::object_path path(entry.first);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700881 std::string swId = path.filename();
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700882 swInfoMap.emplace(swId, make_pair(path, entry.second[0].first));
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700883 }
884
885 auto swEntry = swInfoMap.find(target);
886 if (swEntry == swInfoMap.end())
887 {
888 BMCWEB_LOG_WARNING("No valid DBus path for Target URI {}", target);
889 messages::propertyValueFormatError(asyncResp->res, target, "Targets");
890 return;
891 }
892
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700893 BMCWEB_LOG_DEBUG("Found software version path {} serviceName {}",
894 swEntry->second.first.str, swEntry->second.second);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700895
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700896 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
897 swEntry->second.first.str, swEntry->second.second);
898}
899
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400900inline void handleBMCUpdate(
901 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
902 const MemoryFileDescriptor& memfd, const std::string& applyTime,
903 const boost::system::error_code& ec,
904 const dbus::utility::MapperEndPoints& functionalSoftware)
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700905{
906 if (ec)
907 {
908 BMCWEB_LOG_ERROR("error_code = {}", ec);
909 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
910 messages::internalError(asyncResp->res);
911 return;
912 }
913 if (functionalSoftware.size() != 1)
914 {
915 BMCWEB_LOG_ERROR("Found {} functional software endpoints",
916 functionalSoftware.size());
917 messages::internalError(asyncResp->res);
918 return;
919 }
920
921 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
922 functionalSoftware[0], "xyz.openbmc_project.Software.Manager");
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700923}
924
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400925inline void processUpdateRequest(
926 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
927 task::Payload&& payload, std::string_view body,
928 const std::string& applyTime, std::vector<std::string>& targets)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700929{
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700930 MemoryFileDescriptor memfd("update-image");
931 if (memfd.fd == -1)
932 {
933 BMCWEB_LOG_ERROR("Failed to create image memfd");
934 messages::internalError(asyncResp->res);
935 return;
936 }
937 if (write(memfd.fd, body.data(), body.length()) !=
938 static_cast<ssize_t>(body.length()))
939 {
940 BMCWEB_LOG_ERROR("Failed to write to image memfd");
941 messages::internalError(asyncResp->res);
942 return;
943 }
944 if (!memfd.rewind())
945 {
946 messages::internalError(asyncResp->res);
947 return;
948 }
949
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700950 if (!targets.empty() && targets[0] == BMCWEB_REDFISH_MANAGER_URI_NAME)
951 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700952 dbus::utility::getAssociationEndPoints(
Jagpal Singh Gill89449bb2024-08-12 16:17:58 -0700953 "/xyz/openbmc_project/software/bmc/updateable",
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700954 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
955 applyTime](
956 const boost::system::error_code& ec,
957 const dbus::utility::MapperEndPoints& objectPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400958 handleBMCUpdate(asyncResp, std::move(payload), memfd, applyTime,
959 ec, objectPaths);
960 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700961 }
962 else
963 {
964 constexpr std::array<std::string_view, 1> interfaces = {
965 "xyz.openbmc_project.Software.Version"};
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700966 dbus::utility::getSubTree(
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700967 "/xyz/openbmc_project/software", 1, interfaces,
968 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700969 applyTime, targets](const boost::system::error_code& ec,
970 const dbus::utility::MapperGetSubTreeResponse&
971 subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400972 getSwInfo(asyncResp, std::move(payload), memfd, applyTime,
973 targets[0], ec, subtree);
974 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700975 }
976}
977
Patrick Williams504af5a2025-02-03 14:29:03 -0500978inline void updateMultipartContext(
979 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
980 const crow::Request& req, MultipartParser&& parser)
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700981{
982 std::optional<MultiPartUpdateParameters> multipart =
983 extractMultipartUpdateParameters(asyncResp, std::move(parser));
984 if (!multipart)
985 {
George Liu0ed80c82020-05-12 16:06:27 +0800986 return;
987 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700988 if (!multipart->applyTime)
George Liu0ed80c82020-05-12 16:06:27 +0800989 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700990 multipart->applyTime = "OnReset";
George Liu0ed80c82020-05-12 16:06:27 +0800991 }
992
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700993 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
994 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -0700995 std::string applyTimeNewVal;
996 if (!convertApplyTime(asyncResp->res, *multipart->applyTime,
997 applyTimeNewVal))
998 {
999 return;
1000 }
1001 task::Payload payload(req);
1002
1003 processUpdateRequest(asyncResp, std::move(payload),
1004 multipart->uploadData, applyTimeNewVal,
1005 multipart->targets);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001006 }
1007 else
1008 {
1009 setApplyTime(asyncResp, *multipart->applyTime);
George Liu0ed80c82020-05-12 16:06:27 +08001010
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001011 // Setup callback for when new software detected
1012 monitorForSoftwareAvailable(asyncResp, req,
1013 "/redfish/v1/UpdateService");
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001014
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001015 uploadImageFile(asyncResp->res, multipart->uploadData);
1016 }
George Liu0ed80c82020-05-12 16:06:27 +08001017}
1018
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001019inline void doHTTPUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1020 const crow::Request& req)
1021{
1022 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
1023 {
1024 task::Payload payload(req);
1025 // HTTP push only supports BMC updates (with ApplyTime as immediate) for
1026 // backwards compatibility. Specific component updates will be handled
1027 // through Multipart form HTTP push.
1028 std::vector<std::string> targets;
1029 targets.emplace_back(BMCWEB_REDFISH_MANAGER_URI_NAME);
1030
1031 processUpdateRequest(
1032 asyncResp, std::move(payload), req.body(),
1033 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate",
1034 targets);
1035 }
1036 else
1037 {
1038 // Setup callback for when new software detected
1039 monitorForSoftwareAvailable(asyncResp, req,
1040 "/redfish/v1/UpdateService");
1041
1042 uploadImageFile(asyncResp->res, req.body());
1043 }
1044}
1045
Patrick Williams504af5a2025-02-03 14:29:03 -05001046inline void handleUpdateServicePost(
1047 App& app, const crow::Request& req,
1048 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousc2051d12022-05-11 12:21:55 -07001049{
Carson Labrado3ba00072022-06-06 19:40:56 +00001050 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -07001051 {
1052 return;
1053 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001054 std::string_view contentType = req.getHeaderValue("Content-Type");
Ed Tanousc2051d12022-05-11 12:21:55 -07001055
Ed Tanous62598e32023-07-17 17:06:25 -07001056 BMCWEB_LOG_DEBUG("doPost: contentType={}", contentType);
Ed Tanousc2051d12022-05-11 12:21:55 -07001057
rajeeranjan0c814aa2025-03-25 13:31:49 +05301058 // Make sure that content type is application/octet-stream
Ed Tanous18f8f602023-07-18 10:07:23 -07001059 if (bmcweb::asciiIEquals(contentType, "application/octet-stream"))
George Liu0ed80c82020-05-12 16:06:27 +08001060 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001061 doHTTPUpdate(asyncResp, req);
George Liu0ed80c82020-05-12 16:06:27 +08001062 }
rajeeranjan0c814aa2025-03-25 13:31:49 +05301063 else
1064 {
1065 BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
1066 asyncResp->res.result(boost::beast::http::status::bad_request);
1067 }
1068}
1069
1070inline void handleUpdateServiceMultipartUpdatePost(
1071 App& app, const crow::Request& req,
1072 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1073{
1074 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1075 {
1076 return;
1077 }
1078
1079 std::string_view contentType = req.getHeaderValue("Content-Type");
1080 // Make sure that content type is multipart/form-data
1081 if (contentType.starts_with("multipart/form-data"))
George Liu0ed80c82020-05-12 16:06:27 +08001082 {
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001083 MultipartParser parser;
1084
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001085 ParserError ec = parser.parse(req);
1086 if (ec != ParserError::PARSER_SUCCESS)
1087 {
1088 // handle error
Ed Tanous62598e32023-07-17 17:06:25 -07001089 BMCWEB_LOG_ERROR("MIME parse failed, ec : {}",
1090 static_cast<int>(ec));
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001091 messages::internalError(asyncResp->res);
1092 return;
1093 }
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001094
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001095 updateMultipartContext(asyncResp, req, std::move(parser));
George Liu0ed80c82020-05-12 16:06:27 +08001096 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001097 else
1098 {
Ed Tanous62598e32023-07-17 17:06:25 -07001099 BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001100 asyncResp->res.result(boost::beast::http::status::bad_request);
1101 }
Ed Tanousc2051d12022-05-11 12:21:55 -07001102}
1103
Patrick Williams504af5a2025-02-03 14:29:03 -05001104inline void handleUpdateServiceGet(
1105 App& app, const crow::Request& req,
1106 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001107{
Ed Tanousf5139332024-04-03 13:25:04 -07001108 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1109 {
1110 return;
1111 }
1112 asyncResp->res.jsonValue["@odata.type"] =
1113 "#UpdateService.v1_11_1.UpdateService";
1114 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
1115 asyncResp->res.jsonValue["Id"] = "UpdateService";
1116 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
1117 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001118
Ed Tanousf5139332024-04-03 13:25:04 -07001119 asyncResp->res.jsonValue["HttpPushUri"] =
1120 "/redfish/v1/UpdateService/update";
1121 asyncResp->res.jsonValue["MultipartHttpPushUri"] =
rajeeranjan0c814aa2025-03-25 13:31:49 +05301122 "/redfish/v1/UpdateService/update-multipart";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001123
Ed Tanousf5139332024-04-03 13:25:04 -07001124 // UpdateService cannot be disabled
1125 asyncResp->res.jsonValue["ServiceEnabled"] = true;
1126 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
1127 "/redfish/v1/UpdateService/FirmwareInventory";
1128 // Get the MaxImageSizeBytes
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001129 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
1130 BMCWEB_HTTP_BODY_LIMIT * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +05301131
Ed Tanous6a371402024-12-03 14:01:25 -08001132 if constexpr (BMCWEB_REDFISH_ALLOW_SIMPLE_UPDATE)
Ed Tanous25b54db2024-04-17 15:40:31 -07001133 {
Ed Tanous6a371402024-12-03 14:01:25 -08001134 // Update Actions object.
1135 nlohmann::json& updateSvcSimpleUpdate =
1136 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
1137 updateSvcSimpleUpdate["target"] =
1138 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
Ed Tanous757178a2024-04-03 14:32:38 -07001139
Ed Tanous6a371402024-12-03 14:01:25 -08001140 nlohmann::json::array_t allowed;
1141 allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
1142 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
1143 std::move(allowed);
1144 }
Ed Tanous757178a2024-04-03 14:32:38 -07001145
Ed Tanous539d8c62024-06-19 14:38:27 -07001146 asyncResp->res
1147 .jsonValue["HttpPushUriOptions"]["HttpPushUriApplyTime"]["ApplyTime"] =
1148 update_service::ApplyTime::Immediate;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001149}
Ed Tanousf5139332024-04-03 13:25:04 -07001150
1151inline void handleUpdateServiceFirmwareInventoryCollectionGet(
1152 App& app, const crow::Request& req,
1153 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1154{
1155 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1156 {
1157 return;
1158 }
1159 asyncResp->res.jsonValue["@odata.type"] =
1160 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
1161 asyncResp->res.jsonValue["@odata.id"] =
1162 "/redfish/v1/UpdateService/FirmwareInventory";
1163 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
1164 const std::array<const std::string_view, 1> iface = {
1165 "xyz.openbmc_project.Software.Version"};
1166
1167 redfish::collection_util::getCollectionMembers(
1168 asyncResp,
1169 boost::urls::url("/redfish/v1/UpdateService/FirmwareInventory"), iface,
1170 "/xyz/openbmc_project/software");
1171}
1172
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001173/* Fill related item links (i.e. bmc, bios) in for inventory */
Ed Tanousf5139332024-04-03 13:25:04 -07001174inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1175 const std::string& purpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001176{
Willy Tueee00132022-06-14 14:53:17 -07001177 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001178 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001179 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001180 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001181 item["@odata.id"] = boost::urls::format(
1182 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001183 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001184 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1185 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001186 }
Willy Tueee00132022-06-14 14:53:17 -07001187 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001188 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001189 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001190 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001191 item["@odata.id"] = std::format("/redfish/v1/Systems/{}/Bios",
1192 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001193 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001194 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1195 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001196 }
1197 else
1198 {
Carson Labradobf2dded2023-08-10 00:37:06 +00001199 BMCWEB_LOG_DEBUG("Unknown software purpose {}", purpose);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001200 }
1201}
1202
Patrick Williams504af5a2025-02-03 14:29:03 -05001203inline void getSoftwareVersion(
1204 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1205 const std::string& service, const std::string& path,
1206 const std::string& swId)
Willy Tuaf246602022-06-14 15:51:53 -07001207{
Ed Tanousdeae6a72024-11-11 21:58:57 -08001208 dbus::utility::getAllProperties(
1209 service, path, "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -07001210 [asyncResp,
Ed Tanous8b242752023-06-27 17:17:13 -07001211 swId](const boost::system::error_code& ec,
Willy Tuaf246602022-06-14 15:51:53 -07001212 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001213 if (ec)
1214 {
1215 messages::internalError(asyncResp->res);
1216 return;
1217 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001218
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001219 const std::string* swInvPurpose = nullptr;
1220 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001221
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001222 const bool success = sdbusplus::unpackPropertiesNoThrow(
1223 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
1224 swInvPurpose, "Version", version);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001225
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001226 if (!success)
1227 {
1228 messages::internalError(asyncResp->res);
1229 return;
1230 }
Willy Tuaf246602022-06-14 15:51:53 -07001231
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001232 if (swInvPurpose == nullptr)
1233 {
1234 BMCWEB_LOG_DEBUG("Can't find property \"Purpose\"!");
1235 messages::internalError(asyncResp->res);
1236 return;
1237 }
Willy Tuaf246602022-06-14 15:51:53 -07001238
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001239 BMCWEB_LOG_DEBUG("swInvPurpose = {}", *swInvPurpose);
Willy Tuaf246602022-06-14 15:51:53 -07001240
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001241 if (version == nullptr)
1242 {
1243 BMCWEB_LOG_DEBUG("Can't find property \"Version\"!");
Willy Tuaf246602022-06-14 15:51:53 -07001244
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001245 messages::internalError(asyncResp->res);
Willy Tuaf246602022-06-14 15:51:53 -07001246
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001247 return;
1248 }
1249 asyncResp->res.jsonValue["Version"] = *version;
1250 asyncResp->res.jsonValue["Id"] = swId;
Willy Tuaf246602022-06-14 15:51:53 -07001251
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001252 // swInvPurpose is of format:
1253 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
1254 // Translate this to "ABC image"
1255 size_t endDesc = swInvPurpose->rfind('.');
1256 if (endDesc == std::string::npos)
1257 {
1258 messages::internalError(asyncResp->res);
1259 return;
1260 }
1261 endDesc++;
1262 if (endDesc >= swInvPurpose->size())
1263 {
1264 messages::internalError(asyncResp->res);
1265 return;
1266 }
Willy Tuaf246602022-06-14 15:51:53 -07001267
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001268 std::string formatDesc = swInvPurpose->substr(endDesc);
1269 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
1270 getRelatedItems(asyncResp, *swInvPurpose);
1271 });
Willy Tuaf246602022-06-14 15:51:53 -07001272}
1273
Ed Tanousf5139332024-04-03 13:25:04 -07001274inline void handleUpdateServiceFirmwareInventoryGet(
1275 App& app, const crow::Request& req,
1276 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1277 const std::string& param)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001278{
Ed Tanousf5139332024-04-03 13:25:04 -07001279 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1280 {
1281 return;
1282 }
1283 std::shared_ptr<std::string> swId = std::make_shared<std::string>(param);
1284
Ed Tanousf5139332024-04-03 13:25:04 -07001285 constexpr std::array<std::string_view, 1> interfaces = {
1286 "xyz.openbmc_project.Software.Version"};
1287 dbus::utility::getSubTree(
Abiola Asojof90af522025-03-18 16:29:31 +00001288 "/xyz/openbmc_project/software/", 0, interfaces,
Ed Tanousf5139332024-04-03 13:25:04 -07001289 [asyncResp,
1290 swId](const boost::system::error_code& ec,
1291 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001292 BMCWEB_LOG_DEBUG("doGet callback...");
1293 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001294 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001295 messages::internalError(asyncResp->res);
1296 return;
Ed Tanous45ca1b82022-03-25 13:07:27 -07001297 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001298
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001299 // Ensure we find our input swId, otherwise return an error
1300 bool found = false;
1301 for (const std::pair<std::string,
1302 std::vector<std::pair<
1303 std::string, std::vector<std::string>>>>&
1304 obj : subtree)
Ed Tanous002d39b2022-05-31 08:59:27 -07001305 {
Abiola Asojof90af522025-03-18 16:29:31 +00001306 sdbusplus::message::object_path path(obj.first);
1307 std::string id = path.filename();
1308 if (id.empty())
1309 {
1310 BMCWEB_LOG_DEBUG("Failed to find software id in {}",
1311 obj.first);
1312 continue;
1313 }
1314 if (id != *swId)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001315 {
1316 continue;
1317 }
1318
1319 if (obj.second.empty())
1320 {
1321 continue;
1322 }
1323
1324 found = true;
1325 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
1326 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
1327 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -07001328 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001329 if (!found)
1330 {
1331 BMCWEB_LOG_WARNING("Input swID {} not found!", *swId);
1332 messages::resourceMissingAtURI(
1333 asyncResp->res,
1334 boost::urls::format(
1335 "/redfish/v1/UpdateService/FirmwareInventory/{}",
1336 *swId));
1337 return;
1338 }
Abiola Asojof90af522025-03-18 16:29:31 +00001339 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1340 "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001341 asyncResp->res.jsonValue["@odata.type"] =
1342 "#SoftwareInventory.v1_1_0.SoftwareInventory";
1343 asyncResp->res.jsonValue["Name"] = "Software Inventory";
1344 asyncResp->res.jsonValue["Status"]["HealthRollup"] =
1345 resource::Health::OK;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001346
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001347 asyncResp->res.jsonValue["Updateable"] = false;
1348 sw_util::getSwUpdatableStatus(asyncResp, swId);
1349 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001350}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001351
Ed Tanousf5139332024-04-03 13:25:04 -07001352inline void requestRoutesUpdateService(App& app)
1353{
Ed Tanous6a371402024-12-03 14:01:25 -08001354 if constexpr (BMCWEB_REDFISH_ALLOW_SIMPLE_UPDATE)
1355 {
1356 BMCWEB_ROUTE(
1357 app,
1358 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
1359 .privileges(redfish::privileges::postUpdateService)
1360 .methods(boost::beast::http::verb::post)(std::bind_front(
1361 handleUpdateServiceSimpleUpdateAction, std::ref(app)));
1362 }
Ed Tanousf5139332024-04-03 13:25:04 -07001363 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
1364 .privileges(redfish::privileges::getSoftwareInventory)
1365 .methods(boost::beast::http::verb::get)(std::bind_front(
1366 handleUpdateServiceFirmwareInventoryGet, std::ref(app)));
1367
1368 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1369 .privileges(redfish::privileges::getUpdateService)
1370 .methods(boost::beast::http::verb::get)(
1371 std::bind_front(handleUpdateServiceGet, std::ref(app)));
1372
Ed Tanousf5139332024-04-03 13:25:04 -07001373 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
1374 .privileges(redfish::privileges::postUpdateService)
1375 .methods(boost::beast::http::verb::post)(
1376 std::bind_front(handleUpdateServicePost, std::ref(app)));
1377
rajeeranjan0c814aa2025-03-25 13:31:49 +05301378 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update-multipart/")
1379 .privileges(redfish::privileges::postUpdateService)
1380 .methods(boost::beast::http::verb::post)(std::bind_front(
1381 handleUpdateServiceMultipartUpdatePost, std::ref(app)));
1382
Ed Tanousf5139332024-04-03 13:25:04 -07001383 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1384 .privileges(redfish::privileges::getSoftwareInventoryCollection)
1385 .methods(boost::beast::http::verb::get)(std::bind_front(
1386 handleUpdateServiceFirmwareInventoryCollectionGet, std::ref(app)));
1387}
1388
Ed Tanous1abe55e2018-09-05 08:30:59 -07001389} // namespace redfish