blob: 766419591ba8c6171778380363a88f2193d2bc29 [file] [log] [blame]
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -07001#include "update_manager.hpp"
2
3#include "item_updater.hpp"
4#include "software_utils.hpp"
5#include "version.hpp"
6
7#include <phosphor-logging/elog-errors.hpp>
8#include <phosphor-logging/elog.hpp>
9#include <phosphor-logging/lg2.hpp>
10#include <sdbusplus/async.hpp>
11#include <xyz/openbmc_project/Common/error.hpp>
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070012#include <xyz/openbmc_project/Software/Image/error.hpp>
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070013
14#include <filesystem>
15
16PHOSPHOR_LOG2_USING;
17
18namespace phosphor::software::update
19{
20
21namespace fs = std::filesystem;
22namespace softwareUtils = phosphor::software::utils;
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070023namespace SoftwareLogging = phosphor::logging::xyz::openbmc_project::software;
24namespace SoftwareErrors =
25 sdbusplus::error::xyz::openbmc_project::software::image;
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070026using namespace phosphor::logging;
27using Version = phosphor::software::manager::Version;
28using ActivationIntf = phosphor::software::updater::Activation;
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070029using ManifestFail = SoftwareLogging::image::ManifestFileFailure;
30using UnTarFail = SoftwareLogging::image::UnTarFailure;
31using InternalFail = SoftwareLogging::image::InternalFailure;
32using ImageFail = SoftwareLogging::image::ImageFailure;
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070033
34void Manager::processImageFailed(sdbusplus::message::unix_fd image,
35 std::string& id)
36{
37 close(image);
38 updateInProgress = false;
39 itemUpdater.updateActivationStatus(id,
40 ActivationIntf::Activations::Invalid);
41}
42
Jagpal Singh Gill46f2a392024-11-04 18:02:28 -080043bool verifyImagePurpose(Version::VersionPurpose purpose,
44 ItemUpdaterIntf::UpdaterType type)
45{
46 if (purpose == Version::VersionPurpose::Host)
47 {
48 return (type == ItemUpdaterIntf::UpdaterType::BIOS ||
49 type == ItemUpdaterIntf::UpdaterType::ALL);
50 }
51 return true;
52}
53
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070054auto Manager::processImage(sdbusplus::message::unix_fd image,
55 ApplyTimeIntf::RequestedApplyTimes applyTime,
Patrick Williamsb3e3d642024-12-18 11:20:22 -050056 std::string id, std::string objPath)
57 -> sdbusplus::async::task<>
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070058{
59 debug("Processing image {FD}", "FD", image.fd);
60 fs::path tmpDirPath(std::string{IMG_UPLOAD_DIR});
61 tmpDirPath /= "imageXXXXXX";
62 auto tmpDir = tmpDirPath.string();
63 // Create a tmp dir to copy tarball.
64 if (!mkdtemp(tmpDir.data()))
65 {
66 error("Error ({ERRNO}) occurred during mkdtemp", "ERRNO", errno);
67 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070068 report<SoftwareErrors::InternalFailure>(InternalFail::FAIL("mkdtemp"));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070069 co_return;
70 }
71
72 std::error_code ec;
73 tmpDirPath = tmpDir;
74 softwareUtils::RemovablePath tmpDirToRemove(tmpDirPath);
75
76 // Untar tarball into the tmp dir
77 if (!softwareUtils::unTar(image, tmpDirPath.string()))
78 {
79 error("Error occurred during untar");
80 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070081 report<SoftwareErrors::UnTarFailure>(
82 UnTarFail::PATH(tmpDirPath.c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070083 co_return;
84 }
85
86 fs::path manifestPath = tmpDirPath;
87 manifestPath /= MANIFEST_FILE_NAME;
88
89 // Get version
90 auto version = Version::getValue(manifestPath.string(), "version");
91 if (version.empty())
92 {
93 error("Unable to read version from manifest file");
94 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070095 report<SoftwareErrors::ManifestFileFailure>(
96 ManifestFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070097 co_return;
98 }
99
100 // Get running machine name
101 std::string currMachine = Version::getBMCMachine(OS_RELEASE_FILE);
102 if (currMachine.empty())
103 {
104 auto path = OS_RELEASE_FILE;
105 error("Failed to read machine name from osRelease: {PATH}", "PATH",
106 path);
107 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700108 report<SoftwareErrors::ImageFailure>(
109 ImageFail::FAIL("Failed to read machine name"),
110 ImageFail::PATH(path));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700111 co_return;
112 }
113
114 // Get machine name for image to be upgraded
115 std::string machineStr =
116 Version::getValue(manifestPath.string(), "MachineName");
117 if (!machineStr.empty())
118 {
119 if (machineStr != currMachine)
120 {
121 error(
122 "BMC upgrade: Machine name doesn't match: {CURRENT_MACHINE} vs {NEW_MACHINE}",
123 "CURRENT_MACHINE", currMachine, "NEW_MACHINE", machineStr);
124 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700125 report<SoftwareErrors::ImageFailure>(
126 ImageFail::FAIL("Machine name does not match"),
127 ImageFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700128 co_return;
129 }
130 }
131 else
132 {
133 warning("No machine name in Manifest file");
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700134 report<SoftwareErrors::ImageFailure>(
135 ImageFail::FAIL("MANIFEST is missing machine name"),
136 ImageFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700137 }
138
139 // Get purpose
140 auto purposeString = Version::getValue(manifestPath.string(), "purpose");
141 if (purposeString.empty())
142 {
143 error("Unable to read purpose from manifest file");
144 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700145 report<SoftwareErrors::ManifestFileFailure>(
146 ManifestFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700147 co_return;
148 }
149 auto convertedPurpose =
150 sdbusplus::message::convert_from_string<Version::VersionPurpose>(
151 purposeString);
152 if (!convertedPurpose)
153 {
154 warning(
155 "Failed to convert manifest purpose ({PURPOSE}) to enum; setting to Unknown.",
156 "PURPOSE", purposeString);
157 }
158 auto purpose = convertedPurpose.value_or(Version::VersionPurpose::Unknown);
159
Jagpal Singh Gill46f2a392024-11-04 18:02:28 -0800160 if (!verifyImagePurpose(purpose, itemUpdater.type))
161 {
162 error("Purpose ({PURPOSE}) is not supported", "PURPOSE", purpose);
163 processImageFailed(image, id);
164 report<SoftwareErrors::ImageFailure>(
165 ImageFail::FAIL("Purpose is not supported"),
166 ImageFail::PATH(manifestPath.string().c_str()));
167 co_return;
168 }
169
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700170 // Get ExtendedVersion
171 std::string extendedVersion =
172 Version::getValue(manifestPath.string(), "ExtendedVersion");
173
174 // Get CompatibleNames
175 std::vector<std::string> compatibleNames =
176 Version::getRepeatedValues(manifestPath.string(), "CompatibleName");
177
178 // Rename IMG_UPLOAD_DIR/imageXXXXXX to IMG_UPLOAD_DIR/id as Manifest
179 // parsing succedded.
180 fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
181 imageDirPath /= id;
182 fs::rename(tmpDirPath, imageDirPath, ec);
183 tmpDirToRemove.path.clear();
184
185 auto filePath = imageDirPath.string();
186 // Create Version object
187 auto state = itemUpdater.verifyAndCreateObjects(
188 id, objPath, version, purpose, extendedVersion, filePath,
189 compatibleNames);
190 if (state != ActivationIntf::Activations::Ready)
191 {
192 error("Software image is invalid");
193 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700194 report<SoftwareErrors::ImageFailure>(
195 ImageFail::FAIL("Image is invalid"),
196 ImageFail::PATH(filePath.c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700197 co_return;
198 }
199 if (applyTime == ApplyTimeIntf::RequestedApplyTimes::Immediate ||
200 applyTime == ApplyTimeIntf::RequestedApplyTimes::OnReset)
201 {
202 itemUpdater.requestActivation(id);
203 }
204
205 updateInProgress = false;
206 close(image);
207 co_return;
208}
209
Patrick Williamseae5ec92025-02-01 08:21:45 -0500210sdbusplus::message::object_path Manager::startUpdate(
211 sdbusplus::message::unix_fd image,
212 ApplyTimeIntf::RequestedApplyTimes applyTime)
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700213{
214 info("Starting update for image {FD}", "FD", static_cast<int>(image));
215 using sdbusplus::xyz::openbmc_project::Common::Error::Unavailable;
216 if (updateInProgress)
217 {
218 error("Failed to start as update is already in progress");
219 report<Unavailable>();
220 return sdbusplus::message::object_path();
221 }
222 updateInProgress = true;
223
224 auto id = Version::getId(std::to_string(randomGen()));
225 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
226
227 // Create Activation Object
228 itemUpdater.createActivationWithApplyTime(id, objPath, applyTime);
229
230 int newFd = dup(image);
231 ctx.spawn(processImage(newFd, applyTime, id, objPath));
232
233 return sdbusplus::message::object_path(objPath);
234}
235
236} // namespace phosphor::software::update