blob: ebc451a109025ec5756ffa0fff82679013f2cb7f [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
43// NOLINTNEXTLINE(readability-static-accessed-through-instance)
44auto Manager::processImage(sdbusplus::message::unix_fd image,
45 ApplyTimeIntf::RequestedApplyTimes applyTime,
46 std::string id,
47 std::string objPath) -> sdbusplus::async::task<>
48{
49 debug("Processing image {FD}", "FD", image.fd);
50 fs::path tmpDirPath(std::string{IMG_UPLOAD_DIR});
51 tmpDirPath /= "imageXXXXXX";
52 auto tmpDir = tmpDirPath.string();
53 // Create a tmp dir to copy tarball.
54 if (!mkdtemp(tmpDir.data()))
55 {
56 error("Error ({ERRNO}) occurred during mkdtemp", "ERRNO", errno);
57 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070058 report<SoftwareErrors::InternalFailure>(InternalFail::FAIL("mkdtemp"));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070059 co_return;
60 }
61
62 std::error_code ec;
63 tmpDirPath = tmpDir;
64 softwareUtils::RemovablePath tmpDirToRemove(tmpDirPath);
65
66 // Untar tarball into the tmp dir
67 if (!softwareUtils::unTar(image, tmpDirPath.string()))
68 {
69 error("Error occurred during untar");
70 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070071 report<SoftwareErrors::UnTarFailure>(
72 UnTarFail::PATH(tmpDirPath.c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070073 co_return;
74 }
75
76 fs::path manifestPath = tmpDirPath;
77 manifestPath /= MANIFEST_FILE_NAME;
78
79 // Get version
80 auto version = Version::getValue(manifestPath.string(), "version");
81 if (version.empty())
82 {
83 error("Unable to read version from manifest file");
84 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070085 report<SoftwareErrors::ManifestFileFailure>(
86 ManifestFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -070087 co_return;
88 }
89
90 // Get running machine name
91 std::string currMachine = Version::getBMCMachine(OS_RELEASE_FILE);
92 if (currMachine.empty())
93 {
94 auto path = OS_RELEASE_FILE;
95 error("Failed to read machine name from osRelease: {PATH}", "PATH",
96 path);
97 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -070098 report<SoftwareErrors::ImageFailure>(
99 ImageFail::FAIL("Failed to read machine name"),
100 ImageFail::PATH(path));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700101 co_return;
102 }
103
104 // Get machine name for image to be upgraded
105 std::string machineStr =
106 Version::getValue(manifestPath.string(), "MachineName");
107 if (!machineStr.empty())
108 {
109 if (machineStr != currMachine)
110 {
111 error(
112 "BMC upgrade: Machine name doesn't match: {CURRENT_MACHINE} vs {NEW_MACHINE}",
113 "CURRENT_MACHINE", currMachine, "NEW_MACHINE", machineStr);
114 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700115 report<SoftwareErrors::ImageFailure>(
116 ImageFail::FAIL("Machine name does not match"),
117 ImageFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700118 co_return;
119 }
120 }
121 else
122 {
123 warning("No machine name in Manifest file");
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700124 report<SoftwareErrors::ImageFailure>(
125 ImageFail::FAIL("MANIFEST is missing machine name"),
126 ImageFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700127 }
128
129 // Get purpose
130 auto purposeString = Version::getValue(manifestPath.string(), "purpose");
131 if (purposeString.empty())
132 {
133 error("Unable to read purpose from manifest file");
134 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700135 report<SoftwareErrors::ManifestFileFailure>(
136 ManifestFail::PATH(manifestPath.string().c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700137 co_return;
138 }
139 auto convertedPurpose =
140 sdbusplus::message::convert_from_string<Version::VersionPurpose>(
141 purposeString);
142 if (!convertedPurpose)
143 {
144 warning(
145 "Failed to convert manifest purpose ({PURPOSE}) to enum; setting to Unknown.",
146 "PURPOSE", purposeString);
147 }
148 auto purpose = convertedPurpose.value_or(Version::VersionPurpose::Unknown);
149
150 // Get ExtendedVersion
151 std::string extendedVersion =
152 Version::getValue(manifestPath.string(), "ExtendedVersion");
153
154 // Get CompatibleNames
155 std::vector<std::string> compatibleNames =
156 Version::getRepeatedValues(manifestPath.string(), "CompatibleName");
157
158 // Rename IMG_UPLOAD_DIR/imageXXXXXX to IMG_UPLOAD_DIR/id as Manifest
159 // parsing succedded.
160 fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
161 imageDirPath /= id;
162 fs::rename(tmpDirPath, imageDirPath, ec);
163 tmpDirToRemove.path.clear();
164
165 auto filePath = imageDirPath.string();
166 // Create Version object
167 auto state = itemUpdater.verifyAndCreateObjects(
168 id, objPath, version, purpose, extendedVersion, filePath,
169 compatibleNames);
170 if (state != ActivationIntf::Activations::Ready)
171 {
172 error("Software image is invalid");
173 processImageFailed(image, id);
Jagpal Singh Gill054954a2024-08-14 14:14:56 -0700174 report<SoftwareErrors::ImageFailure>(
175 ImageFail::FAIL("Image is invalid"),
176 ImageFail::PATH(filePath.c_str()));
Jagpal Singh Gill6d131aa2024-04-07 23:56:48 -0700177 co_return;
178 }
179 if (applyTime == ApplyTimeIntf::RequestedApplyTimes::Immediate ||
180 applyTime == ApplyTimeIntf::RequestedApplyTimes::OnReset)
181 {
182 itemUpdater.requestActivation(id);
183 }
184
185 updateInProgress = false;
186 close(image);
187 co_return;
188}
189
190sdbusplus::message::object_path
191 Manager::startUpdate(sdbusplus::message::unix_fd image,
192 ApplyTimeIntf::RequestedApplyTimes applyTime)
193{
194 info("Starting update for image {FD}", "FD", static_cast<int>(image));
195 using sdbusplus::xyz::openbmc_project::Common::Error::Unavailable;
196 if (updateInProgress)
197 {
198 error("Failed to start as update is already in progress");
199 report<Unavailable>();
200 return sdbusplus::message::object_path();
201 }
202 updateInProgress = true;
203
204 auto id = Version::getId(std::to_string(randomGen()));
205 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
206
207 // Create Activation Object
208 itemUpdater.createActivationWithApplyTime(id, objPath, applyTime);
209
210 int newFd = dup(image);
211 ctx.spawn(processImage(newFd, applyTime, id, objPath));
212
213 return sdbusplus::message::object_path(objPath);
214}
215
216} // namespace phosphor::software::update