blob: a82630b7cc97b5111031515dd32c03f5bd6d6c52 [file] [log] [blame]
Jennifer Lee729dae72018-04-24 15:59:34 -07001/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2018 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
Jennifer Lee729dae72018-04-24 15:59:34 -070015*/
16#pragma once
17
Tejas Patild61e5192021-06-04 15:49:35 +053018#include "bmcweb_config.h"
19
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "app.hpp"
21#include "dbus_utility.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070022#include "error_messages.hpp"
Ed Tanous757178a2024-04-03 14:32:38 -070023#include "generated/enums/update_service.hpp"
George Liu0ed80c82020-05-12 16:06:27 +080024#include "multipart_parser.hpp"
Ed Tanous2c6ffdb2023-06-28 11:28:38 -070025#include "ossl_random.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "query.hpp"
27#include "registries/privilege_registry.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080028#include "task.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070029#include "task_messages.hpp"
John Edward Broadbent08d81ad2022-05-17 20:00:23 -070030#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080031#include "utils/dbus_utils.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070032#include "utils/json_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080033#include "utils/sw_utils.hpp"
34
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070035#include <sys/mman.h>
36
George Liue99073f2022-12-09 11:06:16 +080037#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070038#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070039#include <sdbusplus/asio/property.hpp>
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080040#include <sdbusplus/bus/match.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020041#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042
George Liu2b731192023-01-11 16:27:13 +080043#include <array>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070044#include <cstddef>
George Liu0ed80c82020-05-12 16:06:27 +080045#include <filesystem>
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -070046#include <functional>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070047#include <iterator>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070048#include <memory>
Ed Tanous7cb59f62022-05-05 11:48:31 -070049#include <optional>
50#include <string>
George Liu2b731192023-01-11 16:27:13 +080051#include <string_view>
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070052#include <unordered_map>
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -070053#include <vector>
George Liu2b731192023-01-11 16:27:13 +080054
Ed Tanous1abe55e2018-09-05 08:30:59 -070055namespace redfish
56{
Ed Tanous27826b52018-10-29 11:40:58 -070057
Andrew Geissler0e7de462019-03-04 19:11:54 -060058// Match signals added on software path
Ed Tanouscf9e4172022-12-21 09:30:16 -080059// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050060static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
Ed Tanouscf9e4172022-12-21 09:30:16 -080061// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Patrick Williams59d494e2022-07-22 19:26:55 -050062static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
Andrew Geissler0e7de462019-03-04 19:11:54 -060063// Only allow one update at a time
Ed Tanouscf9e4172022-12-21 09:30:16 -080064// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Andrew Geissler0e7de462019-03-04 19:11:54 -060065static bool fwUpdateInProgress = false;
Andrew Geissler86adcd62019-04-18 10:58:05 -050066// Timer for software available
Ed Tanouscf9e4172022-12-21 09:30:16 -080067// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous271584a2019-07-09 16:24:22 -070068static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
Andrew Geissler86adcd62019-04-18 10:58:05 -050069
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -070070struct MemoryFileDescriptor
71{
72 int fd = -1;
73
74 explicit MemoryFileDescriptor(const std::string& filename) :
75 fd(memfd_create(filename.c_str(), 0))
76 {}
77
78 MemoryFileDescriptor(const MemoryFileDescriptor&) = default;
79 MemoryFileDescriptor(MemoryFileDescriptor&& other) noexcept : fd(other.fd)
80 {
81 other.fd = -1;
82 }
83 MemoryFileDescriptor& operator=(const MemoryFileDescriptor&) = delete;
84 MemoryFileDescriptor& operator=(MemoryFileDescriptor&&) = default;
85
86 ~MemoryFileDescriptor()
87 {
88 if (fd != -1)
89 {
90 close(fd);
91 }
92 }
93
94 bool rewind() const
95 {
96 if (lseek(fd, 0, SEEK_SET) == -1)
97 {
98 BMCWEB_LOG_ERROR("Failed to seek to beginning of image memfd");
99 return false;
100 }
101 return true;
102 }
103};
104
Ed Tanousdf254f22024-04-01 13:25:46 -0700105inline void cleanUp()
Andrew Geissler86adcd62019-04-18 10:58:05 -0500106{
107 fwUpdateInProgress = false;
108 fwUpdateMatcher = nullptr;
James Feist4cde5d92020-06-11 10:39:55 -0700109 fwUpdateErrorMatcher = nullptr;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500110}
Ed Tanousdf254f22024-04-01 13:25:46 -0700111
112inline void activateImage(const std::string& objPath,
113 const std::string& service)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500114{
Ed Tanous62598e32023-07-17 17:06:25 -0700115 BMCWEB_LOG_DEBUG("Activate image for {} {}", objPath, service);
George Liu9ae226f2023-06-21 17:56:46 +0800116 sdbusplus::asio::setProperty(
117 *crow::connections::systemBus, service, objPath,
118 "xyz.openbmc_project.Software.Activation", "RequestedActivation",
119 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
Ed Tanous8b242752023-06-27 17:17:13 -0700120 [](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400121 if (ec)
122 {
123 BMCWEB_LOG_DEBUG("error_code = {}", ec);
124 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
125 }
126 });
Andrew Geissler86adcd62019-04-18 10:58:05 -0500127}
Andrew Geissler0554c982019-04-23 14:40:12 -0500128
Jagpal Singh Gillc71b6c92024-04-29 16:50:53 -0700129inline bool handleCreateTask(const boost::system::error_code& ec2,
130 sdbusplus::message_t& msg,
131 const std::shared_ptr<task::TaskData>& taskData)
132{
133 if (ec2)
134 {
135 return task::completed;
136 }
137
138 std::string iface;
139 dbus::utility::DBusPropertiesMap values;
140
141 std::string index = std::to_string(taskData->index);
142 msg.read(iface, values);
143
144 if (iface == "xyz.openbmc_project.Software.Activation")
145 {
146 const std::string* state = nullptr;
147 for (const auto& property : values)
148 {
149 if (property.first == "Activation")
150 {
151 state = std::get_if<std::string>(&property.second);
152 if (state == nullptr)
153 {
154 taskData->messages.emplace_back(messages::internalError());
155 return task::completed;
156 }
157 }
158 }
159
160 if (state == nullptr)
161 {
162 return !task::completed;
163 }
164
165 if (state->ends_with("Invalid") || state->ends_with("Failed"))
166 {
167 taskData->state = "Exception";
168 taskData->status = "Warning";
169 taskData->messages.emplace_back(messages::taskAborted(index));
170 return task::completed;
171 }
172
173 if (state->ends_with("Staged"))
174 {
175 taskData->state = "Stopping";
176 taskData->messages.emplace_back(messages::taskPaused(index));
177
178 // its staged, set a long timer to
179 // allow them time to complete the
180 // update (probably cycle the
181 // system) if this expires then
182 // task will be canceled
183 taskData->extendTimer(std::chrono::hours(5));
184 return !task::completed;
185 }
186
187 if (state->ends_with("Active"))
188 {
189 taskData->messages.emplace_back(messages::taskCompletedOK(index));
190 taskData->state = "Completed";
191 return task::completed;
192 }
193 }
194 else if (iface == "xyz.openbmc_project.Software.ActivationProgress")
195 {
196 const uint8_t* progress = nullptr;
197 for (const auto& property : values)
198 {
199 if (property.first == "Progress")
200 {
201 progress = std::get_if<uint8_t>(&property.second);
202 if (progress == nullptr)
203 {
204 taskData->messages.emplace_back(messages::internalError());
205 return task::completed;
206 }
207 }
208 }
209
210 if (progress == nullptr)
211 {
212 return !task::completed;
213 }
214 taskData->percentComplete = *progress;
215 taskData->messages.emplace_back(
216 messages::taskProgressChanged(index, *progress));
217
218 // if we're getting status updates it's
219 // still alive, update timer
220 taskData->extendTimer(std::chrono::minutes(5));
221 }
222
223 // as firmware update often results in a
224 // reboot, the task may never "complete"
225 // unless it is an error
226
227 return !task::completed;
228}
229
230inline void createTask(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
231 task::Payload&& payload,
232 const sdbusplus::message::object_path& objPath)
233{
234 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
235 std::bind_front(handleCreateTask),
236 "type='signal',interface='org.freedesktop.DBus.Properties',"
237 "member='PropertiesChanged',path='" +
238 objPath.str + "'");
239 task->startTimer(std::chrono::minutes(5));
240 task->populateResp(asyncResp->res);
241 task->payload.emplace(std::move(payload));
242}
243
Andrew Geissler0554c982019-04-23 14:40:12 -0500244// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
245// then no asyncResp updates will occur
Ed Tanous4ff0f1f2024-09-04 17:27:37 -0700246inline void
zhanghch058d1b46d2021-04-01 11:18:24 +0800247 softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Patrick Williams59d494e2022-07-22 19:26:55 -0500248 sdbusplus::message_t& m, task::Payload&& payload)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500249{
Michael Shen80f79a42023-08-24 13:41:53 +0000250 dbus::utility::DBusInterfacesMap interfacesProperties;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500251
252 sdbusplus::message::object_path objPath;
253
254 m.read(objPath, interfacesProperties);
255
Ed Tanous62598e32023-07-17 17:06:25 -0700256 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
Ed Tanouse3eb3d62022-12-21 11:56:07 -0800257 for (const auto& interface : interfacesProperties)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500258 {
Ed Tanous62598e32023-07-17 17:06:25 -0700259 BMCWEB_LOG_DEBUG("interface = {}", interface.first);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500260
261 if (interface.first == "xyz.openbmc_project.Software.Activation")
262 {
Andrew Geissler86adcd62019-04-18 10:58:05 -0500263 // Retrieve service and activate
George Liu2b731192023-01-11 16:27:13 +0800264 constexpr std::array<std::string_view, 1> interfaces = {
265 "xyz.openbmc_project.Software.Activation"};
266 dbus::utility::getDbusObject(
267 objPath.str, interfaces,
Ed Tanousa3e65892021-09-16 14:13:20 -0700268 [objPath, asyncResp, payload(std::move(payload))](
Ed Tanous8b242752023-06-27 17:17:13 -0700269 const boost::system::error_code& ec,
Ed Tanousa3e65892021-09-16 14:13:20 -0700270 const std::vector<
271 std::pair<std::string, std::vector<std::string>>>&
272 objInfo) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400273 if (ec)
Andrew Geissler0554c982019-04-23 14:40:12 -0500274 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400275 BMCWEB_LOG_DEBUG("error_code = {}", ec);
276 BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
277 if (asyncResp)
278 {
279 messages::internalError(asyncResp->res);
280 }
281 cleanUp();
282 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700283 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400284 // Ensure we only got one service back
285 if (objInfo.size() != 1)
Ed Tanous002d39b2022-05-31 08:59:27 -0700286 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400287 BMCWEB_LOG_ERROR("Invalid Object Size {}",
288 objInfo.size());
289 if (asyncResp)
290 {
291 messages::internalError(asyncResp->res);
292 }
293 cleanUp();
294 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700295 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400296 // cancel timer only when
297 // xyz.openbmc_project.Software.Activation interface
298 // is added
299 fwAvailableTimer = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700300
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400301 activateImage(objPath.str, objInfo[0].first);
302 if (asyncResp)
303 {
304 createTask(asyncResp, std::move(payload), objPath);
305 }
306 fwUpdateInProgress = false;
307 });
Patrick Williams62bafc02022-09-08 17:35:35 -0500308
309 break;
Andrew Geissler86adcd62019-04-18 10:58:05 -0500310 }
311 }
312}
313
Myung Bae8549b952023-08-16 15:18:19 -0400314inline void afterAvailbleTimerAsyncWait(
315 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
316 const boost::system::error_code& ec)
317{
318 cleanUp();
319 if (ec == boost::asio::error::operation_aborted)
320 {
321 // expected, we were canceled before the timer completed.
322 return;
323 }
324 BMCWEB_LOG_ERROR("Timed out waiting for firmware object being created");
325 BMCWEB_LOG_ERROR("FW image may has already been uploaded to server");
326 if (ec)
327 {
328 BMCWEB_LOG_ERROR("Async_wait failed{}", ec);
329 return;
330 }
331 if (asyncResp)
332 {
333 redfish::messages::internalError(asyncResp->res);
334 }
335}
336
337inline void
338 handleUpdateErrorType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous48fb20b2024-11-17 11:51:13 -0800339 const std::string& url, const std::string& type)
Myung Bae8549b952023-08-16 15:18:19 -0400340{
Ed Tanousc87294a2024-11-16 22:17:12 -0800341 // NOLINTBEGIN(bugprone-branch-clone)
Myung Bae8549b952023-08-16 15:18:19 -0400342 if (type == "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
343 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800344 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400345 }
346 else if (type ==
347 "xyz.openbmc_project.Software.Image.Error.ManifestFileFailure")
348 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800349 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400350 }
351 else if (type == "xyz.openbmc_project.Software.Image.Error.ImageFailure")
352 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800353 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400354 }
355 else if (type == "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
356 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800357 messages::resourceAlreadyExists(asyncResp->res, "UpdateService",
358 "Version", "uploaded version");
Myung Bae8549b952023-08-16 15:18:19 -0400359 }
360 else if (type == "xyz.openbmc_project.Software.Image.Error.BusyFailure")
361 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800362 messages::serviceTemporarilyUnavailable(asyncResp->res, url);
Myung Bae8549b952023-08-16 15:18:19 -0400363 }
Myung Bae4034a652023-08-17 08:47:35 -0400364 else if (type == "xyz.openbmc_project.Software.Version.Error.Incompatible")
Myung Bae8549b952023-08-16 15:18:19 -0400365 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800366 messages::internalError(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400367 }
368 else if (type ==
369 "xyz.openbmc_project.Software.Version.Error.ExpiredAccessKey")
370 {
Ed Tanousc87294a2024-11-16 22:17:12 -0800371 messages::internalError(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400372 }
373 else if (type ==
374 "xyz.openbmc_project.Software.Version.Error.InvalidSignature")
375 {
Ed Tanous48fb20b2024-11-17 11:51:13 -0800376 messages::missingOrMalformedPart(asyncResp->res);
Myung Bae4034a652023-08-17 08:47:35 -0400377 }
378 else if (type ==
379 "xyz.openbmc_project.Software.Image.Error.InternalFailure" ||
380 type == "xyz.openbmc_project.Software.Version.Error.HostFile")
381 {
382 BMCWEB_LOG_ERROR("Software Image Error type={}", type);
Ed Tanous48fb20b2024-11-17 11:51:13 -0800383 messages::internalError(asyncResp->res);
Myung Bae8549b952023-08-16 15:18:19 -0400384 }
Myung Bae4034a652023-08-17 08:47:35 -0400385 else
386 {
387 // Unrelated error types. Ignored
388 BMCWEB_LOG_INFO("Non-Software-related Error type={}. Ignored", type);
389 return;
390 }
Ed Tanousc87294a2024-11-16 22:17:12 -0800391 // NOLINTEND(bugprone-branch-clone)
Myung Bae4034a652023-08-17 08:47:35 -0400392 // Clear the timer
393 fwAvailableTimer = nullptr;
Myung Bae8549b952023-08-16 15:18:19 -0400394}
395
396inline void
397 afterUpdateErrorMatcher(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
398 const std::string& url, sdbusplus::message_t& m)
399{
Michael Shen80f79a42023-08-24 13:41:53 +0000400 dbus::utility::DBusInterfacesMap interfacesProperties;
Myung Bae8549b952023-08-16 15:18:19 -0400401 sdbusplus::message::object_path objPath;
402 m.read(objPath, interfacesProperties);
403 BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
404 for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
405 interface : interfacesProperties)
406 {
407 if (interface.first == "xyz.openbmc_project.Logging.Entry")
408 {
409 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
410 value : interface.second)
411 {
412 if (value.first != "Message")
413 {
414 continue;
415 }
416 const std::string* type =
417 std::get_if<std::string>(&value.second);
418 if (type == nullptr)
419 {
420 // if this was our message, timeout will cover it
421 return;
422 }
Myung Bae8549b952023-08-16 15:18:19 -0400423 handleUpdateErrorType(asyncResp, url, *type);
424 }
425 }
426 }
427}
428
Andrew Geissler0554c982019-04-23 14:40:12 -0500429// Note that asyncResp can be either a valid pointer or nullptr. If nullptr
430// then no asyncResp updates will occur
Ed Tanousf5139332024-04-03 13:25:04 -0700431inline void monitorForSoftwareAvailable(
zhanghch058d1b46d2021-04-01 11:18:24 +0800432 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
433 const crow::Request& req, const std::string& url,
Gunnar Mills5d138942022-09-07 10:26:21 -0500434 int timeoutTimeSeconds = 25)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500435{
436 // Only allow one FW update at a time
Ed Tanouse05aec52022-01-25 10:28:56 -0800437 if (fwUpdateInProgress)
Andrew Geissler86adcd62019-04-18 10:58:05 -0500438 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500439 if (asyncResp)
440 {
Andrew Geissler0554c982019-04-23 14:40:12 -0500441 messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
442 }
Andrew Geissler86adcd62019-04-18 10:58:05 -0500443 return;
444 }
445
Ed Tanous8e8245d2024-04-11 22:21:38 -0700446 if (req.ioService == nullptr)
447 {
448 messages::internalError(asyncResp->res);
449 return;
450 }
451
Andrew Geissler0554c982019-04-23 14:40:12 -0500452 fwAvailableTimer =
Ed Tanous271584a2019-07-09 16:24:22 -0700453 std::make_unique<boost::asio::steady_timer>(*req.ioService);
Andrew Geissler86adcd62019-04-18 10:58:05 -0500454
Ed Tanous271584a2019-07-09 16:24:22 -0700455 fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500456
457 fwAvailableTimer->async_wait(
Myung Bae8549b952023-08-16 15:18:19 -0400458 std::bind_front(afterAvailbleTimerAsyncWait, asyncResp));
459
Ed Tanousa3e65892021-09-16 14:13:20 -0700460 task::Payload payload(req);
Patrick Williams59d494e2022-07-22 19:26:55 -0500461 auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
Ed Tanous62598e32023-07-17 17:06:25 -0700462 BMCWEB_LOG_DEBUG("Match fired");
Ed Tanousa3e65892021-09-16 14:13:20 -0700463 softwareInterfaceAdded(asyncResp, m, std::move(payload));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500464 };
465
466 fwUpdateInProgress = true;
467
Patrick Williams59d494e2022-07-22 19:26:55 -0500468 fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
Andrew Geissler86adcd62019-04-18 10:58:05 -0500469 *crow::connections::systemBus,
470 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
471 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
472 callback);
James Feist4cde5d92020-06-11 10:39:55 -0700473
Patrick Williams59d494e2022-07-22 19:26:55 -0500474 fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
James Feist4cde5d92020-06-11 10:39:55 -0700475 *crow::connections::systemBus,
Brian Mae1cc4822021-12-01 17:05:54 +0800476 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
477 "member='InterfacesAdded',"
478 "path='/xyz/openbmc_project/logging'",
Myung Bae8549b952023-08-16 15:18:19 -0400479 std::bind_front(afterUpdateErrorMatcher, asyncResp, url));
Andrew Geissler86adcd62019-04-18 10:58:05 -0500480}
Jennifer Lee729dae72018-04-24 15:59:34 -0700481
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400482inline std::optional<boost::urls::url> parseSimpleUpdateUrl(
483 std::string imageURI, std::optional<std::string> transferProtocol,
484 crow::Response& res)
Ed Tanousf86bcc82023-08-25 09:34:07 -0700485{
486 if (imageURI.find("://") == std::string::npos)
487 {
488 if (imageURI.starts_with("/"))
489 {
490 messages::actionParameterValueTypeError(
491 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
492 return std::nullopt;
493 }
494 if (!transferProtocol)
495 {
496 messages::actionParameterValueTypeError(
497 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
498 return std::nullopt;
499 }
Ed Tanous6a371402024-12-03 14:01:25 -0800500 // OpenBMC currently only supports HTTPS
501 if (*transferProtocol == "HTTPS")
Ed Tanouse5cf7772024-04-03 13:45:31 -0700502 {
503 imageURI = "https://" + imageURI;
504 }
Ed Tanous757178a2024-04-03 14:32:38 -0700505 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700506 {
507 messages::actionParameterNotSupported(res, "TransferProtocol",
508 *transferProtocol);
509 BMCWEB_LOG_ERROR("Request incorrect protocol parameter: {}",
510 *transferProtocol);
511 return std::nullopt;
512 }
Ed Tanousf86bcc82023-08-25 09:34:07 -0700513 }
514
515 boost::system::result<boost::urls::url> url =
516 boost::urls::parse_absolute_uri(imageURI);
517 if (!url)
518 {
519 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
520 "UpdateService.SimpleUpdate");
521
522 return std::nullopt;
523 }
524 url->normalize();
525
Ed Tanous757178a2024-04-03 14:32:38 -0700526 if (url->scheme() == "tftp")
527 {
528 if (url->encoded_path().size() < 2)
529 {
530 messages::actionParameterNotSupported(res, "ImageURI",
531 url->buffer());
532 return std::nullopt;
533 }
534 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700535 else if (url->scheme() == "https")
536 {
537 // Empty paths default to "/"
538 if (url->encoded_path().empty())
539 {
540 url->set_encoded_path("/");
541 }
542 }
Ed Tanous757178a2024-04-03 14:32:38 -0700543 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700544 {
545 messages::actionParameterNotSupported(res, "ImageURI", imageURI);
546 return std::nullopt;
547 }
Ed Tanous757178a2024-04-03 14:32:38 -0700548
549 if (url->encoded_path().empty())
Ed Tanousf86bcc82023-08-25 09:34:07 -0700550 {
Ed Tanous757178a2024-04-03 14:32:38 -0700551 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
552 "UpdateService.SimpleUpdate");
Ed Tanousf86bcc82023-08-25 09:34:07 -0700553 return std::nullopt;
554 }
Ed Tanous757178a2024-04-03 14:32:38 -0700555
556 return *url;
Ed Tanousf86bcc82023-08-25 09:34:07 -0700557}
558
Ed Tanouse5cf7772024-04-03 13:45:31 -0700559inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
560 const boost::urls::url_view_base& url)
561{
562 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
563 url.buffer());
564}
565
Ed Tanousf5139332024-04-03 13:25:04 -0700566inline void handleUpdateServiceSimpleUpdateAction(
567 crow::App& app, const crow::Request& req,
568 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Andrew Geissler0554c982019-04-23 14:40:12 -0500569{
Ed Tanousf5139332024-04-03 13:25:04 -0700570 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
571 {
572 return;
573 }
574
575 std::optional<std::string> transferProtocol;
576 std::string imageURI;
577
578 BMCWEB_LOG_DEBUG("Enter UpdateService.SimpleUpdate doPost");
579
580 // User can pass in both TransferProtocol and ImageURI parameters or
581 // they can pass in just the ImageURI with the transfer protocol
582 // embedded within it.
583 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
584 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
585
Myung Baeafc474a2024-10-09 00:53:29 -0700586 if (!json_util::readJsonAction( //
587 req, asyncResp->res, //
588 "ImageURI", imageURI, //
589 "TransferProtocol", transferProtocol //
590 ))
Ed Tanousf5139332024-04-03 13:25:04 -0700591 {
592 BMCWEB_LOG_DEBUG("Missing TransferProtocol or ImageURI parameter");
593 return;
594 }
595
Ed Tanous757178a2024-04-03 14:32:38 -0700596 std::optional<boost::urls::url> url =
597 parseSimpleUpdateUrl(imageURI, transferProtocol, asyncResp->res);
598 if (!url)
Ed Tanousf5139332024-04-03 13:25:04 -0700599 {
600 return;
601 }
Jagpal Singh Gill4e338b22024-06-14 14:24:56 -0700602 if (url->scheme() == "https")
Ed Tanouse5cf7772024-04-03 13:45:31 -0700603 {
604 doHttpsUpdate(asyncResp, *url);
605 }
Ed Tanous757178a2024-04-03 14:32:38 -0700606 else
607 {
608 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
609 url->buffer());
610 return;
611 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700612
Ed Tanousf5139332024-04-03 13:25:04 -0700613 BMCWEB_LOG_DEBUG("Exit UpdateService.SimpleUpdate doPost");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700614}
615
George Liu0ed80c82020-05-12 16:06:27 +0800616inline void uploadImageFile(crow::Response& res, std::string_view body)
617{
Ed Tanous2c6ffdb2023-06-28 11:28:38 -0700618 std::filesystem::path filepath("/tmp/images/" + bmcweb::getRandomUUID());
619
Ed Tanous62598e32023-07-17 17:06:25 -0700620 BMCWEB_LOG_DEBUG("Writing file to {}", filepath.string());
George Liu0ed80c82020-05-12 16:06:27 +0800621 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
622 std::ofstream::trunc);
623 // set the permission of the file to 640
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400624 std::filesystem::perms permission =
625 std::filesystem::perms::owner_read | std::filesystem::perms::group_read;
George Liu0ed80c82020-05-12 16:06:27 +0800626 std::filesystem::permissions(filepath, permission);
627 out << body;
628
629 if (out.bad())
630 {
631 messages::internalError(res);
632 cleanUp();
633 }
634}
635
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700636// Convert the Request Apply Time to the D-Bus value
637inline bool convertApplyTime(crow::Response& res, const std::string& applyTime,
638 std::string& applyTimeNewVal)
639{
640 if (applyTime == "Immediate")
641 {
642 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700643 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700644 }
645 else if (applyTime == "OnReset")
646 {
647 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700648 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700649 }
650 else
651 {
652 BMCWEB_LOG_WARNING(
653 "ApplyTime value {} is not in the list of acceptable values",
654 applyTime);
655 messages::propertyValueNotInList(res, applyTime, "ApplyTime");
656 return false;
657 }
658 return true;
659}
660
George Liu0ed80c82020-05-12 16:06:27 +0800661inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
662 const std::string& applyTime)
663{
664 std::string applyTimeNewVal;
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700665 if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
George Liu0ed80c82020-05-12 16:06:27 +0800666 {
George Liu0ed80c82020-05-12 16:06:27 +0800667 return;
668 }
669
Ginu Georgee93abac2024-06-14 17:35:27 +0530670 setDbusProperty(asyncResp, "ApplyTime", "xyz.openbmc_project.Settings",
Ed Tanousd02aad32024-02-13 14:43:34 -0800671 sdbusplus::message::object_path(
672 "/xyz/openbmc_project/software/apply_time"),
673 "xyz.openbmc_project.Software.ApplyTime",
Ginu Georgee93abac2024-06-14 17:35:27 +0530674 "RequestedApplyTime", applyTimeNewVal);
George Liu0ed80c82020-05-12 16:06:27 +0800675}
676
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700677struct MultiPartUpdateParameters
George Liu0ed80c82020-05-12 16:06:27 +0800678{
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700679 std::optional<std::string> applyTime;
680 std::string uploadData;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700681 std::vector<std::string> targets;
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700682};
683
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700684inline std::optional<std::string>
685 processUrl(boost::system::result<boost::urls::url_view>& url)
686{
687 if (!url)
688 {
689 return std::nullopt;
690 }
691 if (crow::utility::readUrlSegments(*url, "redfish", "v1", "Managers",
692 BMCWEB_REDFISH_MANAGER_URI_NAME))
693 {
694 return std::make_optional(std::string(BMCWEB_REDFISH_MANAGER_URI_NAME));
695 }
696 if constexpr (!BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
697 {
698 return std::nullopt;
699 }
700 std::string firmwareId;
701 if (!crow::utility::readUrlSegments(*url, "redfish", "v1", "UpdateService",
702 "FirmwareInventory",
703 std::ref(firmwareId)))
704 {
705 return std::nullopt;
706 }
707
708 return std::make_optional(firmwareId);
709}
710
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700711inline std::optional<MultiPartUpdateParameters>
712 extractMultipartUpdateParameters(
713 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
714 MultipartParser parser)
715{
716 MultiPartUpdateParameters multiRet;
717 for (FormPart& formpart : parser.mime_fields)
George Liu0ed80c82020-05-12 16:06:27 +0800718 {
719 boost::beast::http::fields::const_iterator it =
720 formpart.fields.find("Content-Disposition");
721 if (it == formpart.fields.end())
722 {
Ed Tanous62598e32023-07-17 17:06:25 -0700723 BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700724 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800725 }
Ed Tanous62598e32023-07-17 17:06:25 -0700726 BMCWEB_LOG_INFO("Parsing value {}", it->value());
George Liu0ed80c82020-05-12 16:06:27 +0800727
728 // The construction parameters of param_list must start with `;`
729 size_t index = it->value().find(';');
730 if (index == std::string::npos)
731 {
732 continue;
733 }
734
Patrick Williams89492a12023-05-10 07:51:34 -0500735 for (const auto& param :
George Liu0ed80c82020-05-12 16:06:27 +0800736 boost::beast::http::param_list{it->value().substr(index)})
737 {
738 if (param.first != "name" || param.second.empty())
739 {
740 continue;
741 }
742
743 if (param.second == "UpdateParameters")
744 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700745 std::vector<std::string> tempTargets;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400746 nlohmann::json content =
747 nlohmann::json::parse(formpart.content, nullptr, false);
Ed Tanousac1e1242024-07-10 22:10:14 -0700748 if (content.is_discarded())
749 {
750 return std::nullopt;
751 }
Ed Tanous7cb59f62022-05-05 11:48:31 -0700752 nlohmann::json::object_t* obj =
753 content.get_ptr<nlohmann::json::object_t*>();
754 if (obj == nullptr)
755 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700756 messages::propertyValueTypeError(
757 asyncResp->res, formpart.content, "UpdateParameters");
758 return std::nullopt;
Ed Tanous7cb59f62022-05-05 11:48:31 -0700759 }
760
Myung Baeafc474a2024-10-09 00:53:29 -0700761 if (!json_util::readJsonObject( //
762 *obj, asyncResp->res, //
763 "@Redfish.OperationApplyTime", multiRet.applyTime, //
764 "Targets", tempTargets //
765 ))
George Liu0ed80c82020-05-12 16:06:27 +0800766 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700767 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800768 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700769
770 for (size_t urlIndex = 0; urlIndex < tempTargets.size();
771 urlIndex++)
George Liu0ed80c82020-05-12 16:06:27 +0800772 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700773 const std::string& target = tempTargets[urlIndex];
774 boost::system::result<boost::urls::url_view> url =
775 boost::urls::parse_origin_form(target);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700776 auto res = processUrl(url);
777 if (!res.has_value())
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700778 {
779 messages::propertyValueFormatError(
780 asyncResp->res, target,
781 std::format("Targets/{}", urlIndex));
782 return std::nullopt;
783 }
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700784 multiRet.targets.emplace_back(res.value());
George Liu0ed80c82020-05-12 16:06:27 +0800785 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700786 if (multiRet.targets.size() != 1)
George Liu0ed80c82020-05-12 16:06:27 +0800787 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700788 messages::propertyValueFormatError(
789 asyncResp->res, multiRet.targets, "Targets");
790 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800791 }
George Liu0ed80c82020-05-12 16:06:27 +0800792 }
793 else if (param.second == "UpdateFile")
794 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700795 multiRet.uploadData = std::move(formpart.content);
George Liu0ed80c82020-05-12 16:06:27 +0800796 }
797 }
798 }
799
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700800 if (multiRet.uploadData.empty())
George Liu0ed80c82020-05-12 16:06:27 +0800801 {
Ed Tanous62598e32023-07-17 17:06:25 -0700802 BMCWEB_LOG_ERROR("Upload data is NULL");
George Liu0ed80c82020-05-12 16:06:27 +0800803 messages::propertyMissing(asyncResp->res, "UpdateFile");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700804 return std::nullopt;
805 }
806 if (multiRet.targets.empty())
807 {
808 messages::propertyMissing(asyncResp->res, "Targets");
809 return std::nullopt;
810 }
811 return multiRet;
812}
813
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400814inline void handleStartUpdate(
815 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
816 const std::string& objectPath, const boost::system::error_code& ec,
817 const sdbusplus::message::object_path& retPath)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700818{
819 if (ec)
820 {
821 BMCWEB_LOG_ERROR("error_code = {}", ec);
822 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
823 messages::internalError(asyncResp->res);
824 return;
825 }
826
Jagpal Singh Gill587090c2024-08-12 00:24:16 -0700827 BMCWEB_LOG_INFO("Call to StartUpdate on {} Success, retPath = {}",
828 objectPath, retPath.str);
829 createTask(asyncResp, std::move(payload), retPath);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700830}
831
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400832inline void startUpdate(
833 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
834 const MemoryFileDescriptor& memfd, const std::string& applyTime,
835 const std::string& objectPath, const std::string& serviceName)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700836{
837 crow::connections::systemBus->async_method_call(
838 [asyncResp, payload = std::move(payload),
839 objectPath](const boost::system::error_code& ec1,
840 const sdbusplus::message::object_path& retPath) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400841 handleStartUpdate(asyncResp, std::move(payload), objectPath, ec1,
842 retPath);
843 },
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700844 serviceName, objectPath, "xyz.openbmc_project.Software.Update",
845 "StartUpdate", sdbusplus::message::unix_fd(memfd.fd), applyTime);
846}
847
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700848inline void getSwInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
849 task::Payload payload, const MemoryFileDescriptor& memfd,
850 const std::string& applyTime, const std::string& target,
851 const boost::system::error_code& ec,
852 const dbus::utility::MapperGetSubTreeResponse& subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700853{
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700854 using SwInfoMap = std::unordered_map<
855 std::string, std::pair<sdbusplus::message::object_path, std::string>>;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700856 SwInfoMap swInfoMap;
857
858 if (ec)
859 {
860 BMCWEB_LOG_ERROR("error_code = {}", ec);
861 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
862 messages::internalError(asyncResp->res);
863 return;
864 }
865 BMCWEB_LOG_DEBUG("Found {} software version paths", subtree.size());
866
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700867 for (const auto& entry : subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700868 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700869 sdbusplus::message::object_path path(entry.first);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700870 std::string swId = path.filename();
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700871 swInfoMap.emplace(swId, make_pair(path, entry.second[0].first));
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700872 }
873
874 auto swEntry = swInfoMap.find(target);
875 if (swEntry == swInfoMap.end())
876 {
877 BMCWEB_LOG_WARNING("No valid DBus path for Target URI {}", target);
878 messages::propertyValueFormatError(asyncResp->res, target, "Targets");
879 return;
880 }
881
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700882 BMCWEB_LOG_DEBUG("Found software version path {} serviceName {}",
883 swEntry->second.first.str, swEntry->second.second);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700884
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700885 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
886 swEntry->second.first.str, swEntry->second.second);
887}
888
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400889inline void handleBMCUpdate(
890 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
891 const MemoryFileDescriptor& memfd, const std::string& applyTime,
892 const boost::system::error_code& ec,
893 const dbus::utility::MapperEndPoints& functionalSoftware)
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700894{
895 if (ec)
896 {
897 BMCWEB_LOG_ERROR("error_code = {}", ec);
898 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
899 messages::internalError(asyncResp->res);
900 return;
901 }
902 if (functionalSoftware.size() != 1)
903 {
904 BMCWEB_LOG_ERROR("Found {} functional software endpoints",
905 functionalSoftware.size());
906 messages::internalError(asyncResp->res);
907 return;
908 }
909
910 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
911 functionalSoftware[0], "xyz.openbmc_project.Software.Manager");
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700912}
913
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400914inline void processUpdateRequest(
915 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
916 task::Payload&& payload, std::string_view body,
917 const std::string& applyTime, std::vector<std::string>& targets)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700918{
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700919 MemoryFileDescriptor memfd("update-image");
920 if (memfd.fd == -1)
921 {
922 BMCWEB_LOG_ERROR("Failed to create image memfd");
923 messages::internalError(asyncResp->res);
924 return;
925 }
926 if (write(memfd.fd, body.data(), body.length()) !=
927 static_cast<ssize_t>(body.length()))
928 {
929 BMCWEB_LOG_ERROR("Failed to write to image memfd");
930 messages::internalError(asyncResp->res);
931 return;
932 }
933 if (!memfd.rewind())
934 {
935 messages::internalError(asyncResp->res);
936 return;
937 }
938
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700939 if (!targets.empty() && targets[0] == BMCWEB_REDFISH_MANAGER_URI_NAME)
940 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700941 dbus::utility::getAssociationEndPoints(
Jagpal Singh Gill89449bb2024-08-12 16:17:58 -0700942 "/xyz/openbmc_project/software/bmc/updateable",
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700943 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
944 applyTime](
945 const boost::system::error_code& ec,
946 const dbus::utility::MapperEndPoints& objectPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400947 handleBMCUpdate(asyncResp, std::move(payload), memfd, applyTime,
948 ec, objectPaths);
949 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700950 }
951 else
952 {
953 constexpr std::array<std::string_view, 1> interfaces = {
954 "xyz.openbmc_project.Software.Version"};
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700955 dbus::utility::getSubTree(
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700956 "/xyz/openbmc_project/software", 1, interfaces,
957 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700958 applyTime, targets](const boost::system::error_code& ec,
959 const dbus::utility::MapperGetSubTreeResponse&
960 subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400961 getSwInfo(asyncResp, std::move(payload), memfd, applyTime,
962 targets[0], ec, subtree);
963 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700964 }
965}
966
967inline void
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700968 updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
969 const crow::Request& req, MultipartParser&& parser)
970{
971 std::optional<MultiPartUpdateParameters> multipart =
972 extractMultipartUpdateParameters(asyncResp, std::move(parser));
973 if (!multipart)
974 {
George Liu0ed80c82020-05-12 16:06:27 +0800975 return;
976 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700977 if (!multipart->applyTime)
George Liu0ed80c82020-05-12 16:06:27 +0800978 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700979 multipart->applyTime = "OnReset";
George Liu0ed80c82020-05-12 16:06:27 +0800980 }
981
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700982 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
983 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -0700984 std::string applyTimeNewVal;
985 if (!convertApplyTime(asyncResp->res, *multipart->applyTime,
986 applyTimeNewVal))
987 {
988 return;
989 }
990 task::Payload payload(req);
991
992 processUpdateRequest(asyncResp, std::move(payload),
993 multipart->uploadData, applyTimeNewVal,
994 multipart->targets);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700995 }
996 else
997 {
998 setApplyTime(asyncResp, *multipart->applyTime);
George Liu0ed80c82020-05-12 16:06:27 +0800999
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001000 // Setup callback for when new software detected
1001 monitorForSoftwareAvailable(asyncResp, req,
1002 "/redfish/v1/UpdateService");
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001003
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001004 uploadImageFile(asyncResp->res, multipart->uploadData);
1005 }
George Liu0ed80c82020-05-12 16:06:27 +08001006}
1007
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001008inline void doHTTPUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1009 const crow::Request& req)
1010{
1011 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
1012 {
1013 task::Payload payload(req);
1014 // HTTP push only supports BMC updates (with ApplyTime as immediate) for
1015 // backwards compatibility. Specific component updates will be handled
1016 // through Multipart form HTTP push.
1017 std::vector<std::string> targets;
1018 targets.emplace_back(BMCWEB_REDFISH_MANAGER_URI_NAME);
1019
1020 processUpdateRequest(
1021 asyncResp, std::move(payload), req.body(),
1022 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate",
1023 targets);
1024 }
1025 else
1026 {
1027 // Setup callback for when new software detected
1028 monitorForSoftwareAvailable(asyncResp, req,
1029 "/redfish/v1/UpdateService");
1030
1031 uploadImageFile(asyncResp->res, req.body());
1032 }
1033}
1034
Ed Tanousc2051d12022-05-11 12:21:55 -07001035inline void
1036 handleUpdateServicePost(App& app, const crow::Request& req,
1037 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1038{
Carson Labrado3ba00072022-06-06 19:40:56 +00001039 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -07001040 {
1041 return;
1042 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001043 std::string_view contentType = req.getHeaderValue("Content-Type");
Ed Tanousc2051d12022-05-11 12:21:55 -07001044
Ed Tanous62598e32023-07-17 17:06:25 -07001045 BMCWEB_LOG_DEBUG("doPost: contentType={}", contentType);
Ed Tanousc2051d12022-05-11 12:21:55 -07001046
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001047 // Make sure that content type is application/octet-stream or
1048 // multipart/form-data
Ed Tanous18f8f602023-07-18 10:07:23 -07001049 if (bmcweb::asciiIEquals(contentType, "application/octet-stream"))
George Liu0ed80c82020-05-12 16:06:27 +08001050 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001051 doHTTPUpdate(asyncResp, req);
George Liu0ed80c82020-05-12 16:06:27 +08001052 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001053 else if (contentType.starts_with("multipart/form-data"))
George Liu0ed80c82020-05-12 16:06:27 +08001054 {
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001055 MultipartParser parser;
1056
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001057 ParserError ec = parser.parse(req);
1058 if (ec != ParserError::PARSER_SUCCESS)
1059 {
1060 // handle error
Ed Tanous62598e32023-07-17 17:06:25 -07001061 BMCWEB_LOG_ERROR("MIME parse failed, ec : {}",
1062 static_cast<int>(ec));
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001063 messages::internalError(asyncResp->res);
1064 return;
1065 }
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001066
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001067 updateMultipartContext(asyncResp, req, std::move(parser));
George Liu0ed80c82020-05-12 16:06:27 +08001068 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001069 else
1070 {
Ed Tanous62598e32023-07-17 17:06:25 -07001071 BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001072 asyncResp->res.result(boost::beast::http::status::bad_request);
1073 }
Ed Tanousc2051d12022-05-11 12:21:55 -07001074}
1075
Ed Tanousf5139332024-04-03 13:25:04 -07001076inline void
1077 handleUpdateServiceGet(App& app, const crow::Request& req,
1078 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001079{
Ed Tanousf5139332024-04-03 13:25:04 -07001080 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1081 {
1082 return;
1083 }
1084 asyncResp->res.jsonValue["@odata.type"] =
1085 "#UpdateService.v1_11_1.UpdateService";
1086 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
1087 asyncResp->res.jsonValue["Id"] = "UpdateService";
1088 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
1089 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001090
Ed Tanousf5139332024-04-03 13:25:04 -07001091 asyncResp->res.jsonValue["HttpPushUri"] =
1092 "/redfish/v1/UpdateService/update";
1093 asyncResp->res.jsonValue["MultipartHttpPushUri"] =
1094 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001095
Ed Tanousf5139332024-04-03 13:25:04 -07001096 // UpdateService cannot be disabled
1097 asyncResp->res.jsonValue["ServiceEnabled"] = true;
1098 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
1099 "/redfish/v1/UpdateService/FirmwareInventory";
1100 // Get the MaxImageSizeBytes
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001101 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
1102 BMCWEB_HTTP_BODY_LIMIT * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +05301103
Ed Tanous6a371402024-12-03 14:01:25 -08001104 if constexpr (BMCWEB_REDFISH_ALLOW_SIMPLE_UPDATE)
Ed Tanous25b54db2024-04-17 15:40:31 -07001105 {
Ed Tanous6a371402024-12-03 14:01:25 -08001106 // Update Actions object.
1107 nlohmann::json& updateSvcSimpleUpdate =
1108 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
1109 updateSvcSimpleUpdate["target"] =
1110 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
Ed Tanous757178a2024-04-03 14:32:38 -07001111
Ed Tanous6a371402024-12-03 14:01:25 -08001112 nlohmann::json::array_t allowed;
1113 allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
1114 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
1115 std::move(allowed);
1116 }
Ed Tanous757178a2024-04-03 14:32:38 -07001117
Ed Tanous539d8c62024-06-19 14:38:27 -07001118 asyncResp->res
1119 .jsonValue["HttpPushUriOptions"]["HttpPushUriApplyTime"]["ApplyTime"] =
1120 update_service::ApplyTime::Immediate;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001121}
Ed Tanousf5139332024-04-03 13:25:04 -07001122
1123inline void handleUpdateServiceFirmwareInventoryCollectionGet(
1124 App& app, const crow::Request& req,
1125 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1126{
1127 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1128 {
1129 return;
1130 }
1131 asyncResp->res.jsonValue["@odata.type"] =
1132 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
1133 asyncResp->res.jsonValue["@odata.id"] =
1134 "/redfish/v1/UpdateService/FirmwareInventory";
1135 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
1136 const std::array<const std::string_view, 1> iface = {
1137 "xyz.openbmc_project.Software.Version"};
1138
1139 redfish::collection_util::getCollectionMembers(
1140 asyncResp,
1141 boost::urls::url("/redfish/v1/UpdateService/FirmwareInventory"), iface,
1142 "/xyz/openbmc_project/software");
1143}
1144
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001145/* Fill related item links (i.e. bmc, bios) in for inventory */
Ed Tanousf5139332024-04-03 13:25:04 -07001146inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1147 const std::string& purpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001148{
Willy Tueee00132022-06-14 14:53:17 -07001149 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001150 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001151 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001152 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001153 item["@odata.id"] = boost::urls::format(
1154 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001155 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001156 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1157 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001158 }
Willy Tueee00132022-06-14 14:53:17 -07001159 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001160 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001161 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001162 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001163 item["@odata.id"] = std::format("/redfish/v1/Systems/{}/Bios",
1164 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001165 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001166 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1167 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001168 }
1169 else
1170 {
Carson Labradobf2dded2023-08-10 00:37:06 +00001171 BMCWEB_LOG_DEBUG("Unknown software purpose {}", purpose);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001172 }
1173}
1174
Willy Tuaf246602022-06-14 15:51:53 -07001175inline void
1176 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1177 const std::string& service, const std::string& path,
1178 const std::string& swId)
1179{
Ed Tanousdeae6a72024-11-11 21:58:57 -08001180 dbus::utility::getAllProperties(
1181 service, path, "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -07001182 [asyncResp,
Ed Tanous8b242752023-06-27 17:17:13 -07001183 swId](const boost::system::error_code& ec,
Willy Tuaf246602022-06-14 15:51:53 -07001184 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001185 if (ec)
1186 {
1187 messages::internalError(asyncResp->res);
1188 return;
1189 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001190
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001191 const std::string* swInvPurpose = nullptr;
1192 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001193
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001194 const bool success = sdbusplus::unpackPropertiesNoThrow(
1195 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
1196 swInvPurpose, "Version", version);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001197
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001198 if (!success)
1199 {
1200 messages::internalError(asyncResp->res);
1201 return;
1202 }
Willy Tuaf246602022-06-14 15:51:53 -07001203
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001204 if (swInvPurpose == nullptr)
1205 {
1206 BMCWEB_LOG_DEBUG("Can't find property \"Purpose\"!");
1207 messages::internalError(asyncResp->res);
1208 return;
1209 }
Willy Tuaf246602022-06-14 15:51:53 -07001210
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001211 BMCWEB_LOG_DEBUG("swInvPurpose = {}", *swInvPurpose);
Willy Tuaf246602022-06-14 15:51:53 -07001212
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001213 if (version == nullptr)
1214 {
1215 BMCWEB_LOG_DEBUG("Can't find property \"Version\"!");
Willy Tuaf246602022-06-14 15:51:53 -07001216
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001217 messages::internalError(asyncResp->res);
Willy Tuaf246602022-06-14 15:51:53 -07001218
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001219 return;
1220 }
1221 asyncResp->res.jsonValue["Version"] = *version;
1222 asyncResp->res.jsonValue["Id"] = swId;
Willy Tuaf246602022-06-14 15:51:53 -07001223
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001224 // swInvPurpose is of format:
1225 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
1226 // Translate this to "ABC image"
1227 size_t endDesc = swInvPurpose->rfind('.');
1228 if (endDesc == std::string::npos)
1229 {
1230 messages::internalError(asyncResp->res);
1231 return;
1232 }
1233 endDesc++;
1234 if (endDesc >= swInvPurpose->size())
1235 {
1236 messages::internalError(asyncResp->res);
1237 return;
1238 }
Willy Tuaf246602022-06-14 15:51:53 -07001239
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001240 std::string formatDesc = swInvPurpose->substr(endDesc);
1241 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
1242 getRelatedItems(asyncResp, *swInvPurpose);
1243 });
Willy Tuaf246602022-06-14 15:51:53 -07001244}
1245
Ed Tanousf5139332024-04-03 13:25:04 -07001246inline void handleUpdateServiceFirmwareInventoryGet(
1247 App& app, const crow::Request& req,
1248 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1249 const std::string& param)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001250{
Ed Tanousf5139332024-04-03 13:25:04 -07001251 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1252 {
1253 return;
1254 }
1255 std::shared_ptr<std::string> swId = std::make_shared<std::string>(param);
1256
1257 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1258 "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId);
1259
1260 constexpr std::array<std::string_view, 1> interfaces = {
1261 "xyz.openbmc_project.Software.Version"};
1262 dbus::utility::getSubTree(
1263 "/", 0, interfaces,
1264 [asyncResp,
1265 swId](const boost::system::error_code& ec,
1266 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001267 BMCWEB_LOG_DEBUG("doGet callback...");
1268 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001269 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001270 messages::internalError(asyncResp->res);
1271 return;
Ed Tanous45ca1b82022-03-25 13:07:27 -07001272 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001273
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001274 // Ensure we find our input swId, otherwise return an error
1275 bool found = false;
1276 for (const std::pair<std::string,
1277 std::vector<std::pair<
1278 std::string, std::vector<std::string>>>>&
1279 obj : subtree)
Ed Tanous002d39b2022-05-31 08:59:27 -07001280 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001281 if (!obj.first.ends_with(*swId))
1282 {
1283 continue;
1284 }
1285
1286 if (obj.second.empty())
1287 {
1288 continue;
1289 }
1290
1291 found = true;
1292 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
1293 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
1294 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -07001295 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001296 if (!found)
1297 {
1298 BMCWEB_LOG_WARNING("Input swID {} not found!", *swId);
1299 messages::resourceMissingAtURI(
1300 asyncResp->res,
1301 boost::urls::format(
1302 "/redfish/v1/UpdateService/FirmwareInventory/{}",
1303 *swId));
1304 return;
1305 }
1306 asyncResp->res.jsonValue["@odata.type"] =
1307 "#SoftwareInventory.v1_1_0.SoftwareInventory";
1308 asyncResp->res.jsonValue["Name"] = "Software Inventory";
1309 asyncResp->res.jsonValue["Status"]["HealthRollup"] =
1310 resource::Health::OK;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001311
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001312 asyncResp->res.jsonValue["Updateable"] = false;
1313 sw_util::getSwUpdatableStatus(asyncResp, swId);
1314 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001315}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001316
Ed Tanousf5139332024-04-03 13:25:04 -07001317inline void requestRoutesUpdateService(App& app)
1318{
Ed Tanous6a371402024-12-03 14:01:25 -08001319 if constexpr (BMCWEB_REDFISH_ALLOW_SIMPLE_UPDATE)
1320 {
1321 BMCWEB_ROUTE(
1322 app,
1323 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
1324 .privileges(redfish::privileges::postUpdateService)
1325 .methods(boost::beast::http::verb::post)(std::bind_front(
1326 handleUpdateServiceSimpleUpdateAction, std::ref(app)));
1327 }
Ed Tanousf5139332024-04-03 13:25:04 -07001328 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
1329 .privileges(redfish::privileges::getSoftwareInventory)
1330 .methods(boost::beast::http::verb::get)(std::bind_front(
1331 handleUpdateServiceFirmwareInventoryGet, std::ref(app)));
1332
1333 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1334 .privileges(redfish::privileges::getUpdateService)
1335 .methods(boost::beast::http::verb::get)(
1336 std::bind_front(handleUpdateServiceGet, std::ref(app)));
1337
Ed Tanousf5139332024-04-03 13:25:04 -07001338 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
1339 .privileges(redfish::privileges::postUpdateService)
1340 .methods(boost::beast::http::verb::post)(
1341 std::bind_front(handleUpdateServicePost, std::ref(app)));
1342
1343 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1344 .privileges(redfish::privileges::getSoftwareInventoryCollection)
1345 .methods(boost::beast::http::verb::get)(std::bind_front(
1346 handleUpdateServiceFirmwareInventoryCollectionGet, std::ref(app)));
1347}
1348
Ed Tanous1abe55e2018-09-05 08:30:59 -07001349} // namespace redfish