blob: 235a5d6bb85487012e856f50e7f6d3fc9d94dd3e [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>
11#include "config.h"
12#include "version.hpp"
Gunnar Mills3027bba2017-04-27 15:49:03 -050013#include "watch.hpp"
Gunnar Millse91d3212017-04-19 15:42:47 -050014#include "image_manager.hpp"
15
16namespace phosphor
17{
18namespace software
19{
20namespace manager
21{
22
Gunnar Mills19e4ce52017-04-27 11:24:19 -050023using namespace phosphor::logging;
24namespace fs = std::experimental::filesystem;
25
26struct RemovablePath
27{
28 fs::path path;
29
30 RemovablePath(const fs::path& path) : path(path) {}
31 ~RemovablePath()
32 {
33 fs::remove_all(path);
34 }
35};
36
Gunnar Mills3027bba2017-04-27 15:49:03 -050037int Manager::processImage(const std::string& tarFilePath)
Gunnar Millse91d3212017-04-19 15:42:47 -050038{
Gunnar Mills19e4ce52017-04-27 11:24:19 -050039 if (!fs::is_regular_file(tarFilePath))
40 {
41 log<level::ERR>("Error tarball does not exist",
42 entry("FILENAME=%s", tarFilePath));
43 return -1;
44
45 }
46 RemovablePath tarPathRemove(tarFilePath);
47 fs::path tmpDirPath(std::string{IMG_UPLOAD_DIR});
48 tmpDirPath /= "imageXXXXXX";
49
50 // Need tmp dir to write MANIFEST file to.
51 if (!mkdtemp(const_cast<char*>(tmpDirPath.c_str())))
52 {
53 log<level::ERR>("Error occured during mkdtemp",
54 entry("ERRNO=%d", errno));
55 return -1;
56 }
57
58 RemovablePath tmpDirRemove(tmpDirPath);
59 fs::path manifestPath = tmpDirPath;
60 manifestPath /= MANIFEST_FILE_NAME;
61 int status = 0;
62 pid_t pid = fork();
63
64 // Get the MANIFEST FILE
65 if (pid == 0)
66 {
67 // child process
68 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(), MANIFEST_FILE_NAME,
69 "-C", tmpDirPath.c_str(), (char*)0);
70 // execl only returns on fail
71 log<level::ERR>("Failed to untar file",
72 entry("FILENAME=%s", tarFilePath));
73 return -1;
74 }
75 else if (pid > 0)
76 {
77 waitpid(pid, &status, 0);
78 }
79 else
80 {
81 log<level::ERR>("fork() failed.");
82 return -1;
83 }
84
85 // Verify the manifest file
86 if (!fs::is_regular_file(manifestPath))
87 {
88 log<level::ERR>("Error No manifest file");
89 return -1;
90 }
91
92 // Get version
93 auto version = Version::getValue(manifestPath.string(), "version");
94 if (version.empty())
95 {
96 log<level::ERR>("Error unable to read version from manifest file");
97 return -1;
98 }
99
Gunnar Mills3027bba2017-04-27 15:49:03 -0500100 // Get purpose
101 auto purposeString = Version::getValue(manifestPath.string(), "purpose");
102 if (purposeString.empty())
103 {
104 log<level::ERR>("Error unable to read purpose from manifest file");
105 return -1;
106 }
107
108 std::transform(purposeString.begin(), purposeString.end(),
109 purposeString.begin(), ::tolower);
110
111 auto purpose = Version::VersionPurpose::Unknown;
112 if (purposeString.compare("bmc") == 0)
113 {
114 purpose = Version::VersionPurpose::BMC;
115 }
116 else if (purposeString.compare("host") == 0)
117 {
118 purpose = Version::VersionPurpose::Host;
119 }
120 else if (purposeString.compare("system") == 0)
121 {
122 purpose = Version::VersionPurpose::System;
123 }
124 else if (purposeString.compare("other") == 0)
125 {
126 purpose = Version::VersionPurpose::Other;
127 }
128
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500129 // Compute id
130 auto id = Version::getId(version);
131
132 fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
133 imageDirPath /= id;
134
135 if (mkdir(imageDirPath.c_str(), S_IRWXU) != 0)
136 {
137 log<level::ERR>("Error occured during mkdir",
138 entry("ERRNO=%d", errno));
139 return -1;
140 }
141
142 // Untar tarball
Gunnar Mills3027bba2017-04-27 15:49:03 -0500143 auto rc = Manager::unTar(tarFilePath, imageDirPath.string());
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500144 if (rc < 0)
145 {
146 log<level::ERR>("Error occured during untar");
147 return -1;
148 }
149
Gunnar Mills3027bba2017-04-27 15:49:03 -0500150 // Create Version object
151 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
152
153 this->versions.insert(std::make_pair(
154 id,
155 std::make_unique<Version>(
156 this->bus,
157 objPath,
158 version,
159 purpose,
160 imageDirPath.string())));
161
Gunnar Millse91d3212017-04-19 15:42:47 -0500162 return 0;
163}
164
Gunnar Mills3027bba2017-04-27 15:49:03 -0500165int Manager::unTar(const std::string& tarFilePath,
166 const std::string& extractDirPath)
Gunnar Mills19e4ce52017-04-27 11:24:19 -0500167{
168 if (tarFilePath.empty())
169 {
170 log<level::ERR>("Error TarFilePath is empty");
171 return -1;
172 }
173 if (extractDirPath.empty())
174 {
175 log<level::ERR>("Error ExtractDirPath is empty");
176 return -1;
177 }
178
179 log<level::INFO>("Untaring",
180 entry("FILENAME=%s", tarFilePath),
181 entry("EXTRACTIONDIR=%s", extractDirPath));
182 int status = 0;
183 pid_t pid = fork();
184
185 if (pid == 0)
186 {
187 // child process
188 execl("/bin/tar", "tar", "-xf", tarFilePath.c_str(),
189 "-C", extractDirPath.c_str(), (char*)0);
190 // execl only returns on fail
191 log<level::ERR>("Failed to untar file",
192 entry("FILENAME=%s", tarFilePath));
193 return -1;
194 }
195 else if (pid > 0)
196 {
197 waitpid(pid, &status, 0);
198 }
199 else
200 {
201 log<level::ERR>("fork() failed.");
202 return -1;
203 }
204
205 return 0;
206}
Gunnar Mills3027bba2017-04-27 15:49:03 -0500207
Gunnar Millse91d3212017-04-19 15:42:47 -0500208} // namespace manager
209} // namespace software
210} // namepsace phosphor