xref: /openbmc/phosphor-ipmi-flash/tools/handler.cpp (revision 328f520f44a4e986d58b204468660e7ddeedc189)
1 /*
2  * Copyright 2018 Google Inc.
3  *
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 "handler.hpp"
18 
19 #include "flags.hpp"
20 #include "helper.hpp"
21 #include "status.hpp"
22 #include "tool_errors.hpp"
23 #include "util.hpp"
24 
25 #include <ipmiblob/blob_errors.hpp>
26 
27 #include <algorithm>
28 #include <cstdint>
29 #include <cstring>
30 #include <string>
31 #include <vector>
32 
33 namespace host_tool
34 {
35 
36 bool UpdateHandler::checkAvailable(const std::string& goalFirmware)
37 {
38     std::vector<std::string> blobs = blob->getBlobList();
39 
40     auto blobInst = std::find_if(
41         blobs.begin(), blobs.end(), [&goalFirmware](const std::string& iter) {
42             /* Running into weird scenarios where the string comparison doesn't
43              * work.  TODO: revisit.
44              */
45             return (0 == std::memcmp(goalFirmware.c_str(), iter.c_str(),
46                                      goalFirmware.length()));
47             // return (goalFirmware.compare(iter));
48         });
49     if (blobInst == blobs.end())
50     {
51         std::fprintf(stderr, "%s not found\n", goalFirmware.c_str());
52         return false;
53     }
54 
55     return true;
56 }
57 
58 void UpdateHandler::sendFile(const std::string& target, const std::string& path)
59 {
60     std::uint16_t session;
61     auto supported = handler->supportedType();
62 
63     try
64     {
65         session = blob->openBlob(
66             target, static_cast<std::uint16_t>(supported) |
67                         static_cast<std::uint16_t>(
68                             ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
69     }
70     catch (const ipmiblob::BlobException& b)
71     {
72         throw ToolException("blob exception received: " +
73                             std::string(b.what()));
74     }
75 
76     if (!handler->sendContents(path, session))
77     {
78         /* Need to close the session on failure, or it's stuck open (until the
79          * blob handler timeout is implemented, and even then, why make it wait.
80          */
81         blob->closeBlob(session);
82         throw ToolException("Failed to send contents of " + path);
83     }
84 
85     blob->closeBlob(session);
86 }
87 
88 bool UpdateHandler::verifyFile(const std::string& target, bool ignoreStatus)
89 {
90     std::uint16_t session;
91     bool success = false;
92 
93     try
94     {
95         session = blob->openBlob(
96             target, static_cast<std::uint16_t>(
97                         ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
98     }
99     catch (const ipmiblob::BlobException& b)
100     {
101         throw ToolException("blob exception received: " +
102                             std::string(b.what()));
103     }
104 
105     std::fprintf(stderr, "Committing to %s to trigger service\n",
106                  target.c_str());
107 
108     try
109     {
110         blob->commit(session, {});
111     }
112     catch (const ipmiblob::BlobException& b)
113     {
114         blob->closeBlob(session);
115         throw ToolException("blob exception received: " +
116                             std::string(b.what()));
117     }
118 
119     if (ignoreStatus)
120     {
121         // Skip checking the blob for status if ignoreStatus is enabled
122         blob->closeBlob(session);
123         return true;
124     }
125 
126     std::fprintf(stderr, "Calling stat on %s session to check status\n",
127                  target.c_str());
128 
129     if (pollStatus(session, blob))
130     {
131         std::fprintf(stderr, "Returned success\n");
132         success = true;
133     }
134     else
135     {
136         std::fprintf(stderr, "Returned non-success (could still "
137                              "be running (unlikely))\n");
138     }
139 
140     blob->closeBlob(session);
141     return (success == true);
142 }
143 
144 std::vector<uint8_t> UpdateHandler::readVersion(const std::string& versionBlob)
145 {
146     std::uint16_t session;
147 
148     try
149     {
150         session = blob->openBlob(
151             versionBlob, static_cast<std::uint16_t>(
152                              ipmi_flash::FirmwareFlags::UpdateFlags::openRead));
153     }
154     catch (const ipmiblob::BlobException& b)
155     {
156         throw ToolException("blob exception received: " +
157                             std::string(b.what()));
158     }
159 
160     std::fprintf(stderr, "Calling stat on %s session to check status\n",
161                  versionBlob.c_str());
162     std::vector<uint8_t> data;
163 
164     /* TODO: call readBytes multiple times in case IPMI message length exceeds
165      * IPMI_MAX_MSG_LENGTH.
166      */
167     auto pollResp = pollReadReady(session, blob);
168     if (pollResp.first)
169     {
170         std::fprintf(stderr, "Returned success\n");
171         if (pollResp.second > 0)
172         {
173             try
174             {
175                 data = blob->readBytes(session, 0, pollResp.second);
176             }
177             catch (const ipmiblob::BlobException& b)
178             {
179                 blob->closeBlob(session);
180                 throw ToolException("blob exception received: " +
181                                     std::string(b.what()));
182             }
183         }
184     }
185     else
186     {
187         std::fprintf(stderr, "Returned non-success (could still "
188                              "be running (unlikely))\n");
189     }
190 
191     blob->closeBlob(session);
192     return data;
193 }
194 
195 void UpdateHandler::cleanArtifacts()
196 {
197     /* open(), commit(), close() */
198     std::uint16_t session;
199 
200     /* Errors aren't important for this call. */
201     try
202     {
203         std::fprintf(stderr, "Opening the cleanup blob\n");
204         session = blob->openBlob(
205             ipmi_flash::cleanupBlobId,
206             static_cast<std::uint16_t>(
207                 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
208     }
209     catch (...)
210     {
211         return;
212     }
213 
214     try
215     {
216         std::fprintf(stderr, "Committing to the cleanup blob\n");
217         blob->commit(session, {});
218         std::fprintf(stderr, "Closing cleanup blob\n");
219     }
220     catch (...)
221     {}
222 
223     blob->closeBlob(session);
224 }
225 
226 } // namespace host_tool
227