blob: 5242d8bce652618e3543da55f365b24a6aeb360e [file] [log] [blame]
Gunnar Millse91d3212017-04-19 15:42:47 -05001#include <string>
Gunnar Mills19e4ce52017-04-27 11:24:19 -05002#include <experimental/filesystem>
3#include <stdlib.h>
4#include <cstring>
5#include <stdio.h>
6#include <unistd.h>
Gunnar Mills3027bba2017-04-27 15:49:03 -05007#include <algorithm>
Gunnar Mills19e4ce52017-04-27 11:24:19 -05008#include <sys/wait.h>
9#include <sys/stat.h>
10#include <phosphor-logging/log.hpp>
Gunnar Mills93c12d32017-05-10 13:11:53 -050011#include <phosphor-logging/elog.hpp>
12#include <elog-errors.hpp>
13#include <xyz/openbmc_project/Software/Version/error.hpp>
Gunnar Mills19e4ce52017-04-27 11:24:19 -050014#include "config.h"
15#include "version.hpp"
Gunnar Mills3027bba2017-04-27 15:49:03 -050016#include "watch.hpp"
Gunnar Millse91d3212017-04-19 15:42:47 -050017#include "image_manager.hpp"
18
19namespace phosphor
20{
21namespace software
22{
23namespace manager
24{
25
Gunnar Mills19e4ce52017-04-27 11:24:19 -050026using namespace phosphor::logging;
Gunnar Mills93c12d32017-05-10 13:11:53 -050027using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error;
Gunnar Mills19e4ce52017-04-27 11:24:19 -050028namespace fs = std::experimental::filesystem;
29
30struct RemovablePath
31{
32 fs::path path;
33
34 RemovablePath(const fs::path& path) : path(path) {}
35 ~RemovablePath()
36 {
37 fs::remove_all(path);
38 }
39};
40
Gunnar Mills3027bba2017-04-27 15:49:03 -050041int Manager::processImage(const std::string& tarFilePath)
Gunnar Millse91d3212017-04-19 15:42:47 -050042{
Gunnar Mills19e4ce52017-04-27 11:24:19 -050043 if (!fs::is_regular_file(tarFilePath))
44 {
45 log<level::ERR>("Error tarball does not exist",
46 entry("FILENAME=%s", tarFilePath));
Gunnar Mills93c12d32017-05-10 13:11:53 -050047 report<ManifestFileFailure>(xyz::openbmc_project::Software::Version::
48 ManifestFileFailure::PATH(
49 tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -050050 return -1;
51
52 }
53 RemovablePath tarPathRemove(tarFilePath);
54 fs::path tmpDirPath(std::string{IMG_UPLOAD_DIR});
55 tmpDirPath /= "imageXXXXXX";
56
57 // Need tmp dir to write MANIFEST file to.
58 if (!mkdtemp(const_cast<char*>(tmpDirPath.c_str())))
59 {
60 log<level::ERR>("Error occured during mkdtemp",
61 entry("ERRNO=%d", errno));
Gunnar Mills93c12d32017-05-10 13:11:53 -050062 report<InternalFailure>(xyz::openbmc_project::Software::Version::
63 InternalFailure::FAIL("mkdtemp"));
Gunnar Mills19e4ce52017-04-27 11:24:19 -050064 return -1;
65 }
66
67 RemovablePath tmpDirRemove(tmpDirPath);
68 fs::path manifestPath = tmpDirPath;
69 manifestPath /= MANIFEST_FILE_NAME;
70 int status = 0;
71 pid_t pid = fork();
72
73 // Get the MANIFEST FILE
74 if (pid == 0)
75 {
76 // child process
77 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(), MANIFEST_FILE_NAME,
78 "-C", tmpDirPath.c_str(), (char*)0);
79 // execl only returns on fail
80 log<level::ERR>("Failed to untar file",
81 entry("FILENAME=%s", tarFilePath));
Gunnar Mills93c12d32017-05-10 13:11:53 -050082 report<ManifestFileFailure>(xyz::openbmc_project::Software::Version::
83 ManifestFileFailure::PATH(
84 manifestPath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -050085 return -1;
86 }
87 else if (pid > 0)
88 {
89 waitpid(pid, &status, 0);
90 }
91 else
92 {
93 log<level::ERR>("fork() failed.");
Gunnar Mills93c12d32017-05-10 13:11:53 -050094 report<InternalFailure>(xyz::openbmc_project::Software::Version::
95 InternalFailure::FAIL("fork"));
Gunnar Mills19e4ce52017-04-27 11:24:19 -050096 return -1;
97 }
98
99 // Verify the manifest file
100 if (!fs::is_regular_file(manifestPath))
101 {
102 log<level::ERR>("Error No manifest file");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500103 report<ManifestFileFailure>(xyz::openbmc_project::Software::Version::
104 ManifestFileFailure::PATH(
105 manifestPath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500106 return -1;
107 }
108
109 // Get version
110 auto version = Version::getValue(manifestPath.string(), "version");
111 if (version.empty())
112 {
113 log<level::ERR>("Error unable to read version from manifest file");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500114 report<ManifestFileFailure>(xyz::openbmc_project::Software::Version::
115 ManifestFileFailure::PATH(
116 manifestPath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500117 return -1;
118 }
119
Gunnar Mills3027bba2017-04-27 15:49:03 -0500120 // Get purpose
121 auto purposeString = Version::getValue(manifestPath.string(), "purpose");
122 if (purposeString.empty())
123 {
124 log<level::ERR>("Error unable to read purpose from manifest file");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500125 report<ManifestFileFailure>(xyz::openbmc_project::Software::Version::
126 ManifestFileFailure::PATH(
127 manifestPath.c_str()));
Gunnar Mills3027bba2017-04-27 15:49:03 -0500128 return -1;
129 }
130
Gunnar Mills3027bba2017-04-27 15:49:03 -0500131 auto purpose = Version::VersionPurpose::Unknown;
Leonel Gonzalez9a8d14c2017-06-22 11:42:24 -0500132 try {
133 purpose = Version::convertVersionPurposeFromString(purposeString);
134 } catch (const sdbusplus::exception::InvalidEnumString& e) {
135 log<level::ERR>("Error: Failed to convert manifest purpose to enum. Setting to Unknown.");
Gunnar Mills3027bba2017-04-27 15:49:03 -0500136 }
137
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500138 // Compute id
139 auto id = Version::getId(version);
140
141 fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
142 imageDirPath /= id;
143
Gunnar Millsf576bca2017-05-18 13:40:39 -0500144 if (fs::exists(imageDirPath))
145 {
146 fs::remove_all(imageDirPath);
147 }
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500148 if (mkdir(imageDirPath.c_str(), S_IRWXU) != 0)
149 {
150 log<level::ERR>("Error occured during mkdir",
151 entry("ERRNO=%d", errno));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500152 report<InternalFailure>(xyz::openbmc_project::Software::Version::
153 InternalFailure::FAIL("mkdir"));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500154 return -1;
155 }
156
157 // Untar tarball
Gunnar Mills9ec18ef2017-05-24 11:10:46 -0500158 auto rc = unTar(tarFilePath, imageDirPath.string());
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500159 if (rc < 0)
160 {
161 log<level::ERR>("Error occured during untar");
162 return -1;
163 }
164
Gunnar Mills3027bba2017-04-27 15:49:03 -0500165 // Create Version object
166 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
167
168 this->versions.insert(std::make_pair(
169 id,
170 std::make_unique<Version>(
171 this->bus,
172 objPath,
173 version,
174 purpose,
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500175 imageDirPath.string(),
176 std::bind(&Manager::erase,
177 this,
178 std::placeholders::_1))));
Gunnar Mills3027bba2017-04-27 15:49:03 -0500179
Gunnar Millse91d3212017-04-19 15:42:47 -0500180 return 0;
181}
182
Leonel Gonzalez50d559c2017-07-07 14:38:25 -0500183void Manager::erase(std::string entryId)
184{
185 auto it = versions.find(entryId);
186 if (it == versions.end())
187 {
188 return;
189 }
190 // Delete image dir
191 fs::path imageDirPath = (*(it->second)).path();
192 if (fs::exists(imageDirPath))
193 {
194 fs::remove_all(imageDirPath);
195 }
196 this->versions.erase(entryId);
197}
198
Gunnar Mills3027bba2017-04-27 15:49:03 -0500199int Manager::unTar(const std::string& tarFilePath,
200 const std::string& extractDirPath)
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500201{
202 if (tarFilePath.empty())
203 {
204 log<level::ERR>("Error TarFilePath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500205 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
206 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500207 return -1;
208 }
209 if (extractDirPath.empty())
210 {
211 log<level::ERR>("Error ExtractDirPath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500212 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
213 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500214 return -1;
215 }
216
217 log<level::INFO>("Untaring",
218 entry("FILENAME=%s", tarFilePath),
219 entry("EXTRACTIONDIR=%s", extractDirPath));
220 int status = 0;
221 pid_t pid = fork();
222
223 if (pid == 0)
224 {
225 // child process
226 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(),
227 "-C", extractDirPath.c_str(), (char*)0);
228 // execl only returns on fail
229 log<level::ERR>("Failed to untar file",
230 entry("FILENAME=%s", tarFilePath));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500231 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
232 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500233 return -1;
234 }
235 else if (pid > 0)
236 {
237 waitpid(pid, &status, 0);
238 }
239 else
240 {
241 log<level::ERR>("fork() failed.");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500242 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
243 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500244 return -1;
245 }
246
247 return 0;
248}
Gunnar Mills3027bba2017-04-27 15:49:03 -0500249
Gunnar Millse91d3212017-04-19 15:42:47 -0500250} // namespace manager
251} // namespace software
252} // namepsace phosphor