blob: 859919694dde1fd1648bf1d8ea29996978d274a9 [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
131 std::transform(purposeString.begin(), purposeString.end(),
132 purposeString.begin(), ::tolower);
133
134 auto purpose = Version::VersionPurpose::Unknown;
135 if (purposeString.compare("bmc") == 0)
136 {
137 purpose = Version::VersionPurpose::BMC;
138 }
139 else if (purposeString.compare("host") == 0)
140 {
141 purpose = Version::VersionPurpose::Host;
142 }
143 else if (purposeString.compare("system") == 0)
144 {
145 purpose = Version::VersionPurpose::System;
146 }
147 else if (purposeString.compare("other") == 0)
148 {
149 purpose = Version::VersionPurpose::Other;
150 }
151
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500152 // Compute id
153 auto id = Version::getId(version);
154
155 fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
156 imageDirPath /= id;
157
Gunnar Millsf576bca2017-05-18 13:40:39 -0500158 if (fs::exists(imageDirPath))
159 {
160 fs::remove_all(imageDirPath);
161 }
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500162 if (mkdir(imageDirPath.c_str(), S_IRWXU) != 0)
163 {
164 log<level::ERR>("Error occured during mkdir",
165 entry("ERRNO=%d", errno));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500166 report<InternalFailure>(xyz::openbmc_project::Software::Version::
167 InternalFailure::FAIL("mkdir"));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500168 return -1;
169 }
170
171 // Untar tarball
Gunnar Mills3027bba2017-04-27 15:49:03 -0500172 auto rc = Manager::unTar(tarFilePath, imageDirPath.string());
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500173 if (rc < 0)
174 {
175 log<level::ERR>("Error occured during untar");
176 return -1;
177 }
178
Gunnar Mills3027bba2017-04-27 15:49:03 -0500179 // Create Version object
180 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
181
182 this->versions.insert(std::make_pair(
183 id,
184 std::make_unique<Version>(
185 this->bus,
186 objPath,
187 version,
188 purpose,
189 imageDirPath.string())));
190
Gunnar Millse91d3212017-04-19 15:42:47 -0500191 return 0;
192}
193
Gunnar Mills3027bba2017-04-27 15:49:03 -0500194int Manager::unTar(const std::string& tarFilePath,
195 const std::string& extractDirPath)
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500196{
197 if (tarFilePath.empty())
198 {
199 log<level::ERR>("Error TarFilePath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500200 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
201 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500202 return -1;
203 }
204 if (extractDirPath.empty())
205 {
206 log<level::ERR>("Error ExtractDirPath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500207 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
208 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500209 return -1;
210 }
211
212 log<level::INFO>("Untaring",
213 entry("FILENAME=%s", tarFilePath),
214 entry("EXTRACTIONDIR=%s", extractDirPath));
215 int status = 0;
216 pid_t pid = fork();
217
218 if (pid == 0)
219 {
220 // child process
221 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(),
222 "-C", extractDirPath.c_str(), (char*)0);
223 // execl only returns on fail
224 log<level::ERR>("Failed to untar file",
225 entry("FILENAME=%s", tarFilePath));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500226 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
227 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500228 return -1;
229 }
230 else if (pid > 0)
231 {
232 waitpid(pid, &status, 0);
233 }
234 else
235 {
236 log<level::ERR>("fork() failed.");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500237 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
238 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500239 return -1;
240 }
241
242 return 0;
243}
Gunnar Mills3027bba2017-04-27 15:49:03 -0500244
Gunnar Millse91d3212017-04-19 15:42:47 -0500245} // namespace manager
246} // namespace software
247} // namepsace phosphor