blob: 74c6f9231cda22747f404a9887cab14252112492 [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 Tanouse5cf7772024-04-03 13:45:31 -0700500 // OpenBMC currently only supports TFTP or HTTPS
Ed Tanous757178a2024-04-03 14:32:38 -0700501 if (*transferProtocol == "TFTP")
502 {
503 imageURI = "tftp://" + imageURI;
504 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700505 else if (*transferProtocol == "HTTPS")
506 {
507 imageURI = "https://" + imageURI;
508 }
Ed Tanous757178a2024-04-03 14:32:38 -0700509 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700510 {
511 messages::actionParameterNotSupported(res, "TransferProtocol",
512 *transferProtocol);
513 BMCWEB_LOG_ERROR("Request incorrect protocol parameter: {}",
514 *transferProtocol);
515 return std::nullopt;
516 }
Ed Tanousf86bcc82023-08-25 09:34:07 -0700517 }
518
519 boost::system::result<boost::urls::url> url =
520 boost::urls::parse_absolute_uri(imageURI);
521 if (!url)
522 {
523 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
524 "UpdateService.SimpleUpdate");
525
526 return std::nullopt;
527 }
528 url->normalize();
529
Ed Tanous757178a2024-04-03 14:32:38 -0700530 if (url->scheme() == "tftp")
531 {
532 if (url->encoded_path().size() < 2)
533 {
534 messages::actionParameterNotSupported(res, "ImageURI",
535 url->buffer());
536 return std::nullopt;
537 }
538 }
Ed Tanouse5cf7772024-04-03 13:45:31 -0700539 else if (url->scheme() == "https")
540 {
541 // Empty paths default to "/"
542 if (url->encoded_path().empty())
543 {
544 url->set_encoded_path("/");
545 }
546 }
Ed Tanous757178a2024-04-03 14:32:38 -0700547 else
Ed Tanousf86bcc82023-08-25 09:34:07 -0700548 {
549 messages::actionParameterNotSupported(res, "ImageURI", imageURI);
550 return std::nullopt;
551 }
Ed Tanous757178a2024-04-03 14:32:38 -0700552
553 if (url->encoded_path().empty())
Ed Tanousf86bcc82023-08-25 09:34:07 -0700554 {
Ed Tanous757178a2024-04-03 14:32:38 -0700555 messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
556 "UpdateService.SimpleUpdate");
Ed Tanousf86bcc82023-08-25 09:34:07 -0700557 return std::nullopt;
558 }
Ed Tanous757178a2024-04-03 14:32:38 -0700559
560 return *url;
Ed Tanousf86bcc82023-08-25 09:34:07 -0700561}
562
Ed Tanouse5cf7772024-04-03 13:45:31 -0700563inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
564 const boost::urls::url_view_base& url)
565{
566 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
567 url.buffer());
568}
569
Ed Tanousf5139332024-04-03 13:25:04 -0700570inline void handleUpdateServiceSimpleUpdateAction(
571 crow::App& app, const crow::Request& req,
572 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Andrew Geissler0554c982019-04-23 14:40:12 -0500573{
Ed Tanousf5139332024-04-03 13:25:04 -0700574 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
575 {
576 return;
577 }
578
579 std::optional<std::string> transferProtocol;
580 std::string imageURI;
581
582 BMCWEB_LOG_DEBUG("Enter UpdateService.SimpleUpdate doPost");
583
584 // User can pass in both TransferProtocol and ImageURI parameters or
585 // they can pass in just the ImageURI with the transfer protocol
586 // embedded within it.
587 // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
588 // 2) ImageURI:tftp://1.1.1.1/myfile.bin
589
Myung Baeafc474a2024-10-09 00:53:29 -0700590 if (!json_util::readJsonAction( //
591 req, asyncResp->res, //
592 "ImageURI", imageURI, //
593 "TransferProtocol", transferProtocol //
594 ))
Ed Tanousf5139332024-04-03 13:25:04 -0700595 {
596 BMCWEB_LOG_DEBUG("Missing TransferProtocol or ImageURI parameter");
597 return;
598 }
599
Ed Tanous757178a2024-04-03 14:32:38 -0700600 std::optional<boost::urls::url> url =
601 parseSimpleUpdateUrl(imageURI, transferProtocol, asyncResp->res);
602 if (!url)
Ed Tanousf5139332024-04-03 13:25:04 -0700603 {
604 return;
605 }
Jagpal Singh Gill4e338b22024-06-14 14:24:56 -0700606 if (url->scheme() == "https")
Ed Tanouse5cf7772024-04-03 13:45:31 -0700607 {
608 doHttpsUpdate(asyncResp, *url);
609 }
Ed Tanous757178a2024-04-03 14:32:38 -0700610 else
611 {
612 messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
613 url->buffer());
614 return;
615 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700616
Ed Tanousf5139332024-04-03 13:25:04 -0700617 BMCWEB_LOG_DEBUG("Exit UpdateService.SimpleUpdate doPost");
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700618}
619
George Liu0ed80c82020-05-12 16:06:27 +0800620inline void uploadImageFile(crow::Response& res, std::string_view body)
621{
Ed Tanous2c6ffdb2023-06-28 11:28:38 -0700622 std::filesystem::path filepath("/tmp/images/" + bmcweb::getRandomUUID());
623
Ed Tanous62598e32023-07-17 17:06:25 -0700624 BMCWEB_LOG_DEBUG("Writing file to {}", filepath.string());
George Liu0ed80c82020-05-12 16:06:27 +0800625 std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
626 std::ofstream::trunc);
627 // set the permission of the file to 640
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400628 std::filesystem::perms permission =
629 std::filesystem::perms::owner_read | std::filesystem::perms::group_read;
George Liu0ed80c82020-05-12 16:06:27 +0800630 std::filesystem::permissions(filepath, permission);
631 out << body;
632
633 if (out.bad())
634 {
635 messages::internalError(res);
636 cleanUp();
637 }
638}
639
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700640// Convert the Request Apply Time to the D-Bus value
641inline bool convertApplyTime(crow::Response& res, const std::string& applyTime,
642 std::string& applyTimeNewVal)
643{
644 if (applyTime == "Immediate")
645 {
646 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700647 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700648 }
649 else if (applyTime == "OnReset")
650 {
651 applyTimeNewVal =
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700652 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700653 }
654 else
655 {
656 BMCWEB_LOG_WARNING(
657 "ApplyTime value {} is not in the list of acceptable values",
658 applyTime);
659 messages::propertyValueNotInList(res, applyTime, "ApplyTime");
660 return false;
661 }
662 return true;
663}
664
George Liu0ed80c82020-05-12 16:06:27 +0800665inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
666 const std::string& applyTime)
667{
668 std::string applyTimeNewVal;
Jagpal Singh Gill049079f2024-06-02 18:11:13 -0700669 if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
George Liu0ed80c82020-05-12 16:06:27 +0800670 {
George Liu0ed80c82020-05-12 16:06:27 +0800671 return;
672 }
673
Ginu Georgee93abac2024-06-14 17:35:27 +0530674 setDbusProperty(asyncResp, "ApplyTime", "xyz.openbmc_project.Settings",
Ed Tanousd02aad32024-02-13 14:43:34 -0800675 sdbusplus::message::object_path(
676 "/xyz/openbmc_project/software/apply_time"),
677 "xyz.openbmc_project.Software.ApplyTime",
Ginu Georgee93abac2024-06-14 17:35:27 +0530678 "RequestedApplyTime", applyTimeNewVal);
George Liu0ed80c82020-05-12 16:06:27 +0800679}
680
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700681struct MultiPartUpdateParameters
George Liu0ed80c82020-05-12 16:06:27 +0800682{
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700683 std::optional<std::string> applyTime;
684 std::string uploadData;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700685 std::vector<std::string> targets;
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700686};
687
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700688inline std::optional<std::string>
689 processUrl(boost::system::result<boost::urls::url_view>& url)
690{
691 if (!url)
692 {
693 return std::nullopt;
694 }
695 if (crow::utility::readUrlSegments(*url, "redfish", "v1", "Managers",
696 BMCWEB_REDFISH_MANAGER_URI_NAME))
697 {
698 return std::make_optional(std::string(BMCWEB_REDFISH_MANAGER_URI_NAME));
699 }
700 if constexpr (!BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
701 {
702 return std::nullopt;
703 }
704 std::string firmwareId;
705 if (!crow::utility::readUrlSegments(*url, "redfish", "v1", "UpdateService",
706 "FirmwareInventory",
707 std::ref(firmwareId)))
708 {
709 return std::nullopt;
710 }
711
712 return std::make_optional(firmwareId);
713}
714
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700715inline std::optional<MultiPartUpdateParameters>
716 extractMultipartUpdateParameters(
717 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
718 MultipartParser parser)
719{
720 MultiPartUpdateParameters multiRet;
721 for (FormPart& formpart : parser.mime_fields)
George Liu0ed80c82020-05-12 16:06:27 +0800722 {
723 boost::beast::http::fields::const_iterator it =
724 formpart.fields.find("Content-Disposition");
725 if (it == formpart.fields.end())
726 {
Ed Tanous62598e32023-07-17 17:06:25 -0700727 BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700728 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800729 }
Ed Tanous62598e32023-07-17 17:06:25 -0700730 BMCWEB_LOG_INFO("Parsing value {}", it->value());
George Liu0ed80c82020-05-12 16:06:27 +0800731
732 // The construction parameters of param_list must start with `;`
733 size_t index = it->value().find(';');
734 if (index == std::string::npos)
735 {
736 continue;
737 }
738
Patrick Williams89492a12023-05-10 07:51:34 -0500739 for (const auto& param :
George Liu0ed80c82020-05-12 16:06:27 +0800740 boost::beast::http::param_list{it->value().substr(index)})
741 {
742 if (param.first != "name" || param.second.empty())
743 {
744 continue;
745 }
746
747 if (param.second == "UpdateParameters")
748 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700749 std::vector<std::string> tempTargets;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400750 nlohmann::json content =
751 nlohmann::json::parse(formpart.content, nullptr, false);
Ed Tanousac1e1242024-07-10 22:10:14 -0700752 if (content.is_discarded())
753 {
754 return std::nullopt;
755 }
Ed Tanous7cb59f62022-05-05 11:48:31 -0700756 nlohmann::json::object_t* obj =
757 content.get_ptr<nlohmann::json::object_t*>();
758 if (obj == nullptr)
759 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700760 messages::propertyValueTypeError(
761 asyncResp->res, formpart.content, "UpdateParameters");
762 return std::nullopt;
Ed Tanous7cb59f62022-05-05 11:48:31 -0700763 }
764
Myung Baeafc474a2024-10-09 00:53:29 -0700765 if (!json_util::readJsonObject( //
766 *obj, asyncResp->res, //
767 "@Redfish.OperationApplyTime", multiRet.applyTime, //
768 "Targets", tempTargets //
769 ))
George Liu0ed80c82020-05-12 16:06:27 +0800770 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700771 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800772 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700773
774 for (size_t urlIndex = 0; urlIndex < tempTargets.size();
775 urlIndex++)
George Liu0ed80c82020-05-12 16:06:27 +0800776 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700777 const std::string& target = tempTargets[urlIndex];
778 boost::system::result<boost::urls::url_view> url =
779 boost::urls::parse_origin_form(target);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700780 auto res = processUrl(url);
781 if (!res.has_value())
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700782 {
783 messages::propertyValueFormatError(
784 asyncResp->res, target,
785 std::format("Targets/{}", urlIndex));
786 return std::nullopt;
787 }
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700788 multiRet.targets.emplace_back(res.value());
George Liu0ed80c82020-05-12 16:06:27 +0800789 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700790 if (multiRet.targets.size() != 1)
George Liu0ed80c82020-05-12 16:06:27 +0800791 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700792 messages::propertyValueFormatError(
793 asyncResp->res, multiRet.targets, "Targets");
794 return std::nullopt;
George Liu0ed80c82020-05-12 16:06:27 +0800795 }
George Liu0ed80c82020-05-12 16:06:27 +0800796 }
797 else if (param.second == "UpdateFile")
798 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700799 multiRet.uploadData = std::move(formpart.content);
George Liu0ed80c82020-05-12 16:06:27 +0800800 }
801 }
802 }
803
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700804 if (multiRet.uploadData.empty())
George Liu0ed80c82020-05-12 16:06:27 +0800805 {
Ed Tanous62598e32023-07-17 17:06:25 -0700806 BMCWEB_LOG_ERROR("Upload data is NULL");
George Liu0ed80c82020-05-12 16:06:27 +0800807 messages::propertyMissing(asyncResp->res, "UpdateFile");
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700808 return std::nullopt;
809 }
810 if (multiRet.targets.empty())
811 {
812 messages::propertyMissing(asyncResp->res, "Targets");
813 return std::nullopt;
814 }
815 return multiRet;
816}
817
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400818inline void handleStartUpdate(
819 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
820 const std::string& objectPath, const boost::system::error_code& ec,
821 const sdbusplus::message::object_path& retPath)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700822{
823 if (ec)
824 {
825 BMCWEB_LOG_ERROR("error_code = {}", ec);
826 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
827 messages::internalError(asyncResp->res);
828 return;
829 }
830
Jagpal Singh Gill587090c2024-08-12 00:24:16 -0700831 BMCWEB_LOG_INFO("Call to StartUpdate on {} Success, retPath = {}",
832 objectPath, retPath.str);
833 createTask(asyncResp, std::move(payload), retPath);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700834}
835
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400836inline void startUpdate(
837 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
838 const MemoryFileDescriptor& memfd, const std::string& applyTime,
839 const std::string& objectPath, const std::string& serviceName)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700840{
841 crow::connections::systemBus->async_method_call(
842 [asyncResp, payload = std::move(payload),
843 objectPath](const boost::system::error_code& ec1,
844 const sdbusplus::message::object_path& retPath) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400845 handleStartUpdate(asyncResp, std::move(payload), objectPath, ec1,
846 retPath);
847 },
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700848 serviceName, objectPath, "xyz.openbmc_project.Software.Update",
849 "StartUpdate", sdbusplus::message::unix_fd(memfd.fd), applyTime);
850}
851
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700852inline void getSwInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
853 task::Payload payload, const MemoryFileDescriptor& memfd,
854 const std::string& applyTime, const std::string& target,
855 const boost::system::error_code& ec,
856 const dbus::utility::MapperGetSubTreeResponse& subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700857{
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700858 using SwInfoMap = std::unordered_map<
859 std::string, std::pair<sdbusplus::message::object_path, std::string>>;
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700860 SwInfoMap swInfoMap;
861
862 if (ec)
863 {
864 BMCWEB_LOG_ERROR("error_code = {}", ec);
865 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
866 messages::internalError(asyncResp->res);
867 return;
868 }
869 BMCWEB_LOG_DEBUG("Found {} software version paths", subtree.size());
870
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700871 for (const auto& entry : subtree)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700872 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700873 sdbusplus::message::object_path path(entry.first);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700874 std::string swId = path.filename();
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700875 swInfoMap.emplace(swId, make_pair(path, entry.second[0].first));
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700876 }
877
878 auto swEntry = swInfoMap.find(target);
879 if (swEntry == swInfoMap.end())
880 {
881 BMCWEB_LOG_WARNING("No valid DBus path for Target URI {}", target);
882 messages::propertyValueFormatError(asyncResp->res, target, "Targets");
883 return;
884 }
885
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700886 BMCWEB_LOG_DEBUG("Found software version path {} serviceName {}",
887 swEntry->second.first.str, swEntry->second.second);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700888
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700889 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
890 swEntry->second.first.str, swEntry->second.second);
891}
892
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400893inline void handleBMCUpdate(
894 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
895 const MemoryFileDescriptor& memfd, const std::string& applyTime,
896 const boost::system::error_code& ec,
897 const dbus::utility::MapperEndPoints& functionalSoftware)
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700898{
899 if (ec)
900 {
901 BMCWEB_LOG_ERROR("error_code = {}", ec);
902 BMCWEB_LOG_ERROR("error msg = {}", ec.message());
903 messages::internalError(asyncResp->res);
904 return;
905 }
906 if (functionalSoftware.size() != 1)
907 {
908 BMCWEB_LOG_ERROR("Found {} functional software endpoints",
909 functionalSoftware.size());
910 messages::internalError(asyncResp->res);
911 return;
912 }
913
914 startUpdate(asyncResp, std::move(payload), memfd, applyTime,
915 functionalSoftware[0], "xyz.openbmc_project.Software.Manager");
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700916}
917
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400918inline void processUpdateRequest(
919 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
920 task::Payload&& payload, std::string_view body,
921 const std::string& applyTime, std::vector<std::string>& targets)
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700922{
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700923 MemoryFileDescriptor memfd("update-image");
924 if (memfd.fd == -1)
925 {
926 BMCWEB_LOG_ERROR("Failed to create image memfd");
927 messages::internalError(asyncResp->res);
928 return;
929 }
930 if (write(memfd.fd, body.data(), body.length()) !=
931 static_cast<ssize_t>(body.length()))
932 {
933 BMCWEB_LOG_ERROR("Failed to write to image memfd");
934 messages::internalError(asyncResp->res);
935 return;
936 }
937 if (!memfd.rewind())
938 {
939 messages::internalError(asyncResp->res);
940 return;
941 }
942
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700943 if (!targets.empty() && targets[0] == BMCWEB_REDFISH_MANAGER_URI_NAME)
944 {
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700945 dbus::utility::getAssociationEndPoints(
Jagpal Singh Gill89449bb2024-08-12 16:17:58 -0700946 "/xyz/openbmc_project/software/bmc/updateable",
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700947 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
948 applyTime](
949 const boost::system::error_code& ec,
950 const dbus::utility::MapperEndPoints& objectPaths) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400951 handleBMCUpdate(asyncResp, std::move(payload), memfd, applyTime,
952 ec, objectPaths);
953 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700954 }
955 else
956 {
957 constexpr std::array<std::string_view, 1> interfaces = {
958 "xyz.openbmc_project.Software.Version"};
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700959 dbus::utility::getSubTree(
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700960 "/xyz/openbmc_project/software", 1, interfaces,
961 [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
Jagpal Singh Gill08f61d52024-07-17 15:17:22 -0700962 applyTime, targets](const boost::system::error_code& ec,
963 const dbus::utility::MapperGetSubTreeResponse&
964 subtree) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400965 getSwInfo(asyncResp, std::move(payload), memfd, applyTime,
966 targets[0], ec, subtree);
967 });
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700968 }
969}
970
971inline void
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700972 updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
973 const crow::Request& req, MultipartParser&& parser)
974{
975 std::optional<MultiPartUpdateParameters> multipart =
976 extractMultipartUpdateParameters(asyncResp, std::move(parser));
977 if (!multipart)
978 {
George Liu0ed80c82020-05-12 16:06:27 +0800979 return;
980 }
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700981 if (!multipart->applyTime)
George Liu0ed80c82020-05-12 16:06:27 +0800982 {
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -0700983 multipart->applyTime = "OnReset";
George Liu0ed80c82020-05-12 16:06:27 +0800984 }
985
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700986 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
987 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -0700988 std::string applyTimeNewVal;
989 if (!convertApplyTime(asyncResp->res, *multipart->applyTime,
990 applyTimeNewVal))
991 {
992 return;
993 }
994 task::Payload payload(req);
995
996 processUpdateRequest(asyncResp, std::move(payload),
997 multipart->uploadData, applyTimeNewVal,
998 multipart->targets);
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -0700999 }
1000 else
1001 {
1002 setApplyTime(asyncResp, *multipart->applyTime);
George Liu0ed80c82020-05-12 16:06:27 +08001003
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001004 // Setup callback for when new software detected
1005 monitorForSoftwareAvailable(asyncResp, req,
1006 "/redfish/v1/UpdateService");
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001007
Jagpal Singh Gillde0c9602024-04-29 17:30:21 -07001008 uploadImageFile(asyncResp->res, multipart->uploadData);
1009 }
George Liu0ed80c82020-05-12 16:06:27 +08001010}
1011
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001012inline void doHTTPUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1013 const crow::Request& req)
1014{
1015 if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
1016 {
1017 task::Payload payload(req);
1018 // HTTP push only supports BMC updates (with ApplyTime as immediate) for
1019 // backwards compatibility. Specific component updates will be handled
1020 // through Multipart form HTTP push.
1021 std::vector<std::string> targets;
1022 targets.emplace_back(BMCWEB_REDFISH_MANAGER_URI_NAME);
1023
1024 processUpdateRequest(
1025 asyncResp, std::move(payload), req.body(),
1026 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate",
1027 targets);
1028 }
1029 else
1030 {
1031 // Setup callback for when new software detected
1032 monitorForSoftwareAvailable(asyncResp, req,
1033 "/redfish/v1/UpdateService");
1034
1035 uploadImageFile(asyncResp->res, req.body());
1036 }
1037}
1038
Ed Tanousc2051d12022-05-11 12:21:55 -07001039inline void
1040 handleUpdateServicePost(App& app, const crow::Request& req,
1041 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1042{
Carson Labrado3ba00072022-06-06 19:40:56 +00001043 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanousc2051d12022-05-11 12:21:55 -07001044 {
1045 return;
1046 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001047 std::string_view contentType = req.getHeaderValue("Content-Type");
Ed Tanousc2051d12022-05-11 12:21:55 -07001048
Ed Tanous62598e32023-07-17 17:06:25 -07001049 BMCWEB_LOG_DEBUG("doPost: contentType={}", contentType);
Ed Tanousc2051d12022-05-11 12:21:55 -07001050
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001051 // Make sure that content type is application/octet-stream or
1052 // multipart/form-data
Ed Tanous18f8f602023-07-18 10:07:23 -07001053 if (bmcweb::asciiIEquals(contentType, "application/octet-stream"))
George Liu0ed80c82020-05-12 16:06:27 +08001054 {
Jagpal Singh Gill9dae4de2024-06-02 23:43:56 -07001055 doHTTPUpdate(asyncResp, req);
George Liu0ed80c82020-05-12 16:06:27 +08001056 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001057 else if (contentType.starts_with("multipart/form-data"))
George Liu0ed80c82020-05-12 16:06:27 +08001058 {
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001059 MultipartParser parser;
1060
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001061 ParserError ec = parser.parse(req);
1062 if (ec != ParserError::PARSER_SUCCESS)
1063 {
1064 // handle error
Ed Tanous62598e32023-07-17 17:06:25 -07001065 BMCWEB_LOG_ERROR("MIME parse failed, ec : {}",
1066 static_cast<int>(ec));
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001067 messages::internalError(asyncResp->res);
1068 return;
1069 }
Ed Tanous6b54e4e2024-04-10 08:58:48 -07001070
Jagpal Singh Gillef93eab2024-04-17 16:06:14 -07001071 updateMultipartContext(asyncResp, req, std::move(parser));
George Liu0ed80c82020-05-12 16:06:27 +08001072 }
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001073 else
1074 {
Ed Tanous62598e32023-07-17 17:06:25 -07001075 BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
Ninad Palsuleb33a4322023-06-09 09:19:18 -05001076 asyncResp->res.result(boost::beast::http::status::bad_request);
1077 }
Ed Tanousc2051d12022-05-11 12:21:55 -07001078}
1079
Ed Tanousf5139332024-04-03 13:25:04 -07001080inline void
1081 handleUpdateServiceGet(App& app, const crow::Request& req,
1082 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001083{
Ed Tanousf5139332024-04-03 13:25:04 -07001084 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1085 {
1086 return;
1087 }
1088 asyncResp->res.jsonValue["@odata.type"] =
1089 "#UpdateService.v1_11_1.UpdateService";
1090 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
1091 asyncResp->res.jsonValue["Id"] = "UpdateService";
1092 asyncResp->res.jsonValue["Description"] = "Service for Software Update";
1093 asyncResp->res.jsonValue["Name"] = "Update Service";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001094
Ed Tanousf5139332024-04-03 13:25:04 -07001095 asyncResp->res.jsonValue["HttpPushUri"] =
1096 "/redfish/v1/UpdateService/update";
1097 asyncResp->res.jsonValue["MultipartHttpPushUri"] =
1098 "/redfish/v1/UpdateService/update";
Ed Tanous4dc23f32022-05-11 11:32:19 -07001099
Ed Tanousf5139332024-04-03 13:25:04 -07001100 // UpdateService cannot be disabled
1101 asyncResp->res.jsonValue["ServiceEnabled"] = true;
1102 asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
1103 "/redfish/v1/UpdateService/FirmwareInventory";
1104 // Get the MaxImageSizeBytes
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001105 asyncResp->res.jsonValue["MaxImageSizeBytes"] =
1106 BMCWEB_HTTP_BODY_LIMIT * 1024 * 1024;
Tejas Patild61e5192021-06-04 15:49:35 +05301107
Ed Tanousf5139332024-04-03 13:25:04 -07001108 // Update Actions object.
1109 nlohmann::json& updateSvcSimpleUpdate =
1110 asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
1111 updateSvcSimpleUpdate["target"] =
1112 "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
Ed Tanous757178a2024-04-03 14:32:38 -07001113
1114 nlohmann::json::array_t allowed;
Ed Tanouse5cf7772024-04-03 13:45:31 -07001115 allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
Ed Tanous757178a2024-04-03 14:32:38 -07001116
Ed Tanous25b54db2024-04-17 15:40:31 -07001117 if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
1118 {
1119 allowed.emplace_back(update_service::TransferProtocolType::TFTP);
1120 }
Ed Tanous757178a2024-04-03 14:32:38 -07001121
1122 updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
1123 std::move(allowed);
1124
Ed Tanous539d8c62024-06-19 14:38:27 -07001125 asyncResp->res
1126 .jsonValue["HttpPushUriOptions"]["HttpPushUriApplyTime"]["ApplyTime"] =
1127 update_service::ApplyTime::Immediate;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001128}
Ed Tanousf5139332024-04-03 13:25:04 -07001129
1130inline void handleUpdateServiceFirmwareInventoryCollectionGet(
1131 App& app, const crow::Request& req,
1132 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1133{
1134 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1135 {
1136 return;
1137 }
1138 asyncResp->res.jsonValue["@odata.type"] =
1139 "#SoftwareInventoryCollection.SoftwareInventoryCollection";
1140 asyncResp->res.jsonValue["@odata.id"] =
1141 "/redfish/v1/UpdateService/FirmwareInventory";
1142 asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
1143 const std::array<const std::string_view, 1> iface = {
1144 "xyz.openbmc_project.Software.Version"};
1145
1146 redfish::collection_util::getCollectionMembers(
1147 asyncResp,
1148 boost::urls::url("/redfish/v1/UpdateService/FirmwareInventory"), iface,
1149 "/xyz/openbmc_project/software");
1150}
1151
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001152/* Fill related item links (i.e. bmc, bios) in for inventory */
Ed Tanousf5139332024-04-03 13:25:04 -07001153inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1154 const std::string& purpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001155{
Willy Tueee00132022-06-14 14:53:17 -07001156 if (purpose == sw_util::bmcPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001157 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001158 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001159 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001160 item["@odata.id"] = boost::urls::format(
1161 "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001162 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001163 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1164 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001165 }
Willy Tueee00132022-06-14 14:53:17 -07001166 else if (purpose == sw_util::biosPurpose)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001167 {
Ed Tanousac106bf2023-06-07 09:24:59 -07001168 nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
Ed Tanous14766872022-03-15 10:44:42 -07001169 nlohmann::json::object_t item;
Ed Tanous253f11b2024-05-16 09:38:31 -07001170 item["@odata.id"] = std::format("/redfish/v1/Systems/{}/Bios",
1171 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001172 relatedItem.emplace_back(std::move(item));
Ed Tanousac106bf2023-06-07 09:24:59 -07001173 asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1174 relatedItem.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001175 }
1176 else
1177 {
Carson Labradobf2dded2023-08-10 00:37:06 +00001178 BMCWEB_LOG_DEBUG("Unknown software purpose {}", purpose);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001179 }
1180}
1181
Willy Tuaf246602022-06-14 15:51:53 -07001182inline void
1183 getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1184 const std::string& service, const std::string& path,
1185 const std::string& swId)
1186{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001187 sdbusplus::asio::getAllProperties(
1188 *crow::connections::systemBus, service, path,
1189 "xyz.openbmc_project.Software.Version",
Willy Tuaf246602022-06-14 15:51:53 -07001190 [asyncResp,
Ed Tanous8b242752023-06-27 17:17:13 -07001191 swId](const boost::system::error_code& ec,
Willy Tuaf246602022-06-14 15:51:53 -07001192 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001193 if (ec)
1194 {
1195 messages::internalError(asyncResp->res);
1196 return;
1197 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001198
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001199 const std::string* swInvPurpose = nullptr;
1200 const std::string* version = nullptr;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001201
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001202 const bool success = sdbusplus::unpackPropertiesNoThrow(
1203 dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
1204 swInvPurpose, "Version", version);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001205
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001206 if (!success)
1207 {
1208 messages::internalError(asyncResp->res);
1209 return;
1210 }
Willy Tuaf246602022-06-14 15:51:53 -07001211
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001212 if (swInvPurpose == nullptr)
1213 {
1214 BMCWEB_LOG_DEBUG("Can't find property \"Purpose\"!");
1215 messages::internalError(asyncResp->res);
1216 return;
1217 }
Willy Tuaf246602022-06-14 15:51:53 -07001218
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001219 BMCWEB_LOG_DEBUG("swInvPurpose = {}", *swInvPurpose);
Willy Tuaf246602022-06-14 15:51:53 -07001220
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001221 if (version == nullptr)
1222 {
1223 BMCWEB_LOG_DEBUG("Can't find property \"Version\"!");
Willy Tuaf246602022-06-14 15:51:53 -07001224
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001225 messages::internalError(asyncResp->res);
Willy Tuaf246602022-06-14 15:51:53 -07001226
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001227 return;
1228 }
1229 asyncResp->res.jsonValue["Version"] = *version;
1230 asyncResp->res.jsonValue["Id"] = swId;
Willy Tuaf246602022-06-14 15:51:53 -07001231
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001232 // swInvPurpose is of format:
1233 // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
1234 // Translate this to "ABC image"
1235 size_t endDesc = swInvPurpose->rfind('.');
1236 if (endDesc == std::string::npos)
1237 {
1238 messages::internalError(asyncResp->res);
1239 return;
1240 }
1241 endDesc++;
1242 if (endDesc >= swInvPurpose->size())
1243 {
1244 messages::internalError(asyncResp->res);
1245 return;
1246 }
Willy Tuaf246602022-06-14 15:51:53 -07001247
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001248 std::string formatDesc = swInvPurpose->substr(endDesc);
1249 asyncResp->res.jsonValue["Description"] = formatDesc + " image";
1250 getRelatedItems(asyncResp, *swInvPurpose);
1251 });
Willy Tuaf246602022-06-14 15:51:53 -07001252}
1253
Ed Tanousf5139332024-04-03 13:25:04 -07001254inline void handleUpdateServiceFirmwareInventoryGet(
1255 App& app, const crow::Request& req,
1256 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1257 const std::string& param)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001258{
Ed Tanousf5139332024-04-03 13:25:04 -07001259 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1260 {
1261 return;
1262 }
1263 std::shared_ptr<std::string> swId = std::make_shared<std::string>(param);
1264
1265 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1266 "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId);
1267
1268 constexpr std::array<std::string_view, 1> interfaces = {
1269 "xyz.openbmc_project.Software.Version"};
1270 dbus::utility::getSubTree(
1271 "/", 0, interfaces,
1272 [asyncResp,
1273 swId](const boost::system::error_code& ec,
1274 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001275 BMCWEB_LOG_DEBUG("doGet callback...");
1276 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001277 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001278 messages::internalError(asyncResp->res);
1279 return;
Ed Tanous45ca1b82022-03-25 13:07:27 -07001280 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001281
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001282 // Ensure we find our input swId, otherwise return an error
1283 bool found = false;
1284 for (const std::pair<std::string,
1285 std::vector<std::pair<
1286 std::string, std::vector<std::string>>>>&
1287 obj : subtree)
Ed Tanous002d39b2022-05-31 08:59:27 -07001288 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001289 if (!obj.first.ends_with(*swId))
1290 {
1291 continue;
1292 }
1293
1294 if (obj.second.empty())
1295 {
1296 continue;
1297 }
1298
1299 found = true;
1300 sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
1301 getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
1302 *swId);
Ed Tanous002d39b2022-05-31 08:59:27 -07001303 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001304 if (!found)
1305 {
1306 BMCWEB_LOG_WARNING("Input swID {} not found!", *swId);
1307 messages::resourceMissingAtURI(
1308 asyncResp->res,
1309 boost::urls::format(
1310 "/redfish/v1/UpdateService/FirmwareInventory/{}",
1311 *swId));
1312 return;
1313 }
1314 asyncResp->res.jsonValue["@odata.type"] =
1315 "#SoftwareInventory.v1_1_0.SoftwareInventory";
1316 asyncResp->res.jsonValue["Name"] = "Software Inventory";
1317 asyncResp->res.jsonValue["Status"]["HealthRollup"] =
1318 resource::Health::OK;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001319
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001320 asyncResp->res.jsonValue["Updateable"] = false;
1321 sw_util::getSwUpdatableStatus(asyncResp, swId);
1322 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001323}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001324
Ed Tanousf5139332024-04-03 13:25:04 -07001325inline void requestRoutesUpdateService(App& app)
1326{
1327 BMCWEB_ROUTE(
1328 app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
1329 .privileges(redfish::privileges::postUpdateService)
1330 .methods(boost::beast::http::verb::post)(std::bind_front(
1331 handleUpdateServiceSimpleUpdateAction, std::ref(app)));
1332
1333 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
1334 .privileges(redfish::privileges::getSoftwareInventory)
1335 .methods(boost::beast::http::verb::get)(std::bind_front(
1336 handleUpdateServiceFirmwareInventoryGet, std::ref(app)));
1337
1338 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1339 .privileges(redfish::privileges::getUpdateService)
1340 .methods(boost::beast::http::verb::get)(
1341 std::bind_front(handleUpdateServiceGet, std::ref(app)));
1342
Ed Tanousf5139332024-04-03 13:25:04 -07001343 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
1344 .privileges(redfish::privileges::postUpdateService)
1345 .methods(boost::beast::http::verb::post)(
1346 std::bind_front(handleUpdateServicePost, std::ref(app)));
1347
1348 BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1349 .privileges(redfish::privileges::getSoftwareInventoryCollection)
1350 .methods(boost::beast::http::verb::get)(std::bind_front(
1351 handleUpdateServiceFirmwareInventoryCollectionGet, std::ref(app)));
1352}
1353
Ed Tanous1abe55e2018-09-05 08:30:59 -07001354} // namespace redfish