blob: 605050c006e1192ae57a13e9fdaed2fb8beada95 [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);
Gunnar Mills3027bba2017-04-27 15:49:03 -0500133 auto purpose = Version::VersionPurpose::Unknown;
134 if (purposeString.compare("bmc") == 0)
135 {
136 purpose = Version::VersionPurpose::BMC;
137 }
138 else if (purposeString.compare("host") == 0)
139 {
140 purpose = Version::VersionPurpose::Host;
141 }
142 else if (purposeString.compare("system") == 0)
143 {
144 purpose = Version::VersionPurpose::System;
145 }
146 else if (purposeString.compare("other") == 0)
147 {
148 purpose = Version::VersionPurpose::Other;
149 }
150
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500151 // Compute id
152 auto id = Version::getId(version);
153
154 fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
155 imageDirPath /= id;
156
Gunnar Millsf576bca2017-05-18 13:40:39 -0500157 if (fs::exists(imageDirPath))
158 {
159 fs::remove_all(imageDirPath);
160 }
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500161 if (mkdir(imageDirPath.c_str(), S_IRWXU) != 0)
162 {
163 log<level::ERR>("Error occured during mkdir",
164 entry("ERRNO=%d", errno));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500165 report<InternalFailure>(xyz::openbmc_project::Software::Version::
166 InternalFailure::FAIL("mkdir"));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500167 return -1;
168 }
169
170 // Untar tarball
Gunnar Mills9ec18ef2017-05-24 11:10:46 -0500171 auto rc = unTar(tarFilePath, imageDirPath.string());
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500172 if (rc < 0)
173 {
174 log<level::ERR>("Error occured during untar");
175 return -1;
176 }
177
Gunnar Mills3027bba2017-04-27 15:49:03 -0500178 // Create Version object
179 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
180
181 this->versions.insert(std::make_pair(
182 id,
183 std::make_unique<Version>(
184 this->bus,
185 objPath,
186 version,
187 purpose,
188 imageDirPath.string())));
189
Gunnar Millse91d3212017-04-19 15:42:47 -0500190 return 0;
191}
192
Gunnar Mills3027bba2017-04-27 15:49:03 -0500193int Manager::unTar(const std::string& tarFilePath,
194 const std::string& extractDirPath)
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500195{
196 if (tarFilePath.empty())
197 {
198 log<level::ERR>("Error TarFilePath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500199 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
200 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500201 return -1;
202 }
203 if (extractDirPath.empty())
204 {
205 log<level::ERR>("Error ExtractDirPath is empty");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500206 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
207 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500208 return -1;
209 }
210
211 log<level::INFO>("Untaring",
212 entry("FILENAME=%s", tarFilePath),
213 entry("EXTRACTIONDIR=%s", extractDirPath));
214 int status = 0;
215 pid_t pid = fork();
216
217 if (pid == 0)
218 {
219 // child process
220 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(),
221 "-C", extractDirPath.c_str(), (char*)0);
222 // execl only returns on fail
223 log<level::ERR>("Failed to untar file",
224 entry("FILENAME=%s", tarFilePath));
Gunnar Mills93c12d32017-05-10 13:11:53 -0500225 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
226 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500227 return -1;
228 }
229 else if (pid > 0)
230 {
231 waitpid(pid, &status, 0);
232 }
233 else
234 {
235 log<level::ERR>("fork() failed.");
Gunnar Mills93c12d32017-05-10 13:11:53 -0500236 report<UnTarFailure>(xyz::openbmc_project::Software::Version::
237 UnTarFailure::PATH(tarFilePath.c_str()));
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500238 return -1;
239 }
240
241 return 0;
242}
Gunnar Mills3027bba2017-04-27 15:49:03 -0500243
Gunnar Millse91d3212017-04-19 15:42:47 -0500244} // namespace manager
245} // namespace software
246} // namepsace phosphor