xref: /openbmc/bmcweb/features/redfish/lib/update_service.hpp (revision de0c960c4262169ea92a4b852dd5ebbe3810bf00)
1729dae72SJennifer Lee /*
2729dae72SJennifer Lee // Copyright (c) 2018 Intel Corporation
3729dae72SJennifer Lee //
4729dae72SJennifer Lee // Licensed under the Apache License, Version 2.0 (the "License");
5729dae72SJennifer Lee // you may not use this file except in compliance with the License.
6729dae72SJennifer Lee // You may obtain a copy of the License at
7729dae72SJennifer Lee //
8729dae72SJennifer Lee //      http://www.apache.org/licenses/LICENSE-2.0
9729dae72SJennifer Lee //
10729dae72SJennifer Lee // Unless required by applicable law or agreed to in writing, software
11729dae72SJennifer Lee // distributed under the License is distributed on an "AS IS" BASIS,
12729dae72SJennifer Lee // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13729dae72SJennifer Lee // See the License for the specific language governing permissions and
14729dae72SJennifer Lee // limitations under the License.
15729dae72SJennifer Lee */
16729dae72SJennifer Lee #pragma once
17729dae72SJennifer Lee 
18d61e5194STejas Patil #include "bmcweb_config.h"
19d61e5194STejas Patil 
203ccb3adbSEd Tanous #include "app.hpp"
213ccb3adbSEd Tanous #include "dbus_utility.hpp"
225b90429aSEd Tanous #include "error_messages.hpp"
23757178a5SEd Tanous #include "generated/enums/update_service.hpp"
240ed80c8cSGeorge Liu #include "multipart_parser.hpp"
252c6ffdb0SEd Tanous #include "ossl_random.hpp"
263ccb3adbSEd Tanous #include "query.hpp"
273ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
28a8e884fcSEd Tanous #include "task.hpp"
295b90429aSEd Tanous #include "task_messages.hpp"
3008d81adaSJohn Edward Broadbent #include "utils/collection.hpp"
313ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
325b90429aSEd Tanous #include "utils/json_utils.hpp"
333ccb3adbSEd Tanous #include "utils/sw_utils.hpp"
343ccb3adbSEd Tanous 
35*de0c960cSJagpal Singh Gill #include <sys/mman.h>
36*de0c960cSJagpal Singh Gill 
37e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
38ef4c65b7SEd Tanous #include <boost/url/format.hpp>
391e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
403ccb3adbSEd Tanous #include <sdbusplus/bus/match.hpp>
41d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
421214b7e7SGunnar Mills 
432b73119cSGeorge Liu #include <array>
44*de0c960cSJagpal Singh Gill #include <cstddef>
450ed80c8cSGeorge Liu #include <filesystem>
46c71b6c99SJagpal Singh Gill #include <functional>
47*de0c960cSJagpal Singh Gill #include <iterator>
48ef93eab3SJagpal Singh Gill #include <memory>
497cb59f65SEd Tanous #include <optional>
507cb59f65SEd Tanous #include <string>
512b73119cSGeorge Liu #include <string_view>
52*de0c960cSJagpal Singh Gill #include <unordered_map>
53ef93eab3SJagpal Singh Gill #include <vector>
542b73119cSGeorge Liu 
551abe55efSEd Tanous namespace redfish
561abe55efSEd Tanous {
5727826b5fSEd Tanous 
580e7de46fSAndrew Geissler // Match signals added on software path
59cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
6059d494eeSPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatcher;
61cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
6259d494eeSPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateErrorMatcher;
630e7de46fSAndrew Geissler // Only allow one update at a time
64cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
650e7de46fSAndrew Geissler static bool fwUpdateInProgress = false;
6686adcd6dSAndrew Geissler // Timer for software available
67cf9e417dSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
68271584abSEd Tanous static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
6986adcd6dSAndrew Geissler 
70*de0c960cSJagpal Singh Gill struct MemoryFileDescriptor
71*de0c960cSJagpal Singh Gill {
72*de0c960cSJagpal Singh Gill     int fd = -1;
73*de0c960cSJagpal Singh Gill 
74*de0c960cSJagpal Singh Gill     explicit MemoryFileDescriptor(const std::string& filename) :
75*de0c960cSJagpal Singh Gill         fd(memfd_create(filename.c_str(), 0))
76*de0c960cSJagpal Singh Gill     {}
77*de0c960cSJagpal Singh Gill 
78*de0c960cSJagpal Singh Gill     MemoryFileDescriptor(const MemoryFileDescriptor&) = default;
79*de0c960cSJagpal Singh Gill     MemoryFileDescriptor(MemoryFileDescriptor&& other) noexcept : fd(other.fd)
80*de0c960cSJagpal Singh Gill     {
81*de0c960cSJagpal Singh Gill         other.fd = -1;
82*de0c960cSJagpal Singh Gill     }
83*de0c960cSJagpal Singh Gill     MemoryFileDescriptor& operator=(const MemoryFileDescriptor&) = delete;
84*de0c960cSJagpal Singh Gill     MemoryFileDescriptor& operator=(MemoryFileDescriptor&&) = default;
85*de0c960cSJagpal Singh Gill 
86*de0c960cSJagpal Singh Gill     ~MemoryFileDescriptor()
87*de0c960cSJagpal Singh Gill     {
88*de0c960cSJagpal Singh Gill         if (fd != -1)
89*de0c960cSJagpal Singh Gill         {
90*de0c960cSJagpal Singh Gill             close(fd);
91*de0c960cSJagpal Singh Gill         }
92*de0c960cSJagpal Singh Gill     }
93*de0c960cSJagpal Singh Gill 
94*de0c960cSJagpal Singh Gill     bool rewind() const
95*de0c960cSJagpal Singh Gill     {
96*de0c960cSJagpal Singh Gill         if (lseek(fd, 0, SEEK_SET) == -1)
97*de0c960cSJagpal Singh Gill         {
98*de0c960cSJagpal Singh Gill             BMCWEB_LOG_ERROR("Failed to seek to beginning of image memfd");
99*de0c960cSJagpal Singh Gill             return false;
100*de0c960cSJagpal Singh Gill         }
101*de0c960cSJagpal Singh Gill         return true;
102*de0c960cSJagpal Singh Gill     }
103*de0c960cSJagpal Singh Gill };
104*de0c960cSJagpal Singh Gill 
105df254f2cSEd Tanous inline void cleanUp()
10686adcd6dSAndrew Geissler {
10786adcd6dSAndrew Geissler     fwUpdateInProgress = false;
10886adcd6dSAndrew Geissler     fwUpdateMatcher = nullptr;
1094cde5d90SJames Feist     fwUpdateErrorMatcher = nullptr;
11086adcd6dSAndrew Geissler }
111df254f2cSEd Tanous 
112df254f2cSEd Tanous inline void activateImage(const std::string& objPath,
11386adcd6dSAndrew Geissler                           const std::string& service)
11486adcd6dSAndrew Geissler {
11562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Activate image for {} {}", objPath, service);
1169ae226faSGeorge Liu     sdbusplus::asio::setProperty(
1179ae226faSGeorge Liu         *crow::connections::systemBus, service, objPath,
1189ae226faSGeorge Liu         "xyz.openbmc_project.Software.Activation", "RequestedActivation",
1199ae226faSGeorge Liu         "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
1208b24275dSEd Tanous         [](const boost::system::error_code& ec) {
1218b24275dSEd Tanous         if (ec)
12286adcd6dSAndrew Geissler         {
12362598e31SEd Tanous             BMCWEB_LOG_DEBUG("error_code = {}", ec);
12462598e31SEd Tanous             BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
12586adcd6dSAndrew Geissler         }
1269ae226faSGeorge Liu     });
12786adcd6dSAndrew Geissler }
1280554c984SAndrew Geissler 
129c71b6c99SJagpal Singh Gill inline bool handleCreateTask(const boost::system::error_code& ec2,
130c71b6c99SJagpal Singh Gill                              sdbusplus::message_t& msg,
131c71b6c99SJagpal Singh Gill                              const std::shared_ptr<task::TaskData>& taskData)
132c71b6c99SJagpal Singh Gill {
133c71b6c99SJagpal Singh Gill     if (ec2)
134c71b6c99SJagpal Singh Gill     {
135c71b6c99SJagpal Singh Gill         return task::completed;
136c71b6c99SJagpal Singh Gill     }
137c71b6c99SJagpal Singh Gill 
138c71b6c99SJagpal Singh Gill     std::string iface;
139c71b6c99SJagpal Singh Gill     dbus::utility::DBusPropertiesMap values;
140c71b6c99SJagpal Singh Gill 
141c71b6c99SJagpal Singh Gill     std::string index = std::to_string(taskData->index);
142c71b6c99SJagpal Singh Gill     msg.read(iface, values);
143c71b6c99SJagpal Singh Gill 
144c71b6c99SJagpal Singh Gill     if (iface == "xyz.openbmc_project.Software.Activation")
145c71b6c99SJagpal Singh Gill     {
146c71b6c99SJagpal Singh Gill         const std::string* state = nullptr;
147c71b6c99SJagpal Singh Gill         for (const auto& property : values)
148c71b6c99SJagpal Singh Gill         {
149c71b6c99SJagpal Singh Gill             if (property.first == "Activation")
150c71b6c99SJagpal Singh Gill             {
151c71b6c99SJagpal Singh Gill                 state = std::get_if<std::string>(&property.second);
152c71b6c99SJagpal Singh Gill                 if (state == nullptr)
153c71b6c99SJagpal Singh Gill                 {
154c71b6c99SJagpal Singh Gill                     taskData->messages.emplace_back(messages::internalError());
155c71b6c99SJagpal Singh Gill                     return task::completed;
156c71b6c99SJagpal Singh Gill                 }
157c71b6c99SJagpal Singh Gill             }
158c71b6c99SJagpal Singh Gill         }
159c71b6c99SJagpal Singh Gill 
160c71b6c99SJagpal Singh Gill         if (state == nullptr)
161c71b6c99SJagpal Singh Gill         {
162c71b6c99SJagpal Singh Gill             return !task::completed;
163c71b6c99SJagpal Singh Gill         }
164c71b6c99SJagpal Singh Gill 
165c71b6c99SJagpal Singh Gill         if (state->ends_with("Invalid") || state->ends_with("Failed"))
166c71b6c99SJagpal Singh Gill         {
167c71b6c99SJagpal Singh Gill             taskData->state = "Exception";
168c71b6c99SJagpal Singh Gill             taskData->status = "Warning";
169c71b6c99SJagpal Singh Gill             taskData->messages.emplace_back(messages::taskAborted(index));
170c71b6c99SJagpal Singh Gill             return task::completed;
171c71b6c99SJagpal Singh Gill         }
172c71b6c99SJagpal Singh Gill 
173c71b6c99SJagpal Singh Gill         if (state->ends_with("Staged"))
174c71b6c99SJagpal Singh Gill         {
175c71b6c99SJagpal Singh Gill             taskData->state = "Stopping";
176c71b6c99SJagpal Singh Gill             taskData->messages.emplace_back(messages::taskPaused(index));
177c71b6c99SJagpal Singh Gill 
178c71b6c99SJagpal Singh Gill             // its staged, set a long timer to
179c71b6c99SJagpal Singh Gill             // allow them time to complete the
180c71b6c99SJagpal Singh Gill             // update (probably cycle the
181c71b6c99SJagpal Singh Gill             // system) if this expires then
182c71b6c99SJagpal Singh Gill             // task will be canceled
183c71b6c99SJagpal Singh Gill             taskData->extendTimer(std::chrono::hours(5));
184c71b6c99SJagpal Singh Gill             return !task::completed;
185c71b6c99SJagpal Singh Gill         }
186c71b6c99SJagpal Singh Gill 
187c71b6c99SJagpal Singh Gill         if (state->ends_with("Active"))
188c71b6c99SJagpal Singh Gill         {
189c71b6c99SJagpal Singh Gill             taskData->messages.emplace_back(messages::taskCompletedOK(index));
190c71b6c99SJagpal Singh Gill             taskData->state = "Completed";
191c71b6c99SJagpal Singh Gill             return task::completed;
192c71b6c99SJagpal Singh Gill         }
193c71b6c99SJagpal Singh Gill     }
194c71b6c99SJagpal Singh Gill     else if (iface == "xyz.openbmc_project.Software.ActivationProgress")
195c71b6c99SJagpal Singh Gill     {
196c71b6c99SJagpal Singh Gill         const uint8_t* progress = nullptr;
197c71b6c99SJagpal Singh Gill         for (const auto& property : values)
198c71b6c99SJagpal Singh Gill         {
199c71b6c99SJagpal Singh Gill             if (property.first == "Progress")
200c71b6c99SJagpal Singh Gill             {
201c71b6c99SJagpal Singh Gill                 progress = std::get_if<uint8_t>(&property.second);
202c71b6c99SJagpal Singh Gill                 if (progress == nullptr)
203c71b6c99SJagpal Singh Gill                 {
204c71b6c99SJagpal Singh Gill                     taskData->messages.emplace_back(messages::internalError());
205c71b6c99SJagpal Singh Gill                     return task::completed;
206c71b6c99SJagpal Singh Gill                 }
207c71b6c99SJagpal Singh Gill             }
208c71b6c99SJagpal Singh Gill         }
209c71b6c99SJagpal Singh Gill 
210c71b6c99SJagpal Singh Gill         if (progress == nullptr)
211c71b6c99SJagpal Singh Gill         {
212c71b6c99SJagpal Singh Gill             return !task::completed;
213c71b6c99SJagpal Singh Gill         }
214c71b6c99SJagpal Singh Gill         taskData->percentComplete = *progress;
215c71b6c99SJagpal Singh Gill         taskData->messages.emplace_back(
216c71b6c99SJagpal Singh Gill             messages::taskProgressChanged(index, *progress));
217c71b6c99SJagpal Singh Gill 
218c71b6c99SJagpal Singh Gill         // if we're getting status updates it's
219c71b6c99SJagpal Singh Gill         // still alive, update timer
220c71b6c99SJagpal Singh Gill         taskData->extendTimer(std::chrono::minutes(5));
221c71b6c99SJagpal Singh Gill     }
222c71b6c99SJagpal Singh Gill 
223c71b6c99SJagpal Singh Gill     // as firmware update often results in a
224c71b6c99SJagpal Singh Gill     // reboot, the task  may never "complete"
225c71b6c99SJagpal Singh Gill     // unless it is an error
226c71b6c99SJagpal Singh Gill 
227c71b6c99SJagpal Singh Gill     return !task::completed;
228c71b6c99SJagpal Singh Gill }
229c71b6c99SJagpal Singh Gill 
230c71b6c99SJagpal Singh Gill inline void createTask(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
231c71b6c99SJagpal Singh Gill                        task::Payload&& payload,
232c71b6c99SJagpal Singh Gill                        const sdbusplus::message::object_path& objPath)
233c71b6c99SJagpal Singh Gill {
234c71b6c99SJagpal Singh Gill     std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
235c71b6c99SJagpal Singh Gill         std::bind_front(handleCreateTask),
236c71b6c99SJagpal Singh Gill         "type='signal',interface='org.freedesktop.DBus.Properties',"
237c71b6c99SJagpal Singh Gill         "member='PropertiesChanged',path='" +
238c71b6c99SJagpal Singh Gill             objPath.str + "'");
239c71b6c99SJagpal Singh Gill     task->startTimer(std::chrono::minutes(5));
240c71b6c99SJagpal Singh Gill     task->populateResp(asyncResp->res);
241c71b6c99SJagpal Singh Gill     task->payload.emplace(std::move(payload));
242c71b6c99SJagpal Singh Gill }
243c71b6c99SJagpal Singh Gill 
2440554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
2450554c984SAndrew Geissler // then no asyncResp updates will occur
2468d1b46d7Szhanghch05 static void
2478d1b46d7Szhanghch05     softwareInterfaceAdded(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24859d494eeSPatrick Williams                            sdbusplus::message_t& m, task::Payload&& payload)
24986adcd6dSAndrew Geissler {
25080f79a40SMichael Shen     dbus::utility::DBusInterfacesMap interfacesProperties;
25186adcd6dSAndrew Geissler 
25286adcd6dSAndrew Geissler     sdbusplus::message::object_path objPath;
25386adcd6dSAndrew Geissler 
25486adcd6dSAndrew Geissler     m.read(objPath, interfacesProperties);
25586adcd6dSAndrew Geissler 
25662598e31SEd Tanous     BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
257e3eb3d63SEd Tanous     for (const auto& interface : interfacesProperties)
25886adcd6dSAndrew Geissler     {
25962598e31SEd Tanous         BMCWEB_LOG_DEBUG("interface = {}", interface.first);
26086adcd6dSAndrew Geissler 
26186adcd6dSAndrew Geissler         if (interface.first == "xyz.openbmc_project.Software.Activation")
26286adcd6dSAndrew Geissler         {
26386adcd6dSAndrew Geissler             // Retrieve service and activate
2642b73119cSGeorge Liu             constexpr std::array<std::string_view, 1> interfaces = {
2652b73119cSGeorge Liu                 "xyz.openbmc_project.Software.Activation"};
2662b73119cSGeorge Liu             dbus::utility::getDbusObject(
2672b73119cSGeorge Liu                 objPath.str, interfaces,
268a3e65892SEd Tanous                 [objPath, asyncResp, payload(std::move(payload))](
2698b24275dSEd Tanous                     const boost::system::error_code& ec,
270a3e65892SEd Tanous                     const std::vector<
271a3e65892SEd Tanous                         std::pair<std::string, std::vector<std::string>>>&
272a3e65892SEd Tanous                         objInfo) mutable {
2738b24275dSEd Tanous                 if (ec)
27486adcd6dSAndrew Geissler                 {
27562598e31SEd Tanous                     BMCWEB_LOG_DEBUG("error_code = {}", ec);
27662598e31SEd Tanous                     BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
2770554c984SAndrew Geissler                     if (asyncResp)
2780554c984SAndrew Geissler                     {
27986adcd6dSAndrew Geissler                         messages::internalError(asyncResp->res);
2800554c984SAndrew Geissler                     }
28186adcd6dSAndrew Geissler                     cleanUp();
28286adcd6dSAndrew Geissler                     return;
28386adcd6dSAndrew Geissler                 }
28486adcd6dSAndrew Geissler                 // Ensure we only got one service back
28586adcd6dSAndrew Geissler                 if (objInfo.size() != 1)
28686adcd6dSAndrew Geissler                 {
28762598e31SEd Tanous                     BMCWEB_LOG_ERROR("Invalid Object Size {}", objInfo.size());
2880554c984SAndrew Geissler                     if (asyncResp)
2890554c984SAndrew Geissler                     {
29086adcd6dSAndrew Geissler                         messages::internalError(asyncResp->res);
2910554c984SAndrew Geissler                     }
29286adcd6dSAndrew Geissler                     cleanUp();
29386adcd6dSAndrew Geissler                     return;
29486adcd6dSAndrew Geissler                 }
29586adcd6dSAndrew Geissler                 // cancel timer only when
29686adcd6dSAndrew Geissler                 // xyz.openbmc_project.Software.Activation interface
29786adcd6dSAndrew Geissler                 // is added
29886adcd6dSAndrew Geissler                 fwAvailableTimer = nullptr;
29986adcd6dSAndrew Geissler 
30086adcd6dSAndrew Geissler                 activateImage(objPath.str, objInfo[0].first);
3010554c984SAndrew Geissler                 if (asyncResp)
3020554c984SAndrew Geissler                 {
303c71b6c99SJagpal Singh Gill                     createTask(asyncResp, std::move(payload), objPath);
3040554c984SAndrew Geissler                 }
30586adcd6dSAndrew Geissler                 fwUpdateInProgress = false;
3062b73119cSGeorge Liu             });
30762bafc01SPatrick Williams 
30862bafc01SPatrick Williams             break;
30986adcd6dSAndrew Geissler         }
31086adcd6dSAndrew Geissler     }
31186adcd6dSAndrew Geissler }
31286adcd6dSAndrew Geissler 
3138549b951SMyung Bae inline void afterAvailbleTimerAsyncWait(
3148549b951SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3158549b951SMyung Bae     const boost::system::error_code& ec)
3168549b951SMyung Bae {
3178549b951SMyung Bae     cleanUp();
3188549b951SMyung Bae     if (ec == boost::asio::error::operation_aborted)
3198549b951SMyung Bae     {
3208549b951SMyung Bae         // expected, we were canceled before the timer completed.
3218549b951SMyung Bae         return;
3228549b951SMyung Bae     }
3238549b951SMyung Bae     BMCWEB_LOG_ERROR("Timed out waiting for firmware object being created");
3248549b951SMyung Bae     BMCWEB_LOG_ERROR("FW image may has already been uploaded to server");
3258549b951SMyung Bae     if (ec)
3268549b951SMyung Bae     {
3278549b951SMyung Bae         BMCWEB_LOG_ERROR("Async_wait failed{}", ec);
3288549b951SMyung Bae         return;
3298549b951SMyung Bae     }
3308549b951SMyung Bae     if (asyncResp)
3318549b951SMyung Bae     {
3328549b951SMyung Bae         redfish::messages::internalError(asyncResp->res);
3338549b951SMyung Bae     }
3348549b951SMyung Bae }
3358549b951SMyung Bae 
3368549b951SMyung Bae inline void
3378549b951SMyung Bae     handleUpdateErrorType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3388549b951SMyung Bae                           const std::string& url, const std::string& type)
3398549b951SMyung Bae {
3408549b951SMyung Bae     if (type == "xyz.openbmc_project.Software.Image.Error.UnTarFailure")
3418549b951SMyung Bae     {
3428549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3438549b951SMyung Bae                                          "Invalid archive");
3448549b951SMyung Bae     }
3458549b951SMyung Bae     else if (type ==
3468549b951SMyung Bae              "xyz.openbmc_project.Software.Image.Error.ManifestFileFailure")
3478549b951SMyung Bae     {
3488549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3498549b951SMyung Bae                                          "Invalid manifest");
3508549b951SMyung Bae     }
3518549b951SMyung Bae     else if (type == "xyz.openbmc_project.Software.Image.Error.ImageFailure")
3528549b951SMyung Bae     {
3538549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3548549b951SMyung Bae                                          "Invalid image format");
3558549b951SMyung Bae     }
3568549b951SMyung Bae     else if (type == "xyz.openbmc_project.Software.Version.Error.AlreadyExists")
3578549b951SMyung Bae     {
3588549b951SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3598549b951SMyung Bae                                          "Image version already exists");
3608549b951SMyung Bae 
3618549b951SMyung Bae         redfish::messages::resourceAlreadyExists(
3628549b951SMyung Bae             asyncResp->res, "UpdateService", "Version", "uploaded version");
3638549b951SMyung Bae     }
3648549b951SMyung Bae     else if (type == "xyz.openbmc_project.Software.Image.Error.BusyFailure")
3658549b951SMyung Bae     {
3668549b951SMyung Bae         redfish::messages::resourceExhaustion(asyncResp->res, url);
3678549b951SMyung Bae     }
3684034a652SMyung Bae     else if (type == "xyz.openbmc_project.Software.Version.Error.Incompatible")
3698549b951SMyung Bae     {
3704034a652SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3714034a652SMyung Bae                                          "Incompatible image version");
3724034a652SMyung Bae     }
3734034a652SMyung Bae     else if (type ==
3744034a652SMyung Bae              "xyz.openbmc_project.Software.Version.Error.ExpiredAccessKey")
3754034a652SMyung Bae     {
3764034a652SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3774034a652SMyung Bae                                          "Update Access Key Expired");
3784034a652SMyung Bae     }
3794034a652SMyung Bae     else if (type ==
3804034a652SMyung Bae              "xyz.openbmc_project.Software.Version.Error.InvalidSignature")
3814034a652SMyung Bae     {
3824034a652SMyung Bae         redfish::messages::invalidUpload(asyncResp->res, url,
3834034a652SMyung Bae                                          "Invalid image signature");
3844034a652SMyung Bae     }
3854034a652SMyung Bae     else if (type ==
3864034a652SMyung Bae                  "xyz.openbmc_project.Software.Image.Error.InternalFailure" ||
3874034a652SMyung Bae              type == "xyz.openbmc_project.Software.Version.Error.HostFile")
3884034a652SMyung Bae     {
3894034a652SMyung Bae         BMCWEB_LOG_ERROR("Software Image Error type={}", type);
3908549b951SMyung Bae         redfish::messages::internalError(asyncResp->res);
3918549b951SMyung Bae     }
3924034a652SMyung Bae     else
3934034a652SMyung Bae     {
3944034a652SMyung Bae         // Unrelated error types. Ignored
3954034a652SMyung Bae         BMCWEB_LOG_INFO("Non-Software-related Error type={}. Ignored", type);
3964034a652SMyung Bae         return;
3974034a652SMyung Bae     }
3984034a652SMyung Bae     // Clear the timer
3994034a652SMyung Bae     fwAvailableTimer = nullptr;
4008549b951SMyung Bae }
4018549b951SMyung Bae 
4028549b951SMyung Bae inline void
4038549b951SMyung Bae     afterUpdateErrorMatcher(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4048549b951SMyung Bae                             const std::string& url, sdbusplus::message_t& m)
4058549b951SMyung Bae {
40680f79a40SMichael Shen     dbus::utility::DBusInterfacesMap interfacesProperties;
4078549b951SMyung Bae     sdbusplus::message::object_path objPath;
4088549b951SMyung Bae     m.read(objPath, interfacesProperties);
4098549b951SMyung Bae     BMCWEB_LOG_DEBUG("obj path = {}", objPath.str);
4108549b951SMyung Bae     for (const std::pair<std::string, dbus::utility::DBusPropertiesMap>&
4118549b951SMyung Bae              interface : interfacesProperties)
4128549b951SMyung Bae     {
4138549b951SMyung Bae         if (interface.first == "xyz.openbmc_project.Logging.Entry")
4148549b951SMyung Bae         {
4158549b951SMyung Bae             for (const std::pair<std::string, dbus::utility::DbusVariantType>&
4168549b951SMyung Bae                      value : interface.second)
4178549b951SMyung Bae             {
4188549b951SMyung Bae                 if (value.first != "Message")
4198549b951SMyung Bae                 {
4208549b951SMyung Bae                     continue;
4218549b951SMyung Bae                 }
4228549b951SMyung Bae                 const std::string* type =
4238549b951SMyung Bae                     std::get_if<std::string>(&value.second);
4248549b951SMyung Bae                 if (type == nullptr)
4258549b951SMyung Bae                 {
4268549b951SMyung Bae                     // if this was our message, timeout will cover it
4278549b951SMyung Bae                     return;
4288549b951SMyung Bae                 }
4298549b951SMyung Bae                 handleUpdateErrorType(asyncResp, url, *type);
4308549b951SMyung Bae             }
4318549b951SMyung Bae         }
4328549b951SMyung Bae     }
4338549b951SMyung Bae }
4348549b951SMyung Bae 
4350554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
4360554c984SAndrew Geissler // then no asyncResp updates will occur
437f5139334SEd Tanous inline void monitorForSoftwareAvailable(
4388d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4398d1b46d7Szhanghch05     const crow::Request& req, const std::string& url,
4405d138943SGunnar Mills     int timeoutTimeSeconds = 25)
44186adcd6dSAndrew Geissler {
44286adcd6dSAndrew Geissler     // Only allow one FW update at a time
443e05aec50SEd Tanous     if (fwUpdateInProgress)
44486adcd6dSAndrew Geissler     {
4450554c984SAndrew Geissler         if (asyncResp)
4460554c984SAndrew Geissler         {
44786adcd6dSAndrew Geissler             messages::serviceTemporarilyUnavailable(asyncResp->res, "30");
4480554c984SAndrew Geissler         }
44986adcd6dSAndrew Geissler         return;
45086adcd6dSAndrew Geissler     }
45186adcd6dSAndrew Geissler 
4528e8245dbSEd Tanous     if (req.ioService == nullptr)
4538e8245dbSEd Tanous     {
4548e8245dbSEd Tanous         messages::internalError(asyncResp->res);
4558e8245dbSEd Tanous         return;
4568e8245dbSEd Tanous     }
4578e8245dbSEd Tanous 
4580554c984SAndrew Geissler     fwAvailableTimer =
459271584abSEd Tanous         std::make_unique<boost::asio::steady_timer>(*req.ioService);
46086adcd6dSAndrew Geissler 
461271584abSEd Tanous     fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds));
46286adcd6dSAndrew Geissler 
46386adcd6dSAndrew Geissler     fwAvailableTimer->async_wait(
4648549b951SMyung Bae         std::bind_front(afterAvailbleTimerAsyncWait, asyncResp));
4658549b951SMyung Bae 
466a3e65892SEd Tanous     task::Payload payload(req);
46759d494eeSPatrick Williams     auto callback = [asyncResp, payload](sdbusplus::message_t& m) mutable {
46862598e31SEd Tanous         BMCWEB_LOG_DEBUG("Match fired");
469a3e65892SEd Tanous         softwareInterfaceAdded(asyncResp, m, std::move(payload));
47086adcd6dSAndrew Geissler     };
47186adcd6dSAndrew Geissler 
47286adcd6dSAndrew Geissler     fwUpdateInProgress = true;
47386adcd6dSAndrew Geissler 
47459d494eeSPatrick Williams     fwUpdateMatcher = std::make_unique<sdbusplus::bus::match_t>(
47586adcd6dSAndrew Geissler         *crow::connections::systemBus,
47686adcd6dSAndrew Geissler         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
47786adcd6dSAndrew Geissler         "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
47886adcd6dSAndrew Geissler         callback);
4794cde5d90SJames Feist 
48059d494eeSPatrick Williams     fwUpdateErrorMatcher = std::make_unique<sdbusplus::bus::match_t>(
4814cde5d90SJames Feist         *crow::connections::systemBus,
482e1cc4828SBrian Ma         "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
483e1cc4828SBrian Ma         "member='InterfacesAdded',"
484e1cc4828SBrian Ma         "path='/xyz/openbmc_project/logging'",
4858549b951SMyung Bae         std::bind_front(afterUpdateErrorMatcher, asyncResp, url));
48686adcd6dSAndrew Geissler }
487729dae72SJennifer Lee 
488757178a5SEd Tanous inline std::optional<boost::urls::url>
489757178a5SEd Tanous     parseSimpleUpdateUrl(std::string imageURI,
490f86bcc87SEd Tanous                          std::optional<std::string> transferProtocol,
491f86bcc87SEd Tanous                          crow::Response& res)
492f86bcc87SEd Tanous {
493f86bcc87SEd Tanous     if (imageURI.find("://") == std::string::npos)
494f86bcc87SEd Tanous     {
495f86bcc87SEd Tanous         if (imageURI.starts_with("/"))
496f86bcc87SEd Tanous         {
497f86bcc87SEd Tanous             messages::actionParameterValueTypeError(
498f86bcc87SEd Tanous                 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
499f86bcc87SEd Tanous             return std::nullopt;
500f86bcc87SEd Tanous         }
501f86bcc87SEd Tanous         if (!transferProtocol)
502f86bcc87SEd Tanous         {
503f86bcc87SEd Tanous             messages::actionParameterValueTypeError(
504f86bcc87SEd Tanous                 res, imageURI, "ImageURI", "UpdateService.SimpleUpdate");
505f86bcc87SEd Tanous             return std::nullopt;
506f86bcc87SEd Tanous         }
507e5cf777eSEd Tanous         // OpenBMC currently only supports TFTP or HTTPS
508757178a5SEd Tanous         if (*transferProtocol == "TFTP")
509757178a5SEd Tanous         {
510757178a5SEd Tanous             imageURI = "tftp://" + imageURI;
511757178a5SEd Tanous         }
512e5cf777eSEd Tanous         else if (*transferProtocol == "HTTPS")
513e5cf777eSEd Tanous         {
514e5cf777eSEd Tanous             imageURI = "https://" + imageURI;
515e5cf777eSEd Tanous         }
516757178a5SEd Tanous         else
517f86bcc87SEd Tanous         {
518f86bcc87SEd Tanous             messages::actionParameterNotSupported(res, "TransferProtocol",
519f86bcc87SEd Tanous                                                   *transferProtocol);
520f86bcc87SEd Tanous             BMCWEB_LOG_ERROR("Request incorrect protocol parameter: {}",
521f86bcc87SEd Tanous                              *transferProtocol);
522f86bcc87SEd Tanous             return std::nullopt;
523f86bcc87SEd Tanous         }
524f86bcc87SEd Tanous     }
525f86bcc87SEd Tanous 
526f86bcc87SEd Tanous     boost::system::result<boost::urls::url> url =
527f86bcc87SEd Tanous         boost::urls::parse_absolute_uri(imageURI);
528f86bcc87SEd Tanous     if (!url)
529f86bcc87SEd Tanous     {
530f86bcc87SEd Tanous         messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
531f86bcc87SEd Tanous                                                 "UpdateService.SimpleUpdate");
532f86bcc87SEd Tanous 
533f86bcc87SEd Tanous         return std::nullopt;
534f86bcc87SEd Tanous     }
535f86bcc87SEd Tanous     url->normalize();
536f86bcc87SEd Tanous 
537757178a5SEd Tanous     if (url->scheme() == "tftp")
538757178a5SEd Tanous     {
539757178a5SEd Tanous         if (url->encoded_path().size() < 2)
540757178a5SEd Tanous         {
541757178a5SEd Tanous             messages::actionParameterNotSupported(res, "ImageURI",
542757178a5SEd Tanous                                                   url->buffer());
543757178a5SEd Tanous             return std::nullopt;
544757178a5SEd Tanous         }
545757178a5SEd Tanous     }
546e5cf777eSEd Tanous     else if (url->scheme() == "https")
547e5cf777eSEd Tanous     {
548e5cf777eSEd Tanous         // Empty paths default to "/"
549e5cf777eSEd Tanous         if (url->encoded_path().empty())
550e5cf777eSEd Tanous         {
551e5cf777eSEd Tanous             url->set_encoded_path("/");
552e5cf777eSEd Tanous         }
553e5cf777eSEd Tanous     }
554757178a5SEd Tanous     else
555f86bcc87SEd Tanous     {
556f86bcc87SEd Tanous         messages::actionParameterNotSupported(res, "ImageURI", imageURI);
557f86bcc87SEd Tanous         return std::nullopt;
558f86bcc87SEd Tanous     }
559757178a5SEd Tanous 
560757178a5SEd Tanous     if (url->encoded_path().empty())
561f86bcc87SEd Tanous     {
562757178a5SEd Tanous         messages::actionParameterValueTypeError(res, imageURI, "ImageURI",
563757178a5SEd Tanous                                                 "UpdateService.SimpleUpdate");
564f86bcc87SEd Tanous         return std::nullopt;
565f86bcc87SEd Tanous     }
566757178a5SEd Tanous 
567757178a5SEd Tanous     return *url;
568f86bcc87SEd Tanous }
569f86bcc87SEd Tanous 
570e5cf777eSEd Tanous inline void doHttpsUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
571e5cf777eSEd Tanous                           const boost::urls::url_view_base& url)
572e5cf777eSEd Tanous {
573e5cf777eSEd Tanous     messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
574e5cf777eSEd Tanous                                           url.buffer());
575e5cf777eSEd Tanous }
576e5cf777eSEd Tanous 
5776b0f66bdSEd Tanous inline void doTftpUpdate(const crow::Request& req,
5786b0f66bdSEd Tanous                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
579757178a5SEd Tanous                          const boost::urls::url_view_base& url)
5806b0f66bdSEd Tanous {
581c72503f3SEd Tanous     if (!BMCWEB_INSECURE_TFTP_UPDATE)
582c72503f3SEd Tanous     {
5836b0f66bdSEd Tanous         messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
584757178a5SEd Tanous                                               url.buffer());
5856b0f66bdSEd Tanous         return;
586c72503f3SEd Tanous     }
587757178a5SEd Tanous 
588757178a5SEd Tanous     std::string path(url.encoded_path());
589757178a5SEd Tanous     if (path.size() < 2)
590757178a5SEd Tanous     {
591757178a5SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
592757178a5SEd Tanous                                               url.buffer());
593757178a5SEd Tanous         return;
594757178a5SEd Tanous     }
595757178a5SEd Tanous     // TFTP expects a path without a /
596757178a5SEd Tanous     path.erase(0, 1);
597757178a5SEd Tanous     std::string host(url.encoded_host_and_port());
598757178a5SEd Tanous     BMCWEB_LOG_DEBUG("Server: {} File: {}", host, path);
5996b0f66bdSEd Tanous 
6006b0f66bdSEd Tanous     // Setup callback for when new software detected
6016b0f66bdSEd Tanous     // Give TFTP 10 minutes to complete
6026b0f66bdSEd Tanous     monitorForSoftwareAvailable(
6036b0f66bdSEd Tanous         asyncResp, req,
6046b0f66bdSEd Tanous         "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate", 600);
6056b0f66bdSEd Tanous 
6066b0f66bdSEd Tanous     // TFTP can take up to 10 minutes depending on image size and
6076b0f66bdSEd Tanous     // connection speed. Return to caller as soon as the TFTP operation
6086b0f66bdSEd Tanous     // has been started. The callback above will ensure the activate
6096b0f66bdSEd Tanous     // is started once the download has completed
6106b0f66bdSEd Tanous     redfish::messages::success(asyncResp->res);
6116b0f66bdSEd Tanous 
6126b0f66bdSEd Tanous     // Call TFTP service
6136b0f66bdSEd Tanous     crow::connections::systemBus->async_method_call(
6146b0f66bdSEd Tanous         [](const boost::system::error_code& ec) {
6156b0f66bdSEd Tanous         if (ec)
6166b0f66bdSEd Tanous         {
6176b0f66bdSEd Tanous             // messages::internalError(asyncResp->res);
6186b0f66bdSEd Tanous             cleanUp();
6196b0f66bdSEd Tanous             BMCWEB_LOG_DEBUG("error_code = {}", ec);
6206b0f66bdSEd Tanous             BMCWEB_LOG_DEBUG("error msg = {}", ec.message());
6216b0f66bdSEd Tanous         }
6226b0f66bdSEd Tanous         else
6236b0f66bdSEd Tanous         {
6246b0f66bdSEd Tanous             BMCWEB_LOG_DEBUG("Call to DownloaViaTFTP Success");
6256b0f66bdSEd Tanous         }
6266b0f66bdSEd Tanous     },
6276b0f66bdSEd Tanous         "xyz.openbmc_project.Software.Download",
6286b0f66bdSEd Tanous         "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP",
629757178a5SEd Tanous         "DownloadViaTFTP", path, host);
6306b0f66bdSEd Tanous }
6316b0f66bdSEd Tanous 
632f5139334SEd Tanous inline void handleUpdateServiceSimpleUpdateAction(
633f5139334SEd Tanous     crow::App& app, const crow::Request& req,
634f5139334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
6350554c984SAndrew Geissler {
6363ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
63745ca1b86SEd Tanous     {
63845ca1b86SEd Tanous         return;
63945ca1b86SEd Tanous     }
64045ca1b86SEd Tanous 
6410554c984SAndrew Geissler     std::optional<std::string> transferProtocol;
6420554c984SAndrew Geissler     std::string imageURI;
6430554c984SAndrew Geissler 
64462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Enter UpdateService.SimpleUpdate doPost");
6450554c984SAndrew Geissler 
6460554c984SAndrew Geissler     // User can pass in both TransferProtocol and ImageURI parameters or
6474e0453b1SGunnar Mills     // they can pass in just the ImageURI with the transfer protocol
6484e0453b1SGunnar Mills     // embedded within it.
6490554c984SAndrew Geissler     // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin
6500554c984SAndrew Geissler     // 2) ImageURI:tftp://1.1.1.1/myfile.bin
6510554c984SAndrew Geissler 
652002d39b4SEd Tanous     if (!json_util::readJsonAction(req, asyncResp->res, "TransferProtocol",
653002d39b4SEd Tanous                                    transferProtocol, "ImageURI", imageURI))
6540554c984SAndrew Geissler     {
65562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Missing TransferProtocol or ImageURI parameter");
6560554c984SAndrew Geissler         return;
6570554c984SAndrew Geissler     }
658f5139334SEd Tanous 
659757178a5SEd Tanous     std::optional<boost::urls::url> url =
660757178a5SEd Tanous         parseSimpleUpdateUrl(imageURI, transferProtocol, asyncResp->res);
661757178a5SEd Tanous     if (!url)
6620554c984SAndrew Geissler     {
6630554c984SAndrew Geissler         return;
6640554c984SAndrew Geissler     }
665757178a5SEd Tanous     if (url->scheme() == "tftp")
666757178a5SEd Tanous     {
667757178a5SEd Tanous         doTftpUpdate(req, asyncResp, *url);
668757178a5SEd Tanous     }
669e5cf777eSEd Tanous     else if (url->scheme() == "https")
670e5cf777eSEd Tanous     {
671e5cf777eSEd Tanous         doHttpsUpdate(asyncResp, *url);
672e5cf777eSEd Tanous     }
673757178a5SEd Tanous     else
674757178a5SEd Tanous     {
675757178a5SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, "ImageURI",
676757178a5SEd Tanous                                               url->buffer());
677757178a5SEd Tanous         return;
678757178a5SEd Tanous     }
6790554c984SAndrew Geissler 
68062598e31SEd Tanous     BMCWEB_LOG_DEBUG("Exit UpdateService.SimpleUpdate doPost");
681729dae72SJennifer Lee }
682729dae72SJennifer Lee 
6830ed80c8cSGeorge Liu inline void uploadImageFile(crow::Response& res, std::string_view body)
6840ed80c8cSGeorge Liu {
6852c6ffdb0SEd Tanous     std::filesystem::path filepath("/tmp/images/" + bmcweb::getRandomUUID());
6862c6ffdb0SEd Tanous 
68762598e31SEd Tanous     BMCWEB_LOG_DEBUG("Writing file to {}", filepath.string());
6880ed80c8cSGeorge Liu     std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
6890ed80c8cSGeorge Liu                                     std::ofstream::trunc);
6900ed80c8cSGeorge Liu     // set the permission of the file to 640
69189492a15SPatrick Williams     std::filesystem::perms permission = std::filesystem::perms::owner_read |
69289492a15SPatrick Williams                                         std::filesystem::perms::group_read;
6930ed80c8cSGeorge Liu     std::filesystem::permissions(filepath, permission);
6940ed80c8cSGeorge Liu     out << body;
6950ed80c8cSGeorge Liu 
6960ed80c8cSGeorge Liu     if (out.bad())
6970ed80c8cSGeorge Liu     {
6980ed80c8cSGeorge Liu         messages::internalError(res);
6990ed80c8cSGeorge Liu         cleanUp();
7000ed80c8cSGeorge Liu     }
7010ed80c8cSGeorge Liu }
7020ed80c8cSGeorge Liu 
703*de0c960cSJagpal Singh Gill // Convert the Request Apply Time to the D-Bus value
704*de0c960cSJagpal Singh Gill inline bool convertApplyTime(crow::Response& res, const std::string& applyTime,
705*de0c960cSJagpal Singh Gill                              std::string& applyTimeNewVal)
706*de0c960cSJagpal Singh Gill {
707*de0c960cSJagpal Singh Gill     if (applyTime == "Immediate")
708*de0c960cSJagpal Singh Gill     {
709*de0c960cSJagpal Singh Gill         applyTimeNewVal =
710*de0c960cSJagpal Singh Gill             "xyz.openbmc_project.Software.Update.ApplyTimes.Immediate";
711*de0c960cSJagpal Singh Gill     }
712*de0c960cSJagpal Singh Gill     else if (applyTime == "OnReset")
713*de0c960cSJagpal Singh Gill     {
714*de0c960cSJagpal Singh Gill         applyTimeNewVal =
715*de0c960cSJagpal Singh Gill             "xyz.openbmc_project.Software.Update.ApplyTimes.OnReset";
716*de0c960cSJagpal Singh Gill     }
717*de0c960cSJagpal Singh Gill     else
718*de0c960cSJagpal Singh Gill     {
719*de0c960cSJagpal Singh Gill         BMCWEB_LOG_WARNING(
720*de0c960cSJagpal Singh Gill             "ApplyTime value {} is not in the list of acceptable values",
721*de0c960cSJagpal Singh Gill             applyTime);
722*de0c960cSJagpal Singh Gill         messages::propertyValueNotInList(res, applyTime, "ApplyTime");
723*de0c960cSJagpal Singh Gill         return false;
724*de0c960cSJagpal Singh Gill     }
725*de0c960cSJagpal Singh Gill     return true;
726*de0c960cSJagpal Singh Gill }
727*de0c960cSJagpal Singh Gill 
7280ed80c8cSGeorge Liu inline void setApplyTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7290ed80c8cSGeorge Liu                          const std::string& applyTime)
7300ed80c8cSGeorge Liu {
7310ed80c8cSGeorge Liu     std::string applyTimeNewVal;
7320ed80c8cSGeorge Liu     if (applyTime == "Immediate")
7330ed80c8cSGeorge Liu     {
7340ed80c8cSGeorge Liu         applyTimeNewVal =
7350ed80c8cSGeorge Liu             "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.Immediate";
7360ed80c8cSGeorge Liu     }
7370ed80c8cSGeorge Liu     else if (applyTime == "OnReset")
7380ed80c8cSGeorge Liu     {
7390ed80c8cSGeorge Liu         applyTimeNewVal =
7400ed80c8cSGeorge Liu             "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
7410ed80c8cSGeorge Liu     }
7420ed80c8cSGeorge Liu     else
7430ed80c8cSGeorge Liu     {
74462598e31SEd Tanous         BMCWEB_LOG_INFO(
74562598e31SEd Tanous             "ApplyTime value is not in the list of acceptable values");
7460ed80c8cSGeorge Liu         messages::propertyValueNotInList(asyncResp->res, applyTime,
7470ed80c8cSGeorge Liu                                          "ApplyTime");
7480ed80c8cSGeorge Liu         return;
7490ed80c8cSGeorge Liu     }
7500ed80c8cSGeorge Liu 
751d02aad39SEd Tanous     setDbusProperty(asyncResp, "xyz.openbmc_project.Settings",
752d02aad39SEd Tanous                     sdbusplus::message::object_path(
753d02aad39SEd Tanous                         "/xyz/openbmc_project/software/apply_time"),
754d02aad39SEd Tanous                     "xyz.openbmc_project.Software.ApplyTime",
755d02aad39SEd Tanous                     "RequestedApplyTime", "ApplyTime", applyTimeNewVal);
7560ed80c8cSGeorge Liu }
7570ed80c8cSGeorge Liu 
758ef93eab3SJagpal Singh Gill struct MultiPartUpdateParameters
7590ed80c8cSGeorge Liu {
760ef93eab3SJagpal Singh Gill     std::optional<std::string> applyTime;
761ef93eab3SJagpal Singh Gill     std::string uploadData;
762*de0c960cSJagpal Singh Gill     std::vector<std::string> targets;
763ef93eab3SJagpal Singh Gill };
764ef93eab3SJagpal Singh Gill 
765*de0c960cSJagpal Singh Gill inline std::optional<std::string>
766*de0c960cSJagpal Singh Gill     processUrl(boost::system::result<boost::urls::url_view>& url)
767*de0c960cSJagpal Singh Gill {
768*de0c960cSJagpal Singh Gill     if (!url)
769*de0c960cSJagpal Singh Gill     {
770*de0c960cSJagpal Singh Gill         return std::nullopt;
771*de0c960cSJagpal Singh Gill     }
772*de0c960cSJagpal Singh Gill     if (crow::utility::readUrlSegments(*url, "redfish", "v1", "Managers",
773*de0c960cSJagpal Singh Gill                                        BMCWEB_REDFISH_MANAGER_URI_NAME))
774*de0c960cSJagpal Singh Gill     {
775*de0c960cSJagpal Singh Gill         return std::make_optional(std::string(BMCWEB_REDFISH_MANAGER_URI_NAME));
776*de0c960cSJagpal Singh Gill     }
777*de0c960cSJagpal Singh Gill     if constexpr (!BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
778*de0c960cSJagpal Singh Gill     {
779*de0c960cSJagpal Singh Gill         return std::nullopt;
780*de0c960cSJagpal Singh Gill     }
781*de0c960cSJagpal Singh Gill     std::string firmwareId;
782*de0c960cSJagpal Singh Gill     if (!crow::utility::readUrlSegments(*url, "redfish", "v1", "UpdateService",
783*de0c960cSJagpal Singh Gill                                         "FirmwareInventory",
784*de0c960cSJagpal Singh Gill                                         std::ref(firmwareId)))
785*de0c960cSJagpal Singh Gill     {
786*de0c960cSJagpal Singh Gill         return std::nullopt;
787*de0c960cSJagpal Singh Gill     }
788*de0c960cSJagpal Singh Gill 
789*de0c960cSJagpal Singh Gill     return std::make_optional(firmwareId);
790*de0c960cSJagpal Singh Gill }
791*de0c960cSJagpal Singh Gill 
792ef93eab3SJagpal Singh Gill inline std::optional<MultiPartUpdateParameters>
793ef93eab3SJagpal Singh Gill     extractMultipartUpdateParameters(
794ef93eab3SJagpal Singh Gill         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
795ef93eab3SJagpal Singh Gill         MultipartParser parser)
796ef93eab3SJagpal Singh Gill {
797ef93eab3SJagpal Singh Gill     MultiPartUpdateParameters multiRet;
798ef93eab3SJagpal Singh Gill     for (FormPart& formpart : parser.mime_fields)
7990ed80c8cSGeorge Liu     {
8000ed80c8cSGeorge Liu         boost::beast::http::fields::const_iterator it =
8010ed80c8cSGeorge Liu             formpart.fields.find("Content-Disposition");
8020ed80c8cSGeorge Liu         if (it == formpart.fields.end())
8030ed80c8cSGeorge Liu         {
80462598e31SEd Tanous             BMCWEB_LOG_ERROR("Couldn't find Content-Disposition");
805ef93eab3SJagpal Singh Gill             return std::nullopt;
8060ed80c8cSGeorge Liu         }
80762598e31SEd Tanous         BMCWEB_LOG_INFO("Parsing value {}", it->value());
8080ed80c8cSGeorge Liu 
8090ed80c8cSGeorge Liu         // The construction parameters of param_list must start with `;`
8100ed80c8cSGeorge Liu         size_t index = it->value().find(';');
8110ed80c8cSGeorge Liu         if (index == std::string::npos)
8120ed80c8cSGeorge Liu         {
8130ed80c8cSGeorge Liu             continue;
8140ed80c8cSGeorge Liu         }
8150ed80c8cSGeorge Liu 
81689492a15SPatrick Williams         for (const auto& param :
8170ed80c8cSGeorge Liu              boost::beast::http::param_list{it->value().substr(index)})
8180ed80c8cSGeorge Liu         {
8190ed80c8cSGeorge Liu             if (param.first != "name" || param.second.empty())
8200ed80c8cSGeorge Liu             {
8210ed80c8cSGeorge Liu                 continue;
8220ed80c8cSGeorge Liu             }
8230ed80c8cSGeorge Liu 
8240ed80c8cSGeorge Liu             if (param.second == "UpdateParameters")
8250ed80c8cSGeorge Liu             {
826ef93eab3SJagpal Singh Gill                 std::vector<std::string> tempTargets;
8270ed80c8cSGeorge Liu                 nlohmann::json content =
8280ed80c8cSGeorge Liu                     nlohmann::json::parse(formpart.content);
8297cb59f65SEd Tanous                 nlohmann::json::object_t* obj =
8307cb59f65SEd Tanous                     content.get_ptr<nlohmann::json::object_t*>();
8317cb59f65SEd Tanous                 if (obj == nullptr)
8327cb59f65SEd Tanous                 {
833ef93eab3SJagpal Singh Gill                     messages::propertyValueTypeError(
834ef93eab3SJagpal Singh Gill                         asyncResp->res, formpart.content, "UpdateParameters");
835ef93eab3SJagpal Singh Gill                     return std::nullopt;
8367cb59f65SEd Tanous                 }
8377cb59f65SEd Tanous 
8387cb59f65SEd Tanous                 if (!json_util::readJsonObject(
839ef93eab3SJagpal Singh Gill                         *obj, asyncResp->res, "Targets", tempTargets,
840ef93eab3SJagpal Singh Gill                         "@Redfish.OperationApplyTime", multiRet.applyTime))
8410ed80c8cSGeorge Liu                 {
842ef93eab3SJagpal Singh Gill                     return std::nullopt;
8430ed80c8cSGeorge Liu                 }
844ef93eab3SJagpal Singh Gill 
845ef93eab3SJagpal Singh Gill                 for (size_t urlIndex = 0; urlIndex < tempTargets.size();
846ef93eab3SJagpal Singh Gill                      urlIndex++)
8470ed80c8cSGeorge Liu                 {
848ef93eab3SJagpal Singh Gill                     const std::string& target = tempTargets[urlIndex];
849ef93eab3SJagpal Singh Gill                     boost::system::result<boost::urls::url_view> url =
850ef93eab3SJagpal Singh Gill                         boost::urls::parse_origin_form(target);
851*de0c960cSJagpal Singh Gill                     auto res = processUrl(url);
852*de0c960cSJagpal Singh Gill                     if (!res.has_value())
8530ed80c8cSGeorge Liu                     {
854ef93eab3SJagpal Singh Gill                         messages::propertyValueFormatError(
855ef93eab3SJagpal Singh Gill                             asyncResp->res, target,
856ef93eab3SJagpal Singh Gill                             std::format("Targets/{}", urlIndex));
857ef93eab3SJagpal Singh Gill                         return std::nullopt;
8580ed80c8cSGeorge Liu                     }
859*de0c960cSJagpal Singh Gill                     multiRet.targets.emplace_back(res.value());
860ef93eab3SJagpal Singh Gill                 }
861ef93eab3SJagpal Singh Gill                 if (multiRet.targets.size() != 1)
862ef93eab3SJagpal Singh Gill                 {
863ef93eab3SJagpal Singh Gill                     messages::propertyValueFormatError(
864ef93eab3SJagpal Singh Gill                         asyncResp->res, multiRet.targets, "Targets");
865ef93eab3SJagpal Singh Gill                     return std::nullopt;
866ef93eab3SJagpal Singh Gill                 }
8670ed80c8cSGeorge Liu             }
8680ed80c8cSGeorge Liu             else if (param.second == "UpdateFile")
8690ed80c8cSGeorge Liu             {
870ef93eab3SJagpal Singh Gill                 multiRet.uploadData = std::move(formpart.content);
8710ed80c8cSGeorge Liu             }
8720ed80c8cSGeorge Liu         }
8730ed80c8cSGeorge Liu     }
8740ed80c8cSGeorge Liu 
875ef93eab3SJagpal Singh Gill     if (multiRet.uploadData.empty())
8760ed80c8cSGeorge Liu     {
87762598e31SEd Tanous         BMCWEB_LOG_ERROR("Upload data is NULL");
8780ed80c8cSGeorge Liu         messages::propertyMissing(asyncResp->res, "UpdateFile");
879ef93eab3SJagpal Singh Gill         return std::nullopt;
8800ed80c8cSGeorge Liu     }
881ef93eab3SJagpal Singh Gill     if (multiRet.targets.empty())
8820ed80c8cSGeorge Liu     {
883ef93eab3SJagpal Singh Gill         messages::propertyMissing(asyncResp->res, "Targets");
884ef93eab3SJagpal Singh Gill         return std::nullopt;
885ef93eab3SJagpal Singh Gill     }
886ef93eab3SJagpal Singh Gill     return multiRet;
8870ed80c8cSGeorge Liu }
8880ed80c8cSGeorge Liu 
889ef93eab3SJagpal Singh Gill inline void
890*de0c960cSJagpal Singh Gill     handleStartUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
891*de0c960cSJagpal Singh Gill                       task::Payload payload, const std::string& objectPath,
892*de0c960cSJagpal Singh Gill                       const boost::system::error_code& ec,
893*de0c960cSJagpal Singh Gill                       const sdbusplus::message::object_path& retPath)
894*de0c960cSJagpal Singh Gill {
895*de0c960cSJagpal Singh Gill     if (ec)
896*de0c960cSJagpal Singh Gill     {
897*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("error_code = {}", ec);
898*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
899*de0c960cSJagpal Singh Gill         messages::internalError(asyncResp->res);
900*de0c960cSJagpal Singh Gill         return;
901*de0c960cSJagpal Singh Gill     }
902*de0c960cSJagpal Singh Gill 
903*de0c960cSJagpal Singh Gill     BMCWEB_LOG_INFO("Call to StartUpdate Success, retPath = {}", retPath.str);
904*de0c960cSJagpal Singh Gill     createTask(asyncResp, std::move(payload), objectPath);
905*de0c960cSJagpal Singh Gill }
906*de0c960cSJagpal Singh Gill 
907*de0c960cSJagpal Singh Gill inline void startUpdate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
908*de0c960cSJagpal Singh Gill                         task::Payload payload,
909*de0c960cSJagpal Singh Gill                         const MemoryFileDescriptor& memfd,
910*de0c960cSJagpal Singh Gill                         const std::string& applyTime,
911*de0c960cSJagpal Singh Gill                         const std::string& objectPath,
912*de0c960cSJagpal Singh Gill                         const std::string& serviceName)
913*de0c960cSJagpal Singh Gill {
914*de0c960cSJagpal Singh Gill     crow::connections::systemBus->async_method_call(
915*de0c960cSJagpal Singh Gill         [asyncResp, payload = std::move(payload),
916*de0c960cSJagpal Singh Gill          objectPath](const boost::system::error_code& ec1,
917*de0c960cSJagpal Singh Gill                      const sdbusplus::message::object_path& retPath) mutable {
918*de0c960cSJagpal Singh Gill         handleStartUpdate(asyncResp, std::move(payload), objectPath, ec1,
919*de0c960cSJagpal Singh Gill                           retPath);
920*de0c960cSJagpal Singh Gill     },
921*de0c960cSJagpal Singh Gill         serviceName, objectPath, "xyz.openbmc_project.Software.Update",
922*de0c960cSJagpal Singh Gill         "StartUpdate", sdbusplus::message::unix_fd(memfd.fd), applyTime);
923*de0c960cSJagpal Singh Gill }
924*de0c960cSJagpal Singh Gill 
925*de0c960cSJagpal Singh Gill inline void getAssociatedUpdateInterface(
926*de0c960cSJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, task::Payload payload,
927*de0c960cSJagpal Singh Gill     const MemoryFileDescriptor& memfd, const std::string& applyTime,
928*de0c960cSJagpal Singh Gill     const boost::system::error_code& ec,
929*de0c960cSJagpal Singh Gill     const dbus::utility::MapperGetSubTreeResponse& subtree)
930*de0c960cSJagpal Singh Gill {
931*de0c960cSJagpal Singh Gill     if (ec)
932*de0c960cSJagpal Singh Gill     {
933*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("error_code = {}", ec);
934*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
935*de0c960cSJagpal Singh Gill         messages::internalError(asyncResp->res);
936*de0c960cSJagpal Singh Gill         return;
937*de0c960cSJagpal Singh Gill     }
938*de0c960cSJagpal Singh Gill     BMCWEB_LOG_DEBUG("Found {} startUpdate subtree paths", subtree.size());
939*de0c960cSJagpal Singh Gill 
940*de0c960cSJagpal Singh Gill     if (subtree.size() > 1)
941*de0c960cSJagpal Singh Gill     {
942*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("Found more than one startUpdate subtree paths");
943*de0c960cSJagpal Singh Gill         messages::internalError(asyncResp->res);
944*de0c960cSJagpal Singh Gill         return;
945*de0c960cSJagpal Singh Gill     }
946*de0c960cSJagpal Singh Gill 
947*de0c960cSJagpal Singh Gill     auto objectPath = subtree[0].first;
948*de0c960cSJagpal Singh Gill     auto serviceName = subtree[0].second[0].first;
949*de0c960cSJagpal Singh Gill 
950*de0c960cSJagpal Singh Gill     BMCWEB_LOG_DEBUG("Found objectPath {} serviceName {}", objectPath,
951*de0c960cSJagpal Singh Gill                      serviceName);
952*de0c960cSJagpal Singh Gill     startUpdate(asyncResp, std::move(payload), memfd, applyTime, objectPath,
953*de0c960cSJagpal Singh Gill                 serviceName);
954*de0c960cSJagpal Singh Gill }
955*de0c960cSJagpal Singh Gill 
956*de0c960cSJagpal Singh Gill inline void
957*de0c960cSJagpal Singh Gill     getSwInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
958*de0c960cSJagpal Singh Gill               task::Payload payload, MemoryFileDescriptor memfd,
959*de0c960cSJagpal Singh Gill               const std::string& applyTime, const std::string& target,
960*de0c960cSJagpal Singh Gill               const boost::system::error_code& ec,
961*de0c960cSJagpal Singh Gill               const dbus::utility::MapperGetSubTreePathsResponse& subtree)
962*de0c960cSJagpal Singh Gill {
963*de0c960cSJagpal Singh Gill     using SwInfoMap =
964*de0c960cSJagpal Singh Gill         std::unordered_map<std::string, sdbusplus::message::object_path>;
965*de0c960cSJagpal Singh Gill     SwInfoMap swInfoMap;
966*de0c960cSJagpal Singh Gill 
967*de0c960cSJagpal Singh Gill     if (ec)
968*de0c960cSJagpal Singh Gill     {
969*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("error_code = {}", ec);
970*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("error msg = {}", ec.message());
971*de0c960cSJagpal Singh Gill         messages::internalError(asyncResp->res);
972*de0c960cSJagpal Singh Gill         return;
973*de0c960cSJagpal Singh Gill     }
974*de0c960cSJagpal Singh Gill     BMCWEB_LOG_DEBUG("Found {} software version paths", subtree.size());
975*de0c960cSJagpal Singh Gill 
976*de0c960cSJagpal Singh Gill     for (const auto& objectPath : subtree)
977*de0c960cSJagpal Singh Gill     {
978*de0c960cSJagpal Singh Gill         sdbusplus::message::object_path path(objectPath);
979*de0c960cSJagpal Singh Gill         std::string swId = path.filename();
980*de0c960cSJagpal Singh Gill         swInfoMap.emplace(swId, path);
981*de0c960cSJagpal Singh Gill     }
982*de0c960cSJagpal Singh Gill 
983*de0c960cSJagpal Singh Gill     auto swEntry = swInfoMap.find(target);
984*de0c960cSJagpal Singh Gill     if (swEntry == swInfoMap.end())
985*de0c960cSJagpal Singh Gill     {
986*de0c960cSJagpal Singh Gill         BMCWEB_LOG_WARNING("No valid DBus path for Target URI {}", target);
987*de0c960cSJagpal Singh Gill         messages::propertyValueFormatError(asyncResp->res, target, "Targets");
988*de0c960cSJagpal Singh Gill         return;
989*de0c960cSJagpal Singh Gill     }
990*de0c960cSJagpal Singh Gill 
991*de0c960cSJagpal Singh Gill     BMCWEB_LOG_DEBUG("Found software version path {}", swEntry->second.str);
992*de0c960cSJagpal Singh Gill 
993*de0c960cSJagpal Singh Gill     sdbusplus::message::object_path swObjectPath = swEntry->second /
994*de0c960cSJagpal Singh Gill                                                    "software_version";
995*de0c960cSJagpal Singh Gill     constexpr std::array<std::string_view, 1> interfaces = {
996*de0c960cSJagpal Singh Gill         "xyz.openbmc_project.Software.Update"};
997*de0c960cSJagpal Singh Gill     dbus::utility::getAssociatedSubTree(
998*de0c960cSJagpal Singh Gill         swObjectPath,
999*de0c960cSJagpal Singh Gill         sdbusplus::message::object_path("/xyz/openbmc_project/software"), 0,
1000*de0c960cSJagpal Singh Gill         interfaces,
1001*de0c960cSJagpal Singh Gill         [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
1002*de0c960cSJagpal Singh Gill          applyTime](
1003*de0c960cSJagpal Singh Gill             const boost::system::error_code& ec1,
1004*de0c960cSJagpal Singh Gill             const dbus::utility::MapperGetSubTreeResponse& subtree1) mutable {
1005*de0c960cSJagpal Singh Gill         getAssociatedUpdateInterface(asyncResp, std::move(payload), memfd,
1006*de0c960cSJagpal Singh Gill                                      applyTime, ec1, subtree1);
1007*de0c960cSJagpal Singh Gill     });
1008*de0c960cSJagpal Singh Gill }
1009*de0c960cSJagpal Singh Gill 
1010*de0c960cSJagpal Singh Gill inline void
1011*de0c960cSJagpal Singh Gill     processUpdateRequest(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1012*de0c960cSJagpal Singh Gill                          const crow::Request& req, std::string_view body,
1013*de0c960cSJagpal Singh Gill                          const std::string& applyTime,
1014*de0c960cSJagpal Singh Gill                          std::vector<std::string>& targets)
1015*de0c960cSJagpal Singh Gill {
1016*de0c960cSJagpal Singh Gill     std::string applyTimeNewVal;
1017*de0c960cSJagpal Singh Gill 
1018*de0c960cSJagpal Singh Gill     if (!convertApplyTime(asyncResp->res, applyTime, applyTimeNewVal))
1019*de0c960cSJagpal Singh Gill     {
1020*de0c960cSJagpal Singh Gill         return;
1021*de0c960cSJagpal Singh Gill     }
1022*de0c960cSJagpal Singh Gill 
1023*de0c960cSJagpal Singh Gill     MemoryFileDescriptor memfd("update-image");
1024*de0c960cSJagpal Singh Gill     if (memfd.fd == -1)
1025*de0c960cSJagpal Singh Gill     {
1026*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("Failed to create image memfd");
1027*de0c960cSJagpal Singh Gill         messages::internalError(asyncResp->res);
1028*de0c960cSJagpal Singh Gill         return;
1029*de0c960cSJagpal Singh Gill     }
1030*de0c960cSJagpal Singh Gill     if (write(memfd.fd, body.data(), body.length()) !=
1031*de0c960cSJagpal Singh Gill         static_cast<ssize_t>(body.length()))
1032*de0c960cSJagpal Singh Gill     {
1033*de0c960cSJagpal Singh Gill         BMCWEB_LOG_ERROR("Failed to write to image memfd");
1034*de0c960cSJagpal Singh Gill         messages::internalError(asyncResp->res);
1035*de0c960cSJagpal Singh Gill         return;
1036*de0c960cSJagpal Singh Gill     }
1037*de0c960cSJagpal Singh Gill     if (!memfd.rewind())
1038*de0c960cSJagpal Singh Gill     {
1039*de0c960cSJagpal Singh Gill         messages::internalError(asyncResp->res);
1040*de0c960cSJagpal Singh Gill         return;
1041*de0c960cSJagpal Singh Gill     }
1042*de0c960cSJagpal Singh Gill 
1043*de0c960cSJagpal Singh Gill     task::Payload payload(req);
1044*de0c960cSJagpal Singh Gill     if (!targets.empty() && targets[0] == BMCWEB_REDFISH_MANAGER_URI_NAME)
1045*de0c960cSJagpal Singh Gill     {
1046*de0c960cSJagpal Singh Gill         startUpdate(asyncResp, std::move(payload), memfd, applyTimeNewVal,
1047*de0c960cSJagpal Singh Gill                     "/xyz/openbmc_project/software/bmc",
1048*de0c960cSJagpal Singh Gill                     "xyz.openbmc_project.Software.Manager");
1049*de0c960cSJagpal Singh Gill     }
1050*de0c960cSJagpal Singh Gill     else
1051*de0c960cSJagpal Singh Gill     {
1052*de0c960cSJagpal Singh Gill         constexpr std::array<std::string_view, 1> interfaces = {
1053*de0c960cSJagpal Singh Gill             "xyz.openbmc_project.Software.Version"};
1054*de0c960cSJagpal Singh Gill         dbus::utility::getSubTreePaths(
1055*de0c960cSJagpal Singh Gill             "/xyz/openbmc_project/software", 1, interfaces,
1056*de0c960cSJagpal Singh Gill             [asyncResp, payload = std::move(payload), memfd = std::move(memfd),
1057*de0c960cSJagpal Singh Gill              applyTimeNewVal,
1058*de0c960cSJagpal Singh Gill              targets](const boost::system::error_code& ec,
1059*de0c960cSJagpal Singh Gill                       const dbus::utility::MapperGetSubTreePathsResponse&
1060*de0c960cSJagpal Singh Gill                           subtree) mutable {
1061*de0c960cSJagpal Singh Gill             getSwInfo(asyncResp, std::move(payload), std::move(memfd),
1062*de0c960cSJagpal Singh Gill                       applyTimeNewVal, targets[0], ec, subtree);
1063*de0c960cSJagpal Singh Gill         });
1064*de0c960cSJagpal Singh Gill     }
1065*de0c960cSJagpal Singh Gill }
1066*de0c960cSJagpal Singh Gill 
1067*de0c960cSJagpal Singh Gill inline void
1068ef93eab3SJagpal Singh Gill     updateMultipartContext(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1069ef93eab3SJagpal Singh Gill                            const crow::Request& req, MultipartParser&& parser)
1070ef93eab3SJagpal Singh Gill {
1071ef93eab3SJagpal Singh Gill     std::optional<MultiPartUpdateParameters> multipart =
1072ef93eab3SJagpal Singh Gill         extractMultipartUpdateParameters(asyncResp, std::move(parser));
1073ef93eab3SJagpal Singh Gill     if (!multipart)
1074ef93eab3SJagpal Singh Gill     {
1075ef93eab3SJagpal Singh Gill         return;
1076ef93eab3SJagpal Singh Gill     }
1077ef93eab3SJagpal Singh Gill     if (!multipart->applyTime)
1078ef93eab3SJagpal Singh Gill     {
1079ef93eab3SJagpal Singh Gill         multipart->applyTime = "OnReset";
1080ef93eab3SJagpal Singh Gill     }
1081ef93eab3SJagpal Singh Gill 
1082*de0c960cSJagpal Singh Gill     if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS)
1083*de0c960cSJagpal Singh Gill     {
1084*de0c960cSJagpal Singh Gill         processUpdateRequest(asyncResp, req, multipart->uploadData,
1085*de0c960cSJagpal Singh Gill                              *multipart->applyTime, multipart->targets);
1086*de0c960cSJagpal Singh Gill     }
1087*de0c960cSJagpal Singh Gill     else
1088*de0c960cSJagpal Singh Gill     {
1089ef93eab3SJagpal Singh Gill         setApplyTime(asyncResp, *multipart->applyTime);
10900ed80c8cSGeorge Liu 
10916b54e4e0SEd Tanous         // Setup callback for when new software detected
1092*de0c960cSJagpal Singh Gill         monitorForSoftwareAvailable(asyncResp, req,
1093*de0c960cSJagpal Singh Gill                                     "/redfish/v1/UpdateService");
10946b54e4e0SEd Tanous 
1095ef93eab3SJagpal Singh Gill         uploadImageFile(asyncResp->res, multipart->uploadData);
10960ed80c8cSGeorge Liu     }
1097*de0c960cSJagpal Singh Gill }
10980ed80c8cSGeorge Liu 
1099c2051d11SEd Tanous inline void
1100c2051d11SEd Tanous     handleUpdateServicePost(App& app, const crow::Request& req,
1101c2051d11SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1102c2051d11SEd Tanous {
11033ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1104c2051d11SEd Tanous     {
1105c2051d11SEd Tanous         return;
1106c2051d11SEd Tanous     }
1107b33a4327SNinad Palsule     std::string_view contentType = req.getHeaderValue("Content-Type");
1108b33a4327SNinad Palsule 
110962598e31SEd Tanous     BMCWEB_LOG_DEBUG("doPost: contentType={}", contentType);
1110b33a4327SNinad Palsule 
1111b33a4327SNinad Palsule     // Make sure that content type is application/octet-stream or
1112b33a4327SNinad Palsule     // multipart/form-data
111318f8f608SEd Tanous     if (bmcweb::asciiIEquals(contentType, "application/octet-stream"))
1114b33a4327SNinad Palsule     {
1115b33a4327SNinad Palsule         // Setup callback for when new software detected
1116b33a4327SNinad Palsule         monitorForSoftwareAvailable(asyncResp, req,
1117b33a4327SNinad Palsule                                     "/redfish/v1/UpdateService");
1118b33a4327SNinad Palsule 
1119b33a4327SNinad Palsule         uploadImageFile(asyncResp->res, req.body());
1120b33a4327SNinad Palsule     }
1121b33a4327SNinad Palsule     else if (contentType.starts_with("multipart/form-data"))
1122b33a4327SNinad Palsule     {
1123b33a4327SNinad Palsule         MultipartParser parser;
1124c2051d11SEd Tanous 
11250ed80c8cSGeorge Liu         ParserError ec = parser.parse(req);
11260ed80c8cSGeorge Liu         if (ec != ParserError::PARSER_SUCCESS)
11270ed80c8cSGeorge Liu         {
11280ed80c8cSGeorge Liu             // handle error
112962598e31SEd Tanous             BMCWEB_LOG_ERROR("MIME parse failed, ec : {}",
113062598e31SEd Tanous                              static_cast<int>(ec));
11310ed80c8cSGeorge Liu             messages::internalError(asyncResp->res);
11320ed80c8cSGeorge Liu             return;
11330ed80c8cSGeorge Liu         }
11346b54e4e0SEd Tanous 
1135ef93eab3SJagpal Singh Gill         updateMultipartContext(asyncResp, req, std::move(parser));
1136c2051d11SEd Tanous     }
1137b33a4327SNinad Palsule     else
1138b33a4327SNinad Palsule     {
113962598e31SEd Tanous         BMCWEB_LOG_DEBUG("Bad content type specified:{}", contentType);
1140b33a4327SNinad Palsule         asyncResp->res.result(boost::beast::http::status::bad_request);
1141b33a4327SNinad Palsule     }
1142b33a4327SNinad Palsule }
1143c2051d11SEd Tanous 
1144f5139334SEd Tanous inline void
1145f5139334SEd Tanous     handleUpdateServiceGet(App& app, const crow::Request& req,
1146f5139334SEd Tanous                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
11471abe55efSEd Tanous {
11483ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
114945ca1b86SEd Tanous     {
115045ca1b86SEd Tanous         return;
115145ca1b86SEd Tanous     }
11528d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
11530ed80c8cSGeorge Liu         "#UpdateService.v1_11_1.UpdateService";
11548d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
11558d1b46d7Szhanghch05     asyncResp->res.jsonValue["Id"] = "UpdateService";
1156002d39b4SEd Tanous     asyncResp->res.jsonValue["Description"] = "Service for Software Update";
11578d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Update Service";
11584dc23f3fSEd Tanous 
11597e860f15SJohn Edward Broadbent     asyncResp->res.jsonValue["HttpPushUri"] =
11604dc23f3fSEd Tanous         "/redfish/v1/UpdateService/update";
11610ed80c8cSGeorge Liu     asyncResp->res.jsonValue["MultipartHttpPushUri"] =
11620ed80c8cSGeorge Liu         "/redfish/v1/UpdateService/update";
11634dc23f3fSEd Tanous 
11640f74e643SEd Tanous     // UpdateService cannot be disabled
11658d1b46d7Szhanghch05     asyncResp->res.jsonValue["ServiceEnabled"] = true;
11661476687dSEd Tanous     asyncResp->res.jsonValue["FirmwareInventory"]["@odata.id"] =
11671476687dSEd Tanous         "/redfish/v1/UpdateService/FirmwareInventory";
1168d61e5194STejas Patil     // Get the MaxImageSizeBytes
116925b54dbaSEd Tanous     asyncResp->res.jsonValue["MaxImageSizeBytes"] = BMCWEB_HTTP_BODY_LIMIT *
1170f5139334SEd Tanous                                                     1024 * 1024;
1171d61e5194STejas Patil 
11720554c984SAndrew Geissler     // Update Actions object.
11730554c984SAndrew Geissler     nlohmann::json& updateSvcSimpleUpdate =
1174002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"];
11750554c984SAndrew Geissler     updateSvcSimpleUpdate["target"] =
11760554c984SAndrew Geissler         "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate";
1177757178a5SEd Tanous 
1178757178a5SEd Tanous     nlohmann::json::array_t allowed;
1179e5cf777eSEd Tanous     allowed.emplace_back(update_service::TransferProtocolType::HTTPS);
1180757178a5SEd Tanous 
118125b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
118225b54dbaSEd Tanous     {
1183757178a5SEd Tanous         allowed.emplace_back(update_service::TransferProtocolType::TFTP);
118425b54dbaSEd Tanous     }
1185757178a5SEd Tanous 
1186757178a5SEd Tanous     updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] =
1187757178a5SEd Tanous         std::move(allowed);
1188757178a5SEd Tanous 
1189274dfe62SJayashankar Padath     // Get the current ApplyTime value
11901e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
11911e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
11921e1e598dSJonathan Doman         "/xyz/openbmc_project/software/apply_time",
11931e1e598dSJonathan Doman         "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime",
11945e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
11951e1e598dSJonathan Doman                     const std::string& applyTime) {
1196274dfe62SJayashankar Padath         if (ec)
1197274dfe62SJayashankar Padath         {
119862598e31SEd Tanous             BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
11998d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
1200274dfe62SJayashankar Padath             return;
1201274dfe62SJayashankar Padath         }
1202274dfe62SJayashankar Padath 
1203274dfe62SJayashankar Padath         // Store the ApplyTime Value
12041e1e598dSJonathan Doman         if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
12051e1e598dSJonathan Doman                          "RequestedApplyTimes.Immediate")
1206274dfe62SJayashankar Padath         {
1207002d39b4SEd Tanous             asyncResp->res.jsonValue["HttpPushUriOptions"]
12087e860f15SJohn Edward Broadbent                                     ["HttpPushUriApplyTime"]["ApplyTime"] =
12097e860f15SJohn Edward Broadbent                 "Immediate";
1210274dfe62SJayashankar Padath         }
1211002d39b4SEd Tanous         else if (applyTime == "xyz.openbmc_project.Software.ApplyTime."
12121e1e598dSJonathan Doman                               "RequestedApplyTimes.OnReset")
1213274dfe62SJayashankar Padath         {
1214002d39b4SEd Tanous             asyncResp->res.jsonValue["HttpPushUriOptions"]
12157e860f15SJohn Edward Broadbent                                     ["HttpPushUriApplyTime"]["ApplyTime"] =
12167e860f15SJohn Edward Broadbent                 "OnReset";
1217274dfe62SJayashankar Padath         }
12181e1e598dSJonathan Doman     });
1219f5139334SEd Tanous }
1220f5139334SEd Tanous 
1221f5139334SEd Tanous inline void handleUpdateServicePatch(
1222f5139334SEd Tanous     App& app, const crow::Request& req,
1223f5139334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1224f5139334SEd Tanous {
12253ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
122645ca1b86SEd Tanous     {
122745ca1b86SEd Tanous         return;
122845ca1b86SEd Tanous     }
122962598e31SEd Tanous     BMCWEB_LOG_DEBUG("doPatch...");
1230fa1a5a38SJayashankar Padath 
1231274dfe62SJayashankar Padath     std::optional<std::string> applyTime;
12327cb59f65SEd Tanous     if (!json_util::readJsonPatch(
12337cb59f65SEd Tanous             req, asyncResp->res,
12347cb59f65SEd Tanous             "HttpPushUriOptions/HttpPushUriApplyTime/ApplyTime", applyTime))
1235274dfe62SJayashankar Padath     {
1236274dfe62SJayashankar Padath         return;
1237274dfe62SJayashankar Padath     }
1238274dfe62SJayashankar Padath 
1239274dfe62SJayashankar Padath     if (applyTime)
1240fa1a5a38SJayashankar Padath     {
12410ed80c8cSGeorge Liu         setApplyTime(asyncResp, *applyTime);
1242fa1a5a38SJayashankar Padath     }
1243729dae72SJennifer Lee }
1244729dae72SJennifer Lee 
1245f5139334SEd Tanous inline void handleUpdateServiceFirmwareInventoryCollectionGet(
1246f5139334SEd Tanous     App& app, const crow::Request& req,
1247f5139334SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12481abe55efSEd Tanous {
12493ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
125045ca1b86SEd Tanous     {
125145ca1b86SEd Tanous         return;
125245ca1b86SEd Tanous     }
12538d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
12540f74e643SEd Tanous         "#SoftwareInventoryCollection.SoftwareInventoryCollection";
12558d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] =
12560f74e643SEd Tanous         "/redfish/v1/UpdateService/FirmwareInventory";
1257002d39b4SEd Tanous     asyncResp->res.jsonValue["Name"] = "Software Inventory Collection";
125808d81adaSJohn Edward Broadbent     const std::array<const std::string_view, 1> iface = {
1259e99073f5SGeorge Liu         "xyz.openbmc_project.Software.Version"};
12606c4eb9deSJennifer Lee 
126108d81adaSJohn Edward Broadbent     redfish::collection_util::getCollectionMembers(
126208d81adaSJohn Edward Broadbent         asyncResp,
1263f5139334SEd Tanous         boost::urls::url("/redfish/v1/UpdateService/FirmwareInventory"), iface,
1264f5139334SEd Tanous         "/xyz/openbmc_project/software");
1265729dae72SJennifer Lee }
1266f5139334SEd Tanous 
126787d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */
1268f5139334SEd Tanous inline void getRelatedItems(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
126987d84729SAndrew Geissler                             const std::string& purpose)
127087d84729SAndrew Geissler {
1271eee0013eSWilly Tu     if (purpose == sw_util::bmcPurpose)
127287d84729SAndrew Geissler     {
1273ac106bf6SEd Tanous         nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
12741476687dSEd Tanous         nlohmann::json::object_t item;
1275253f11b8SEd Tanous         item["@odata.id"] = boost::urls::format(
1276253f11b8SEd Tanous             "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME);
1277b2ba3072SPatrick Williams         relatedItem.emplace_back(std::move(item));
1278ac106bf6SEd Tanous         asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1279ac106bf6SEd Tanous             relatedItem.size();
128087d84729SAndrew Geissler     }
1281eee0013eSWilly Tu     else if (purpose == sw_util::biosPurpose)
128287d84729SAndrew Geissler     {
1283ac106bf6SEd Tanous         nlohmann::json& relatedItem = asyncResp->res.jsonValue["RelatedItem"];
12841476687dSEd Tanous         nlohmann::json::object_t item;
1285253f11b8SEd Tanous         item["@odata.id"] = std::format("/redfish/v1/Systems/{}/Bios",
1286253f11b8SEd Tanous                                         BMCWEB_REDFISH_SYSTEM_URI_NAME);
1287b2ba3072SPatrick Williams         relatedItem.emplace_back(std::move(item));
1288ac106bf6SEd Tanous         asyncResp->res.jsonValue["RelatedItem@odata.count"] =
1289ac106bf6SEd Tanous             relatedItem.size();
129087d84729SAndrew Geissler     }
129187d84729SAndrew Geissler     else
129287d84729SAndrew Geissler     {
1293bf2ddedeSCarson Labrado         BMCWEB_LOG_DEBUG("Unknown software purpose {}", purpose);
129487d84729SAndrew Geissler     }
129587d84729SAndrew Geissler }
129687d84729SAndrew Geissler 
1297af24660dSWilly Tu inline void
1298af24660dSWilly Tu     getSoftwareVersion(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1299af24660dSWilly Tu                        const std::string& service, const std::string& path,
1300af24660dSWilly Tu                        const std::string& swId)
1301af24660dSWilly Tu {
1302d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
1303d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, service, path,
1304d1bde9e5SKrzysztof Grobelny         "xyz.openbmc_project.Software.Version",
1305af24660dSWilly Tu         [asyncResp,
13068b24275dSEd Tanous          swId](const boost::system::error_code& ec,
1307af24660dSWilly Tu                const dbus::utility::DBusPropertiesMap& propertiesList) {
13088b24275dSEd Tanous         if (ec)
1309af24660dSWilly Tu         {
1310af24660dSWilly Tu             messages::internalError(asyncResp->res);
1311af24660dSWilly Tu             return;
1312af24660dSWilly Tu         }
1313d1bde9e5SKrzysztof Grobelny 
1314af24660dSWilly Tu         const std::string* swInvPurpose = nullptr;
1315af24660dSWilly Tu         const std::string* version = nullptr;
1316d1bde9e5SKrzysztof Grobelny 
1317d1bde9e5SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
1318d1bde9e5SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
1319d1bde9e5SKrzysztof Grobelny             swInvPurpose, "Version", version);
1320d1bde9e5SKrzysztof Grobelny 
1321d1bde9e5SKrzysztof Grobelny         if (!success)
1322af24660dSWilly Tu         {
1323d1bde9e5SKrzysztof Grobelny             messages::internalError(asyncResp->res);
1324d1bde9e5SKrzysztof Grobelny             return;
1325af24660dSWilly Tu         }
1326af24660dSWilly Tu 
1327af24660dSWilly Tu         if (swInvPurpose == nullptr)
1328af24660dSWilly Tu         {
132962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Can't find property \"Purpose\"!");
1330af24660dSWilly Tu             messages::internalError(asyncResp->res);
1331af24660dSWilly Tu             return;
1332af24660dSWilly Tu         }
1333af24660dSWilly Tu 
133462598e31SEd Tanous         BMCWEB_LOG_DEBUG("swInvPurpose = {}", *swInvPurpose);
1335af24660dSWilly Tu 
1336af24660dSWilly Tu         if (version == nullptr)
1337af24660dSWilly Tu         {
133862598e31SEd Tanous             BMCWEB_LOG_DEBUG("Can't find property \"Version\"!");
1339af24660dSWilly Tu 
1340af24660dSWilly Tu             messages::internalError(asyncResp->res);
1341af24660dSWilly Tu 
1342af24660dSWilly Tu             return;
1343af24660dSWilly Tu         }
1344af24660dSWilly Tu         asyncResp->res.jsonValue["Version"] = *version;
1345af24660dSWilly Tu         asyncResp->res.jsonValue["Id"] = swId;
1346af24660dSWilly Tu 
1347af24660dSWilly Tu         // swInvPurpose is of format:
1348af24660dSWilly Tu         // xyz.openbmc_project.Software.Version.VersionPurpose.ABC
1349af24660dSWilly Tu         // Translate this to "ABC image"
1350af24660dSWilly Tu         size_t endDesc = swInvPurpose->rfind('.');
1351af24660dSWilly Tu         if (endDesc == std::string::npos)
1352af24660dSWilly Tu         {
1353af24660dSWilly Tu             messages::internalError(asyncResp->res);
1354af24660dSWilly Tu             return;
1355af24660dSWilly Tu         }
1356af24660dSWilly Tu         endDesc++;
1357af24660dSWilly Tu         if (endDesc >= swInvPurpose->size())
1358af24660dSWilly Tu         {
1359af24660dSWilly Tu             messages::internalError(asyncResp->res);
1360af24660dSWilly Tu             return;
1361af24660dSWilly Tu         }
1362af24660dSWilly Tu 
1363af24660dSWilly Tu         std::string formatDesc = swInvPurpose->substr(endDesc);
1364af24660dSWilly Tu         asyncResp->res.jsonValue["Description"] = formatDesc + " image";
1365af24660dSWilly Tu         getRelatedItems(asyncResp, *swInvPurpose);
1366d1bde9e5SKrzysztof Grobelny     });
1367af24660dSWilly Tu }
1368af24660dSWilly Tu 
1369f5139334SEd Tanous inline void handleUpdateServiceFirmwareInventoryGet(
1370f5139334SEd Tanous     App& app, const crow::Request& req,
137145ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1372f5139334SEd Tanous     const std::string& param)
1373f5139334SEd Tanous {
13743ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
137545ca1b86SEd Tanous     {
137645ca1b86SEd Tanous         return;
137745ca1b86SEd Tanous     }
1378f5139334SEd Tanous     std::shared_ptr<std::string> swId = std::make_shared<std::string>(param);
1379c711bf86SEd Tanous 
1380ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1381ef4c65b7SEd Tanous         "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId);
1382c711bf86SEd Tanous 
1383e99073f5SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
1384e99073f5SGeorge Liu         "xyz.openbmc_project.Software.Version"};
1385e99073f5SGeorge Liu     dbus::utility::getSubTree(
1386e99073f5SGeorge Liu         "/", 0, interfaces,
1387b9d36b47SEd Tanous         [asyncResp,
1388e99073f5SGeorge Liu          swId](const boost::system::error_code& ec,
1389b9d36b47SEd Tanous                const dbus::utility::MapperGetSubTreeResponse& subtree) {
139062598e31SEd Tanous         BMCWEB_LOG_DEBUG("doGet callback...");
13911abe55efSEd Tanous         if (ec)
13921abe55efSEd Tanous         {
1393f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
13946c4eb9deSJennifer Lee             return;
13956c4eb9deSJennifer Lee         }
13966c4eb9deSJennifer Lee 
13976913228dSAndrew Geissler         // Ensure we find our input swId, otherwise return an error
13986913228dSAndrew Geissler         bool found = false;
1399f5139334SEd Tanous         for (const std::pair<
1400f5139334SEd Tanous                  std::string,
1401f5139334SEd Tanous                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
1402002d39b4SEd Tanous                  obj : subtree)
14031abe55efSEd Tanous         {
140411ba3979SEd Tanous             if (!obj.first.ends_with(*swId))
14051abe55efSEd Tanous             {
1406acb7cfb4SJennifer Lee                 continue;
1407acb7cfb4SJennifer Lee             }
1408acb7cfb4SJennifer Lee 
140926f6976fSEd Tanous             if (obj.second.empty())
14101abe55efSEd Tanous             {
1411acb7cfb4SJennifer Lee                 continue;
1412acb7cfb4SJennifer Lee             }
14136c4eb9deSJennifer Lee 
14146913228dSAndrew Geissler             found = true;
1415eee0013eSWilly Tu             sw_util::getSwStatus(asyncResp, swId, obj.second[0].first);
1416af24660dSWilly Tu             getSoftwareVersion(asyncResp, obj.second[0].first, obj.first,
1417af24660dSWilly Tu                                *swId);
14186c4eb9deSJennifer Lee         }
14196913228dSAndrew Geissler         if (!found)
14206913228dSAndrew Geissler         {
142162598e31SEd Tanous             BMCWEB_LOG_WARNING("Input swID {} not found!", *swId);
14226913228dSAndrew Geissler             messages::resourceMissingAtURI(
1423ef4c65b7SEd Tanous                 asyncResp->res,
1424ef4c65b7SEd Tanous                 boost::urls::format(
1425f5139334SEd Tanous                     "/redfish/v1/UpdateService/FirmwareInventory/{}", *swId));
14266913228dSAndrew Geissler             return;
14276913228dSAndrew Geissler         }
14284e68c45bSAyushi Smriti         asyncResp->res.jsonValue["@odata.type"] =
14294e68c45bSAyushi Smriti             "#SoftwareInventory.v1_1_0.SoftwareInventory";
14304e68c45bSAyushi Smriti         asyncResp->res.jsonValue["Name"] = "Software Inventory";
14314e68c45bSAyushi Smriti         asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
14323f8a743aSAppaRao Puli 
14333f8a743aSAppaRao Puli         asyncResp->res.jsonValue["Updateable"] = false;
1434eee0013eSWilly Tu         sw_util::getSwUpdatableStatus(asyncResp, swId);
1435e99073f5SGeorge Liu     });
1436f5139334SEd Tanous }
1437f5139334SEd Tanous 
1438f5139334SEd Tanous inline void requestRoutesUpdateService(App& app)
1439f5139334SEd Tanous {
1440f5139334SEd Tanous     BMCWEB_ROUTE(
1441f5139334SEd Tanous         app, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/")
1442f5139334SEd Tanous         .privileges(redfish::privileges::postUpdateService)
1443f5139334SEd Tanous         .methods(boost::beast::http::verb::post)(std::bind_front(
1444f5139334SEd Tanous             handleUpdateServiceSimpleUpdateAction, std::ref(app)));
1445f5139334SEd Tanous 
1446f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/")
1447f5139334SEd Tanous         .privileges(redfish::privileges::getSoftwareInventory)
1448f5139334SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
1449f5139334SEd Tanous             handleUpdateServiceFirmwareInventoryGet, std::ref(app)));
1450f5139334SEd Tanous 
1451f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1452f5139334SEd Tanous         .privileges(redfish::privileges::getUpdateService)
1453f5139334SEd Tanous         .methods(boost::beast::http::verb::get)(
1454f5139334SEd Tanous             std::bind_front(handleUpdateServiceGet, std::ref(app)));
1455f5139334SEd Tanous 
1456f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/")
1457f5139334SEd Tanous         .privileges(redfish::privileges::patchUpdateService)
1458f5139334SEd Tanous         .methods(boost::beast::http::verb::patch)(
1459f5139334SEd Tanous             std::bind_front(handleUpdateServicePatch, std::ref(app)));
1460f5139334SEd Tanous 
1461f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/update/")
1462f5139334SEd Tanous         .privileges(redfish::privileges::postUpdateService)
1463f5139334SEd Tanous         .methods(boost::beast::http::verb::post)(
1464f5139334SEd Tanous             std::bind_front(handleUpdateServicePost, std::ref(app)));
1465f5139334SEd Tanous 
1466f5139334SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/UpdateService/FirmwareInventory/")
1467f5139334SEd Tanous         .privileges(redfish::privileges::getSoftwareInventoryCollection)
1468f5139334SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
1469f5139334SEd Tanous             handleUpdateServiceFirmwareInventoryCollectionGet, std::ref(app)));
14706c4eb9deSJennifer Lee }
1471729dae72SJennifer Lee 
1472729dae72SJennifer Lee } // namespace redfish
1473