blob: bc6c96f49a30d7913e78a46b57f67850584ced56 [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
158 if (mkdir(imageDirPath.c_str(), S_IRWXU) != 0)
159 {
160 log<level::ERR>("Error occured during mkdir",
161 entry("ERRNO=%d", errno));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500162 report<InternalFailure>(xyz::openbmc_project::Software::Version::
163 InternalFailure::FAIL("mkdir"));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500164 return -1;
165 }
166
167 // Untar tarball
Gunnar Mills3027bba2017-04-27 15:49:03 -0500168 auto rc = Manager::unTar(tarFilePath, imageDirPath.string());
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500169 if (rc < 0)
170 {
171 log<level::ERR>("Error occured during untar");
172 return -1;
173 }
174
Gunnar Mills3027bba2017-04-27 15:49:03 -0500175 // Create Version object
176 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
177
178 this->versions.insert(std::make_pair(
179 id,
180 std::make_unique<Version>(
181 this->bus,
182 objPath,
183 version,
184 purpose,
185 imageDirPath.string())));
186
Gunnar Millse91d3212017-04-19 15:42:47 -0500187 return 0;
188}
189
Gunnar Mills3027bba2017-04-27 15:49:03 -0500190int Manager::unTar(const std::string& tarFilePath,
191 const std::string& extractDirPath)
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500192{
193 if (tarFilePath.empty())
194 {
195 log<level::ERR>("Error TarFilePath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500196 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
197 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500198 return -1;
199 }
200 if (extractDirPath.empty())
201 {
202 log<level::ERR>("Error ExtractDirPath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500203 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
204 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500205 return -1;
206 }
207
208 log<level::INFO>("Untaring",
209 entry("FILENAME=%s", tarFilePath),
210 entry("EXTRACTIONDIR=%s", extractDirPath));
211 int status = 0;
212 pid_t pid = fork();
213
214 if (pid == 0)
215 {
216 // child process
217 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(),
218 "-C", extractDirPath.c_str(), (char*)0);
219 // execl only returns on fail
220 log<level::ERR>("Failed to untar file",
221 entry("FILENAME=%s", tarFilePath));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500222 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
223 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500224 return -1;
225 }
226 else if (pid > 0)
227 {
228 waitpid(pid, &status, 0);
229 }
230 else
231 {
232 log<level::ERR>("fork() failed.");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500233 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
234 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500235 return -1;
236 }
237
238 return 0;
239}
Gunnar Mills3027bba2017-04-27 15:49:03 -0500240
Gunnar Millse91d3212017-04-19 15:42:47 -0500241} // namespace manager
242} // namespace software
243} // namepsace phosphor