blob: 19e8a3dcbf89d08dbf17e495c0b6e8a9d4cf476c [file] [log] [blame]
Patrick Venture54c3b532018-08-01 11:45:49 -07001/*
Patrick Venture514f6482018-08-07 14:27:58 -07002 * Copyright 2018 Google Inc.
Patrick Venture54c3b532018-08-01 11:45:49 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "flash-ipmi.hpp"
18
Patrick Venture8ec019f2018-08-07 11:22:33 -070019#include <cstdio>
Patrick Venture7fc66de2018-08-07 14:53:02 -070020#include <fstream>
Patrick Venture8ec019f2018-08-07 11:22:33 -070021#include <phosphor-logging/log.hpp>
Patrick Venture9c6baad2018-08-07 16:10:45 -070022#include <sdbusplus/bus.hpp>
23
24/* systemd service to kick start a service. */
25static constexpr auto systemdService = "org.freedesktop.systemd1";
26static constexpr auto systemdRoot = "/org/freedesktop/systemd1";
27static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
28static constexpr auto verifyTarget = "verify_image.service";
Patrick Venture8ec019f2018-08-07 11:22:33 -070029
30using namespace phosphor::logging;
31
32namespace
33{
34
35/**
36 * Close a file pointer and set to null.
37 *
38 * @param[in] fd a pointer to your file handle.
39 */
40void closeFile(std::FILE** fd)
41{
42 if (!fd)
43 {
44 return;
45 }
46
47 if (*fd)
48 {
49 std::fclose(*fd);
50 (*fd) = nullptr;
51 }
52}
Patrick Venture8f378c92018-08-31 10:01:43 -070053} // namespace
Patrick Venture8ec019f2018-08-07 11:22:33 -070054
55void FlashUpdate::closeEverything()
56{
57 closeFile(&flashFd);
Patrick Venture6f17bd22018-08-07 13:24:17 -070058 closeFile(&hashFd);
Patrick Venture8ec019f2018-08-07 11:22:33 -070059}
60
Patrick Venture605f75f2018-08-07 16:27:05 -070061void FlashUpdate::deleteEverything()
62{
63 /* Assumes you've called closeEverything() already */
64
65 (void)std::remove(tmpPath.c_str());
66 (void)std::remove(verifyPath.c_str());
67
68 /* hashPath is optional. */
69 if (!hashPath.empty())
70 {
71 (void)std::remove(hashPath.c_str());
72 }
73}
74
Patrick Venture8ec019f2018-08-07 11:22:33 -070075FlashUpdate::~FlashUpdate()
76{
77 /* Close without deleting. This object can only be destroyed if the ipmi
78 * daemon unloads it, by closing down. In this event, we want the verified
79 * file to live on.
80 */
81 closeEverything();
82}
83
Patrick Venture54c3b532018-08-01 11:45:49 -070084void FlashUpdate::abortEverything()
85{
Patrick Venture8ec019f2018-08-07 11:22:33 -070086 closeEverything();
87
Patrick Venture605f75f2018-08-07 16:27:05 -070088 /* Stop the systemd unit if it was running. */
89 auto method = bus.new_method_call(systemdService, systemdRoot,
90 systemdInterface, "StopUnit");
91 method.append(verifyTarget);
92 method.append("replace");
93 bus.call_noreply(method);
94
95 deleteEverything();
Patrick Venture54c3b532018-08-01 11:45:49 -070096 return;
97}
98
99bool FlashUpdate::openEverything()
100{
Patrick Venture3c086f22018-08-07 11:59:20 -0700101 flashFd = std::fopen(tmpPath.c_str(), "wb");
Patrick Venture8ec019f2018-08-07 11:22:33 -0700102 if (flashFd == nullptr)
103 {
104 log<level::INFO>("Unable to open staging path",
105 entry("PATH=%s", tmpPath.c_str()));
106 return false;
107 }
108
Patrick Venture6f17bd22018-08-07 13:24:17 -0700109 /* hash path is basically optional. */
110 if (!hashPath.empty())
111 {
112 hashFd = std::fopen(hashPath.c_str(), "wb");
113 if (hashFd == nullptr)
114 {
115 log<level::INFO>("Unable to open hash storage path",
116 entry("PATH=%s", hashPath.c_str()));
117 closeFile(&flashFd);
118 return false;
119 }
120 }
121
Patrick Venture54c3b532018-08-01 11:45:49 -0700122 return true;
123}
124
125/* Prepare to receive a BMC image and then a signature. */
Patrick Venture8ec019f2018-08-07 11:22:33 -0700126bool FlashUpdate::start(uint32_t length)
Patrick Venture54c3b532018-08-01 11:45:49 -0700127{
Patrick Venture54c3b532018-08-01 11:45:49 -0700128 /* Close out and delete everything. */
129 abortEverything();
130
Patrick Venture8ec019f2018-08-07 11:22:33 -0700131 /* TODO: Validate request->length */
132 flashLength = length;
133
Patrick Venture54c3b532018-08-01 11:45:49 -0700134 /* Start over! */
135 return openEverything();
136}
Patrick Venture79e131f2018-08-01 13:34:35 -0700137
Patrick Venture3c086f22018-08-07 11:59:20 -0700138bool FlashUpdate::writeBlock(std::FILE* fd, uint32_t offset,
139 const std::vector<uint8_t>& bytes)
140{
141 /* Seek into position, let's assume fseek won't call if offset matches
142 * position.
143 */
144 if (std::fseek(fd, offset, SEEK_SET))
145 {
146 log<level::ERR>("Unable to seek into file to write bytes.");
147 return false;
148 }
149
150 /* Write the bytes. */
151 auto written = std::fwrite(bytes.data(), 1, bytes.size(), fd);
152
153 if (written != bytes.size())
154 {
155 log<level::ERR>("Unable to write all the bytes requested.");
156 return false;
157 }
158
159 (void)std::fflush(fd);
160 return true;
161}
162
Patrick Venture79e131f2018-08-01 13:34:35 -0700163bool FlashUpdate::flashData(uint32_t offset, const std::vector<uint8_t>& bytes)
164{
Patrick Venture3c086f22018-08-07 11:59:20 -0700165 if (flashFd)
166 {
167 return writeBlock(flashFd, offset, bytes);
168 }
169
Patrick Venture79e131f2018-08-01 13:34:35 -0700170 return false;
171}
Patrick Venture2c1205d2018-08-03 10:23:14 -0700172
173bool FlashUpdate::flashFinish()
174{
Patrick Venture57703662018-08-07 12:52:24 -0700175 /* If it's open, close it. */
176 if (flashFd)
177 {
178 closeFile(&flashFd);
179 return true;
180 }
181
Patrick Venture2c1205d2018-08-03 10:23:14 -0700182 return false;
183}
Patrick Venture8d9f7322018-08-03 10:39:13 -0700184
185bool FlashUpdate::startHash(uint32_t length)
186{
Patrick Venture6f17bd22018-08-07 13:24:17 -0700187 if (!hashFd)
188 {
189 return false;
190 }
191
192 hashLength = length;
193 return true;
Patrick Venture8d9f7322018-08-03 10:39:13 -0700194}
Patrick Venturecfe66872018-08-03 13:32:33 -0700195
196bool FlashUpdate::hashData(uint32_t offset, const std::vector<uint8_t>& bytes)
197{
Patrick Venturecbe51492018-08-07 14:09:17 -0700198 if (hashFd)
199 {
200 return writeBlock(hashFd, offset, bytes);
201 }
202
Patrick Venturecfe66872018-08-03 13:32:33 -0700203 return false;
204}
Patrick Venturefbc7d192018-08-03 13:54:21 -0700205
206bool FlashUpdate::hashFinish()
207{
Patrick Ventured5f590f2018-08-07 14:18:09 -0700208 if (hashFd)
209 {
210 closeFile(&hashFd);
211 return true;
212 }
213
Patrick Venturefbc7d192018-08-03 13:54:21 -0700214 return false;
215}
Patrick Venture1cb87d22018-08-03 18:22:09 -0700216
217bool FlashUpdate::startDataVerification()
218{
Patrick Venture9c6baad2018-08-07 16:10:45 -0700219 auto method = bus.new_method_call(systemdService, systemdRoot,
220 systemdInterface, "StartUnit");
221 method.append(verifyTarget);
222 method.append("replace");
223 bus.call_noreply(method);
224
Patrick Venture1cb87d22018-08-03 18:22:09 -0700225 return false;
226}
Patrick Venture5c251ca2018-08-03 18:31:01 -0700227
228bool FlashUpdate::abortUpdate()
229{
Patrick Venture605f75f2018-08-07 16:27:05 -0700230 abortEverything();
231 return true;
Patrick Venture5c251ca2018-08-03 18:31:01 -0700232}
Patrick Venturefdc65b22018-08-07 14:37:58 -0700233
234VerifyCheckResponse FlashUpdate::checkVerify()
235{
Patrick Venture7fc66de2018-08-07 14:53:02 -0700236 auto result = VerifyCheckResponse::other;
237 std::ifstream ifs;
238 ifs.open(verifyPath);
239 if (ifs.good())
240 {
241 std::string status;
242 /*
243 * Check for the contents of the file, excepting:
244 * running, success, or failed.
245 */
246 ifs >> status;
247 if (status == "running")
248 {
249 result = VerifyCheckResponse::running;
250 }
251 else if (status == "success")
252 {
253 result = VerifyCheckResponse::success;
254 }
255 else if (status == "failed")
256 {
257 result = VerifyCheckResponse::failed;
258 }
259 }
260
261 return result;
Patrick Venturefdc65b22018-08-07 14:37:58 -0700262}