blob: bc9ce9e18ce8c81b975db9c129bf116268c7f73f [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,
175 imageDirPath.string())));
176
Gunnar Millse91d3212017-04-19 15:42:47 -0500177 return 0;
178}
179
Leonel Gonzalez50d559c2017-07-07 14:38:25 -0500180void Manager::erase(std::string entryId)
181{
182 auto it = versions.find(entryId);
183 if (it == versions.end())
184 {
185 return;
186 }
187 // Delete image dir
188 fs::path imageDirPath = (*(it->second)).path();
189 if (fs::exists(imageDirPath))
190 {
191 fs::remove_all(imageDirPath);
192 }
193 this->versions.erase(entryId);
194}
195
Gunnar Mills3027bba2017-04-27 15:49:03 -0500196int Manager::unTar(const std::string& tarFilePath,
197 const std::string& extractDirPath)
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500198{
199 if (tarFilePath.empty())
200 {
201 log<level::ERR>("Error TarFilePath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500202 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
203 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500204 return -1;
205 }
206 if (extractDirPath.empty())
207 {
208 log<level::ERR>("Error ExtractDirPath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500209 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
210 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500211 return -1;
212 }
213
214 log<level::INFO>("Untaring",
215 entry("FILENAME=%s", tarFilePath),
216 entry("EXTRACTIONDIR=%s", extractDirPath));
217 int status = 0;
218 pid_t pid = fork();
219
220 if (pid == 0)
221 {
222 // child process
223 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(),
224 "-C", extractDirPath.c_str(), (char*)0);
225 // execl only returns on fail
226 log<level::ERR>("Failed to untar file",
227 entry("FILENAME=%s", tarFilePath));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500228 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
229 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500230 return -1;
231 }
232 else if (pid > 0)
233 {
234 waitpid(pid, &status, 0);
235 }
236 else
237 {
238 log<level::ERR>("fork() failed.");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500239 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
240 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500241 return -1;
242 }
243
244 return 0;
245}
Gunnar Mills3027bba2017-04-27 15:49:03 -0500246
Gunnar Millse91d3212017-04-19 15:42:47 -0500247} // namespace manager
248} // namespace software
249} // namepsace phosphor