blob: e4fafc778d7fac6f782b84f986ecc2030ac08518 [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>
22
23using namespace phosphor::logging;
24
25namespace
26{
27
28/**
29 * Close a file pointer and set to null.
30 *
31 * @param[in] fd a pointer to your file handle.
32 */
33void closeFile(std::FILE** fd)
34{
35 if (!fd)
36 {
37 return;
38 }
39
40 if (*fd)
41 {
42 std::fclose(*fd);
43 (*fd) = nullptr;
44 }
45}
46}
47
48void FlashUpdate::closeEverything()
49{
50 closeFile(&flashFd);
Patrick Venture6f17bd22018-08-07 13:24:17 -070051 closeFile(&hashFd);
Patrick Venture8ec019f2018-08-07 11:22:33 -070052}
53
54FlashUpdate::~FlashUpdate()
55{
56 /* Close without deleting. This object can only be destroyed if the ipmi
57 * daemon unloads it, by closing down. In this event, we want the verified
58 * file to live on.
59 */
60 closeEverything();
61}
62
Patrick Venture54c3b532018-08-01 11:45:49 -070063void FlashUpdate::abortEverything()
64{
Patrick Venture8ec019f2018-08-07 11:22:33 -070065 closeEverything();
66
67 /* TODO: And now delete everything */
Patrick Venture54c3b532018-08-01 11:45:49 -070068 return;
69}
70
71bool FlashUpdate::openEverything()
72{
Patrick Venture3c086f22018-08-07 11:59:20 -070073 flashFd = std::fopen(tmpPath.c_str(), "wb");
Patrick Venture8ec019f2018-08-07 11:22:33 -070074 if (flashFd == nullptr)
75 {
76 log<level::INFO>("Unable to open staging path",
77 entry("PATH=%s", tmpPath.c_str()));
78 return false;
79 }
80
Patrick Venture6f17bd22018-08-07 13:24:17 -070081 /* hash path is basically optional. */
82 if (!hashPath.empty())
83 {
84 hashFd = std::fopen(hashPath.c_str(), "wb");
85 if (hashFd == nullptr)
86 {
87 log<level::INFO>("Unable to open hash storage path",
88 entry("PATH=%s", hashPath.c_str()));
89 closeFile(&flashFd);
90 return false;
91 }
92 }
93
Patrick Venture54c3b532018-08-01 11:45:49 -070094 return true;
95}
96
97/* Prepare to receive a BMC image and then a signature. */
Patrick Venture8ec019f2018-08-07 11:22:33 -070098bool FlashUpdate::start(uint32_t length)
Patrick Venture54c3b532018-08-01 11:45:49 -070099{
Patrick Venture54c3b532018-08-01 11:45:49 -0700100 /* Close out and delete everything. */
101 abortEverything();
102
Patrick Venture8ec019f2018-08-07 11:22:33 -0700103 /* TODO: Validate request->length */
104 flashLength = length;
105
Patrick Venture54c3b532018-08-01 11:45:49 -0700106 /* Start over! */
107 return openEverything();
108}
Patrick Venture79e131f2018-08-01 13:34:35 -0700109
Patrick Venture3c086f22018-08-07 11:59:20 -0700110bool FlashUpdate::writeBlock(std::FILE* fd, uint32_t offset,
111 const std::vector<uint8_t>& bytes)
112{
113 /* Seek into position, let's assume fseek won't call if offset matches
114 * position.
115 */
116 if (std::fseek(fd, offset, SEEK_SET))
117 {
118 log<level::ERR>("Unable to seek into file to write bytes.");
119 return false;
120 }
121
122 /* Write the bytes. */
123 auto written = std::fwrite(bytes.data(), 1, bytes.size(), fd);
124
125 if (written != bytes.size())
126 {
127 log<level::ERR>("Unable to write all the bytes requested.");
128 return false;
129 }
130
131 (void)std::fflush(fd);
132 return true;
133}
134
Patrick Venture79e131f2018-08-01 13:34:35 -0700135bool FlashUpdate::flashData(uint32_t offset, const std::vector<uint8_t>& bytes)
136{
Patrick Venture3c086f22018-08-07 11:59:20 -0700137 if (flashFd)
138 {
139 return writeBlock(flashFd, offset, bytes);
140 }
141
Patrick Venture79e131f2018-08-01 13:34:35 -0700142 return false;
143}
Patrick Venture2c1205d2018-08-03 10:23:14 -0700144
145bool FlashUpdate::flashFinish()
146{
Patrick Venture57703662018-08-07 12:52:24 -0700147 /* If it's open, close it. */
148 if (flashFd)
149 {
150 closeFile(&flashFd);
151 return true;
152 }
153
Patrick Venture2c1205d2018-08-03 10:23:14 -0700154 return false;
155}
Patrick Venture8d9f7322018-08-03 10:39:13 -0700156
157bool FlashUpdate::startHash(uint32_t length)
158{
Patrick Venture6f17bd22018-08-07 13:24:17 -0700159 if (!hashFd)
160 {
161 return false;
162 }
163
164 hashLength = length;
165 return true;
Patrick Venture8d9f7322018-08-03 10:39:13 -0700166}
Patrick Venturecfe66872018-08-03 13:32:33 -0700167
168bool FlashUpdate::hashData(uint32_t offset, const std::vector<uint8_t>& bytes)
169{
Patrick Venturecbe51492018-08-07 14:09:17 -0700170 if (hashFd)
171 {
172 return writeBlock(hashFd, offset, bytes);
173 }
174
Patrick Venturecfe66872018-08-03 13:32:33 -0700175 return false;
176}
Patrick Venturefbc7d192018-08-03 13:54:21 -0700177
178bool FlashUpdate::hashFinish()
179{
Patrick Ventured5f590f2018-08-07 14:18:09 -0700180 if (hashFd)
181 {
182 closeFile(&hashFd);
183 return true;
184 }
185
Patrick Venturefbc7d192018-08-03 13:54:21 -0700186 return false;
187}
Patrick Venture1cb87d22018-08-03 18:22:09 -0700188
189bool FlashUpdate::startDataVerification()
190{
191 /* TODO: implement. */
192 return false;
193}
Patrick Venture5c251ca2018-08-03 18:31:01 -0700194
195bool FlashUpdate::abortUpdate()
196{
197 /* TODO: implement. */
198 return false;
199}
Patrick Venturefdc65b22018-08-07 14:37:58 -0700200
201VerifyCheckResponse FlashUpdate::checkVerify()
202{
Patrick Venture7fc66de2018-08-07 14:53:02 -0700203 auto result = VerifyCheckResponse::other;
204 std::ifstream ifs;
205 ifs.open(verifyPath);
206 if (ifs.good())
207 {
208 std::string status;
209 /*
210 * Check for the contents of the file, excepting:
211 * running, success, or failed.
212 */
213 ifs >> status;
214 if (status == "running")
215 {
216 result = VerifyCheckResponse::running;
217 }
218 else if (status == "success")
219 {
220 result = VerifyCheckResponse::success;
221 }
222 else if (status == "failed")
223 {
224 result = VerifyCheckResponse::failed;
225 }
226 }
227
228 return result;
Patrick Venturefdc65b22018-08-07 14:37:58 -0700229}