1*6d131aa7SJagpal Singh Gill #include "update_manager.hpp"
2*6d131aa7SJagpal Singh Gill 
3*6d131aa7SJagpal Singh Gill #include "item_updater.hpp"
4*6d131aa7SJagpal Singh Gill #include "software_utils.hpp"
5*6d131aa7SJagpal Singh Gill #include "version.hpp"
6*6d131aa7SJagpal Singh Gill 
7*6d131aa7SJagpal Singh Gill #include <phosphor-logging/elog-errors.hpp>
8*6d131aa7SJagpal Singh Gill #include <phosphor-logging/elog.hpp>
9*6d131aa7SJagpal Singh Gill #include <phosphor-logging/lg2.hpp>
10*6d131aa7SJagpal Singh Gill #include <sdbusplus/async.hpp>
11*6d131aa7SJagpal Singh Gill #include <xyz/openbmc_project/Common/error.hpp>
12*6d131aa7SJagpal Singh Gill 
13*6d131aa7SJagpal Singh Gill #include <filesystem>
14*6d131aa7SJagpal Singh Gill 
15*6d131aa7SJagpal Singh Gill PHOSPHOR_LOG2_USING;
16*6d131aa7SJagpal Singh Gill 
17*6d131aa7SJagpal Singh Gill namespace phosphor::software::update
18*6d131aa7SJagpal Singh Gill {
19*6d131aa7SJagpal Singh Gill 
20*6d131aa7SJagpal Singh Gill namespace fs = std::filesystem;
21*6d131aa7SJagpal Singh Gill namespace softwareUtils = phosphor::software::utils;
22*6d131aa7SJagpal Singh Gill using namespace phosphor::logging;
23*6d131aa7SJagpal Singh Gill using Version = phosphor::software::manager::Version;
24*6d131aa7SJagpal Singh Gill using ActivationIntf = phosphor::software::updater::Activation;
25*6d131aa7SJagpal Singh Gill 
processImageFailed(sdbusplus::message::unix_fd image,std::string & id)26*6d131aa7SJagpal Singh Gill void Manager::processImageFailed(sdbusplus::message::unix_fd image,
27*6d131aa7SJagpal Singh Gill                                  std::string& id)
28*6d131aa7SJagpal Singh Gill {
29*6d131aa7SJagpal Singh Gill     close(image);
30*6d131aa7SJagpal Singh Gill     updateInProgress = false;
31*6d131aa7SJagpal Singh Gill     itemUpdater.updateActivationStatus(id,
32*6d131aa7SJagpal Singh Gill                                        ActivationIntf::Activations::Invalid);
33*6d131aa7SJagpal Singh Gill }
34*6d131aa7SJagpal Singh Gill 
35*6d131aa7SJagpal Singh Gill // NOLINTNEXTLINE(readability-static-accessed-through-instance)
processImage(sdbusplus::message::unix_fd image,ApplyTimeIntf::RequestedApplyTimes applyTime,std::string id,std::string objPath)36*6d131aa7SJagpal Singh Gill auto Manager::processImage(sdbusplus::message::unix_fd image,
37*6d131aa7SJagpal Singh Gill                            ApplyTimeIntf::RequestedApplyTimes applyTime,
38*6d131aa7SJagpal Singh Gill                            std::string id,
39*6d131aa7SJagpal Singh Gill                            std::string objPath) -> sdbusplus::async::task<>
40*6d131aa7SJagpal Singh Gill {
41*6d131aa7SJagpal Singh Gill     debug("Processing image {FD}", "FD", image.fd);
42*6d131aa7SJagpal Singh Gill     fs::path tmpDirPath(std::string{IMG_UPLOAD_DIR});
43*6d131aa7SJagpal Singh Gill     tmpDirPath /= "imageXXXXXX";
44*6d131aa7SJagpal Singh Gill     auto tmpDir = tmpDirPath.string();
45*6d131aa7SJagpal Singh Gill     // Create a tmp dir to copy tarball.
46*6d131aa7SJagpal Singh Gill     if (!mkdtemp(tmpDir.data()))
47*6d131aa7SJagpal Singh Gill     {
48*6d131aa7SJagpal Singh Gill         error("Error ({ERRNO}) occurred during mkdtemp", "ERRNO", errno);
49*6d131aa7SJagpal Singh Gill         processImageFailed(image, id);
50*6d131aa7SJagpal Singh Gill         co_return;
51*6d131aa7SJagpal Singh Gill     }
52*6d131aa7SJagpal Singh Gill 
53*6d131aa7SJagpal Singh Gill     std::error_code ec;
54*6d131aa7SJagpal Singh Gill     tmpDirPath = tmpDir;
55*6d131aa7SJagpal Singh Gill     softwareUtils::RemovablePath tmpDirToRemove(tmpDirPath);
56*6d131aa7SJagpal Singh Gill 
57*6d131aa7SJagpal Singh Gill     // Untar tarball into the tmp dir
58*6d131aa7SJagpal Singh Gill     if (!softwareUtils::unTar(image, tmpDirPath.string()))
59*6d131aa7SJagpal Singh Gill     {
60*6d131aa7SJagpal Singh Gill         error("Error occurred during untar");
61*6d131aa7SJagpal Singh Gill         processImageFailed(image, id);
62*6d131aa7SJagpal Singh Gill         co_return;
63*6d131aa7SJagpal Singh Gill     }
64*6d131aa7SJagpal Singh Gill 
65*6d131aa7SJagpal Singh Gill     fs::path manifestPath = tmpDirPath;
66*6d131aa7SJagpal Singh Gill     manifestPath /= MANIFEST_FILE_NAME;
67*6d131aa7SJagpal Singh Gill 
68*6d131aa7SJagpal Singh Gill     // Get version
69*6d131aa7SJagpal Singh Gill     auto version = Version::getValue(manifestPath.string(), "version");
70*6d131aa7SJagpal Singh Gill     if (version.empty())
71*6d131aa7SJagpal Singh Gill     {
72*6d131aa7SJagpal Singh Gill         error("Unable to read version from manifest file");
73*6d131aa7SJagpal Singh Gill         processImageFailed(image, id);
74*6d131aa7SJagpal Singh Gill         co_return;
75*6d131aa7SJagpal Singh Gill     }
76*6d131aa7SJagpal Singh Gill 
77*6d131aa7SJagpal Singh Gill     // Get running machine name
78*6d131aa7SJagpal Singh Gill     std::string currMachine = Version::getBMCMachine(OS_RELEASE_FILE);
79*6d131aa7SJagpal Singh Gill     if (currMachine.empty())
80*6d131aa7SJagpal Singh Gill     {
81*6d131aa7SJagpal Singh Gill         auto path = OS_RELEASE_FILE;
82*6d131aa7SJagpal Singh Gill         error("Failed to read machine name from osRelease: {PATH}", "PATH",
83*6d131aa7SJagpal Singh Gill               path);
84*6d131aa7SJagpal Singh Gill         processImageFailed(image, id);
85*6d131aa7SJagpal Singh Gill         co_return;
86*6d131aa7SJagpal Singh Gill     }
87*6d131aa7SJagpal Singh Gill 
88*6d131aa7SJagpal Singh Gill     // Get machine name for image to be upgraded
89*6d131aa7SJagpal Singh Gill     std::string machineStr =
90*6d131aa7SJagpal Singh Gill         Version::getValue(manifestPath.string(), "MachineName");
91*6d131aa7SJagpal Singh Gill     if (!machineStr.empty())
92*6d131aa7SJagpal Singh Gill     {
93*6d131aa7SJagpal Singh Gill         if (machineStr != currMachine)
94*6d131aa7SJagpal Singh Gill         {
95*6d131aa7SJagpal Singh Gill             error(
96*6d131aa7SJagpal Singh Gill                 "BMC upgrade: Machine name doesn't match: {CURRENT_MACHINE} vs {NEW_MACHINE}",
97*6d131aa7SJagpal Singh Gill                 "CURRENT_MACHINE", currMachine, "NEW_MACHINE", machineStr);
98*6d131aa7SJagpal Singh Gill             processImageFailed(image, id);
99*6d131aa7SJagpal Singh Gill             co_return;
100*6d131aa7SJagpal Singh Gill         }
101*6d131aa7SJagpal Singh Gill     }
102*6d131aa7SJagpal Singh Gill     else
103*6d131aa7SJagpal Singh Gill     {
104*6d131aa7SJagpal Singh Gill         warning("No machine name in Manifest file");
105*6d131aa7SJagpal Singh Gill     }
106*6d131aa7SJagpal Singh Gill 
107*6d131aa7SJagpal Singh Gill     // Get purpose
108*6d131aa7SJagpal Singh Gill     auto purposeString = Version::getValue(manifestPath.string(), "purpose");
109*6d131aa7SJagpal Singh Gill     if (purposeString.empty())
110*6d131aa7SJagpal Singh Gill     {
111*6d131aa7SJagpal Singh Gill         error("Unable to read purpose from manifest file");
112*6d131aa7SJagpal Singh Gill         processImageFailed(image, id);
113*6d131aa7SJagpal Singh Gill         co_return;
114*6d131aa7SJagpal Singh Gill     }
115*6d131aa7SJagpal Singh Gill     auto convertedPurpose =
116*6d131aa7SJagpal Singh Gill         sdbusplus::message::convert_from_string<Version::VersionPurpose>(
117*6d131aa7SJagpal Singh Gill             purposeString);
118*6d131aa7SJagpal Singh Gill     if (!convertedPurpose)
119*6d131aa7SJagpal Singh Gill     {
120*6d131aa7SJagpal Singh Gill         warning(
121*6d131aa7SJagpal Singh Gill             "Failed to convert manifest purpose ({PURPOSE}) to enum; setting to Unknown.",
122*6d131aa7SJagpal Singh Gill             "PURPOSE", purposeString);
123*6d131aa7SJagpal Singh Gill     }
124*6d131aa7SJagpal Singh Gill     auto purpose = convertedPurpose.value_or(Version::VersionPurpose::Unknown);
125*6d131aa7SJagpal Singh Gill 
126*6d131aa7SJagpal Singh Gill     // Get ExtendedVersion
127*6d131aa7SJagpal Singh Gill     std::string extendedVersion =
128*6d131aa7SJagpal Singh Gill         Version::getValue(manifestPath.string(), "ExtendedVersion");
129*6d131aa7SJagpal Singh Gill 
130*6d131aa7SJagpal Singh Gill     // Get CompatibleNames
131*6d131aa7SJagpal Singh Gill     std::vector<std::string> compatibleNames =
132*6d131aa7SJagpal Singh Gill         Version::getRepeatedValues(manifestPath.string(), "CompatibleName");
133*6d131aa7SJagpal Singh Gill 
134*6d131aa7SJagpal Singh Gill     // Rename IMG_UPLOAD_DIR/imageXXXXXX to IMG_UPLOAD_DIR/id as Manifest
135*6d131aa7SJagpal Singh Gill     // parsing succedded.
136*6d131aa7SJagpal Singh Gill     fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
137*6d131aa7SJagpal Singh Gill     imageDirPath /= id;
138*6d131aa7SJagpal Singh Gill     fs::rename(tmpDirPath, imageDirPath, ec);
139*6d131aa7SJagpal Singh Gill     tmpDirToRemove.path.clear();
140*6d131aa7SJagpal Singh Gill 
141*6d131aa7SJagpal Singh Gill     auto filePath = imageDirPath.string();
142*6d131aa7SJagpal Singh Gill     // Create Version object
143*6d131aa7SJagpal Singh Gill     auto state = itemUpdater.verifyAndCreateObjects(
144*6d131aa7SJagpal Singh Gill         id, objPath, version, purpose, extendedVersion, filePath,
145*6d131aa7SJagpal Singh Gill         compatibleNames);
146*6d131aa7SJagpal Singh Gill     if (state != ActivationIntf::Activations::Ready)
147*6d131aa7SJagpal Singh Gill     {
148*6d131aa7SJagpal Singh Gill         error("Software image is invalid");
149*6d131aa7SJagpal Singh Gill         processImageFailed(image, id);
150*6d131aa7SJagpal Singh Gill         co_return;
151*6d131aa7SJagpal Singh Gill     }
152*6d131aa7SJagpal Singh Gill     if (applyTime == ApplyTimeIntf::RequestedApplyTimes::Immediate ||
153*6d131aa7SJagpal Singh Gill         applyTime == ApplyTimeIntf::RequestedApplyTimes::OnReset)
154*6d131aa7SJagpal Singh Gill     {
155*6d131aa7SJagpal Singh Gill         itemUpdater.requestActivation(id);
156*6d131aa7SJagpal Singh Gill     }
157*6d131aa7SJagpal Singh Gill 
158*6d131aa7SJagpal Singh Gill     updateInProgress = false;
159*6d131aa7SJagpal Singh Gill     close(image);
160*6d131aa7SJagpal Singh Gill     co_return;
161*6d131aa7SJagpal Singh Gill }
162*6d131aa7SJagpal Singh Gill 
163*6d131aa7SJagpal Singh Gill sdbusplus::message::object_path
startUpdate(sdbusplus::message::unix_fd image,ApplyTimeIntf::RequestedApplyTimes applyTime)164*6d131aa7SJagpal Singh Gill     Manager::startUpdate(sdbusplus::message::unix_fd image,
165*6d131aa7SJagpal Singh Gill                          ApplyTimeIntf::RequestedApplyTimes applyTime)
166*6d131aa7SJagpal Singh Gill {
167*6d131aa7SJagpal Singh Gill     info("Starting update for image {FD}", "FD", static_cast<int>(image));
168*6d131aa7SJagpal Singh Gill     using sdbusplus::xyz::openbmc_project::Common::Error::Unavailable;
169*6d131aa7SJagpal Singh Gill     if (updateInProgress)
170*6d131aa7SJagpal Singh Gill     {
171*6d131aa7SJagpal Singh Gill         error("Failed to start as update is already in progress");
172*6d131aa7SJagpal Singh Gill         report<Unavailable>();
173*6d131aa7SJagpal Singh Gill         return sdbusplus::message::object_path();
174*6d131aa7SJagpal Singh Gill     }
175*6d131aa7SJagpal Singh Gill     updateInProgress = true;
176*6d131aa7SJagpal Singh Gill 
177*6d131aa7SJagpal Singh Gill     auto id = Version::getId(std::to_string(randomGen()));
178*6d131aa7SJagpal Singh Gill     auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
179*6d131aa7SJagpal Singh Gill 
180*6d131aa7SJagpal Singh Gill     // Create Activation Object
181*6d131aa7SJagpal Singh Gill     itemUpdater.createActivationWithApplyTime(id, objPath, applyTime);
182*6d131aa7SJagpal Singh Gill 
183*6d131aa7SJagpal Singh Gill     int newFd = dup(image);
184*6d131aa7SJagpal Singh Gill     ctx.spawn(processImage(newFd, applyTime, id, objPath));
185*6d131aa7SJagpal Singh Gill 
186*6d131aa7SJagpal Singh Gill     return sdbusplus::message::object_path(objPath);
187*6d131aa7SJagpal Singh Gill }
188*6d131aa7SJagpal Singh Gill 
189*6d131aa7SJagpal Singh Gill } // namespace phosphor::software::update
190