blob: e4ab130e315ed1b15c157a52ce91acf8873dbf1f [file] [log] [blame]
Sampa Misraaea5dde2020-08-31 08:33:47 -05001#include "inband_code_update.hpp"
2
Sagar Srinivas78a225a2020-08-27 00:52:20 -05003#include "libpldmresponder/pdr.hpp"
Sampa Misraaea5dde2020-08-31 08:33:47 -05004#include "oem_ibm_handler.hpp"
5#include "xyz/openbmc_project/Common/error.hpp"
6
Adriana Kobylak727f7382020-09-01 14:38:25 -05007#include <arpa/inet.h>
George Liuc453e162022-12-21 17:16:23 +08008#include <libpldm/entity.h>
Adriana Kobylak727f7382020-09-01 14:38:25 -05009
Riya Dixit49cfb132023-03-02 04:26:53 -060010#include <phosphor-logging/lg2.hpp>
Sampa Misraaea5dde2020-08-31 08:33:47 -050011#include <sdbusplus/server.hpp>
12#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
13
14#include <exception>
Adriana Kobylak727f7382020-09-01 14:38:25 -050015#include <fstream>
Riya Dixit49cfb132023-03-02 04:26:53 -060016
17PHOSPHOR_LOG2_USING;
18
Sampa Misraaea5dde2020-08-31 08:33:47 -050019namespace pldm
20{
Brad Bishop5079ac42021-08-19 18:35:06 -040021using namespace utils;
22
Sampa Misraaea5dde2020-08-31 08:33:47 -050023namespace responder
24{
25using namespace oem_ibm_platform;
26
Adriana Kobylakfa810d72020-10-16 16:27:28 -050027/** @brief Directory where the lid files without a header are stored */
28auto lidDirPath = fs::path(LID_STAGING_DIR) / "lid";
29
Adriana Kobylaka1f158c2020-11-09 12:47:29 -060030/** @brief Directory where the image files are stored as they are built */
31auto imageDirPath = fs::path(LID_STAGING_DIR) / "image";
32
Adriana Kobylak837fb472020-10-16 16:53:42 -050033/** @brief Directory where the code update tarball files are stored */
34auto updateDirPath = fs::path(LID_STAGING_DIR) / "update";
35
Adriana Kobylaka1f158c2020-11-09 12:47:29 -060036/** @brief The file name of the code update tarball */
37constexpr auto tarImageName = "image.tar";
38
Adriana Kobylak837fb472020-10-16 16:53:42 -050039/** @brief The file name of the hostfw image */
Adriana Kobylak131327e2021-03-10 18:45:24 +000040constexpr auto hostfwImageName = "image-hostfw";
Adriana Kobylak837fb472020-10-16 16:53:42 -050041
Adriana Kobylaka1f158c2020-11-09 12:47:29 -060042/** @brief The path to the code update tarball file */
43auto tarImagePath = fs::path(imageDirPath) / tarImageName;
44
Adriana Kobylak837fb472020-10-16 16:53:42 -050045/** @brief The path to the hostfw image */
46auto hostfwImagePath = fs::path(imageDirPath) / hostfwImageName;
47
48/** @brief The path to the tarball file expected by the phosphor software
49 * manager */
50auto updateImagePath = fs::path("/tmp/images") / tarImageName;
51
Sampa Misraaea5dde2020-08-31 08:33:47 -050052std::string CodeUpdate::fetchCurrentBootSide()
53{
54 return currBootSide;
55}
56
57std::string CodeUpdate::fetchNextBootSide()
58{
59 return nextBootSide;
60}
61
62int CodeUpdate::setCurrentBootSide(const std::string& currSide)
63{
64 currBootSide = currSide;
65 return PLDM_SUCCESS;
66}
67
68int CodeUpdate::setNextBootSide(const std::string& nextSide)
69{
70 nextBootSide = nextSide;
71 std::string objPath{};
72 if (nextBootSide == currBootSide)
73 {
74 objPath = runningVersion;
75 }
76 else
77 {
78 objPath = nonRunningVersion;
79 }
80 if (objPath.empty())
81 {
Riya Dixit49cfb132023-03-02 04:26:53 -060082 error("no nonRunningVersion present");
Sampa Misraaea5dde2020-08-31 08:33:47 -050083 return PLDM_PLATFORM_INVALID_STATE_VALUE;
84 }
85
86 pldm::utils::DBusMapping dbusMapping{objPath, redundancyIntf, "Priority",
87 "uint8_t"};
88 uint8_t val = 0;
89 pldm::utils::PropertyValue value = static_cast<uint8_t>(val);
90 try
91 {
92 dBusIntf->setDbusProperty(dbusMapping, value);
93 }
94 catch (const std::exception& e)
95 {
Riya Dixit49cfb132023-03-02 04:26:53 -060096 error(
97 "failed to set the next boot side to {OBJ_PATH} ERROR={ERR_EXCEP}",
98 "OBJ_PATH", objPath.c_str(), "ERR_EXCEP", e.what());
Sampa Misraaea5dde2020-08-31 08:33:47 -050099 return PLDM_ERROR;
100 }
101 return PLDM_SUCCESS;
102}
103
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500104int CodeUpdate::setRequestedApplyTime()
105{
106 int rc = PLDM_SUCCESS;
107 pldm::utils::PropertyValue value =
108 "xyz.openbmc_project.Software.ApplyTime.RequestedApplyTimes.OnReset";
109 DBusMapping dbusMapping;
110 dbusMapping.objectPath = "/xyz/openbmc_project/software/apply_time";
111 dbusMapping.interface = "xyz.openbmc_project.Software.ApplyTime";
112 dbusMapping.propertyName = "RequestedApplyTime";
113 dbusMapping.propertyType = "string";
114 try
115 {
116 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
117 }
118 catch (const std::exception& e)
119 {
Sagar Srinivas90403472023-08-21 06:08:55 -0500120 error(
121 "Failed To set RequestedApplyTime property, OBJ_PATH={OBJ_PATH}, INTERFACE={INTERFACE}, PROP_NAME={PROP_NAME}, ERROR={ERR_EXCEP}",
122 "OBJ_PATH", dbusMapping.objectPath, "INTERFACE",
123 dbusMapping.interface, "PROP_NAME", dbusMapping.propertyName,
124 "ERR_EXCEP", e.what());
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500125 rc = PLDM_ERROR;
126 }
127 return rc;
128}
129
130int CodeUpdate::setRequestedActivation()
131{
132 int rc = PLDM_SUCCESS;
133 pldm::utils::PropertyValue value =
134 "xyz.openbmc_project.Software.Activation.RequestedActivations.Active";
135 DBusMapping dbusMapping;
136 dbusMapping.objectPath = newImageId;
137 dbusMapping.interface = "xyz.openbmc_project.Software.Activation";
138 dbusMapping.propertyName = "RequestedActivation";
139 dbusMapping.propertyType = "string";
140 try
141 {
142 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
143 }
144 catch (const std::exception& e)
145 {
Sagar Srinivas90403472023-08-21 06:08:55 -0500146 error(
147 "Failed To set RequestedActivation property, OBJ_PATH={OBJ_PATH}, INTERFACE={INTERFACE}, PROP_NAME={PROP_NAME}, ERROR={ERR_EXCEP}",
148 "OBJ_PATH", dbusMapping.objectPath, "INTERFACE",
149 dbusMapping.interface, "PROP_NAME", dbusMapping.propertyName,
150 "ERR_EXCEP", e.what());
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500151 rc = PLDM_ERROR;
152 }
Sagar Srinivascfdbca72020-09-22 10:03:35 -0500153 return rc;
154}
155
Sampa Misraaea5dde2020-08-31 08:33:47 -0500156void CodeUpdate::setVersions()
157{
158 static constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
159 static constexpr auto functionalObjPath =
160 "/xyz/openbmc_project/software/functional";
161 static constexpr auto activeObjPath =
162 "/xyz/openbmc_project/software/active";
163 static constexpr auto propIntf = "org.freedesktop.DBus.Properties";
164
165 auto& bus = dBusIntf->getBus();
Sampa Misraaea5dde2020-08-31 08:33:47 -0500166 try
167 {
168 auto method = bus.new_method_call(mapperService, functionalObjPath,
169 propIntf, "Get");
170 method.append("xyz.openbmc_project.Association", "endpoints");
171 std::variant<std::vector<std::string>> paths;
172
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500173 auto reply = bus.call(method, dbusTimeout);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500174 reply.read(paths);
175
176 runningVersion = std::get<std::vector<std::string>>(paths)[0];
177
Patrick Williams6da4f912023-05-10 07:50:53 -0500178 auto method1 = bus.new_method_call(mapperService, activeObjPath,
179 propIntf, "Get");
Sampa Misraaea5dde2020-08-31 08:33:47 -0500180 method1.append("xyz.openbmc_project.Association", "endpoints");
181
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500182 auto reply1 = bus.call(method1, dbusTimeout);
Sampa Misraaea5dde2020-08-31 08:33:47 -0500183 reply1.read(paths);
184 for (const auto& path : std::get<std::vector<std::string>>(paths))
185 {
186 if (path != runningVersion)
187 {
188 nonRunningVersion = path;
189 break;
190 }
191 }
192 }
193 catch (const std::exception& e)
194 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600195 error(
196 "failed to make a d-bus call to Object Mapper Association, ERROR={ERR_EXCEP}",
197 "ERR_EXCEP", e.what());
Sampa Misraaea5dde2020-08-31 08:33:47 -0500198 return;
199 }
200
201 using namespace sdbusplus::bus::match::rules;
202 captureNextBootSideChange.push_back(
Patrick Williams84b790c2022-07-22 19:26:56 -0500203 std::make_unique<sdbusplus::bus::match_t>(
Sampa Misraaea5dde2020-08-31 08:33:47 -0500204 pldm::utils::DBusHandler::getBus(),
205 propertiesChanged(runningVersion, redundancyIntf),
Patrick Williams84b790c2022-07-22 19:26:56 -0500206 [this](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500207 DbusChangedProps props;
208 std::string iface;
209 msg.read(iface, props);
210 processPriorityChangeNotification(props);
Patrick Williamsa6756622023-10-20 11:19:15 -0500211 }));
Patrick Williams84b790c2022-07-22 19:26:56 -0500212 fwUpdateMatcher.push_back(std::make_unique<sdbusplus::bus::match_t>(
Sampa Misraaea5dde2020-08-31 08:33:47 -0500213 pldm::utils::DBusHandler::getBus(),
214 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
215 "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
Patrick Williams84b790c2022-07-22 19:26:56 -0500216 [this](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500217 DBusInterfaceAdded interfaces;
218 sdbusplus::message::object_path path;
219 msg.read(path, interfaces);
Sagar Srinivas9a64b4a2021-02-09 07:55:38 -0600220
Patrick Williams6da4f912023-05-10 07:50:53 -0500221 for (auto& interface : interfaces)
222 {
223 if (interface.first == "xyz.openbmc_project.Software.Activation")
Sampa Misraaea5dde2020-08-31 08:33:47 -0500224 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500225 auto imageInterface = "xyz.openbmc_project.Software.Activation";
226 auto imageObjPath = path.str.c_str();
Sagar Srinivas9a64b4a2021-02-09 07:55:38 -0600227
Patrick Williams6da4f912023-05-10 07:50:53 -0500228 try
229 {
230 auto propVal = dBusIntf->getDbusPropertyVariant(
231 imageObjPath, "Activation", imageInterface);
232 const auto& imageProp = std::get<std::string>(propVal);
233 if (imageProp == "xyz.openbmc_project.Software."
234 "Activation.Activations.Ready" &&
235 isCodeUpdateInProgress())
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500236 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500237 newImageId = path.str;
238 if (!imageActivationMatch)
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500239 {
Patrick Williams6da4f912023-05-10 07:50:53 -0500240 imageActivationMatch =
241 std::make_unique<sdbusplus::bus::match_t>(
Sagar Srinivas9a64b4a2021-02-09 07:55:38 -0600242 pldm::utils::DBusHandler::getBus(),
243 propertiesChanged(newImageId,
244 "xyz.openbmc_project."
245 "Software.Activation"),
Patrick Williams84b790c2022-07-22 19:26:56 -0500246 [this](sdbusplus::message_t& msg) {
Patrick Williams6da4f912023-05-10 07:50:53 -0500247 DbusChangedProps props;
248 std::string iface;
249 msg.read(iface, props);
250 const auto itr = props.find("Activation");
251 if (itr != props.end())
252 {
253 PropertyValue value = itr->second;
254 auto propVal = std::get<std::string>(value);
255 if (propVal ==
256 "xyz.openbmc_project.Software."
257 "Activation.Activations.Active")
258 {
259 CodeUpdateState state =
260 CodeUpdateState::END;
261 setCodeUpdateProgress(false);
262 auto sensorId =
263 getFirmwareUpdateSensor();
264 sendStateSensorEvent(
265 sensorId, PLDM_STATE_SENSOR_STATE,
266 0, uint8_t(state),
267 uint8_t(CodeUpdateState::START));
268 newImageId.clear();
269 }
270 else if (propVal == "xyz.openbmc_project."
271 "Software.Activation."
272 "Activations.Failed" ||
273 propVal == "xyz.openbmc_"
274 "project.Software."
275 "Activation."
276 "Activations."
277 "Invalid")
278 {
279 CodeUpdateState state =
280 CodeUpdateState::FAIL;
281 setCodeUpdateProgress(false);
282 auto sensorId =
283 getFirmwareUpdateSensor();
284 sendStateSensorEvent(
285 sensorId, PLDM_STATE_SENSOR_STATE,
286 0, uint8_t(state),
287 uint8_t(CodeUpdateState::START));
288 newImageId.clear();
289 }
290 }
Patrick Williamsa6756622023-10-20 11:19:15 -0500291 });
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500292 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500293 auto rc = setRequestedActivation();
294 if (rc != PLDM_SUCCESS)
295 {
296 CodeUpdateState state = CodeUpdateState::FAIL;
297 setCodeUpdateProgress(false);
298 auto sensorId = getFirmwareUpdateSensor();
299 sendStateSensorEvent(
300 sensorId, PLDM_STATE_SENSOR_STATE, 0,
301 uint8_t(state),
302 uint8_t(CodeUpdateState::START));
303 error("could not set RequestedActivation");
304 }
305 break;
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500306 }
Sampa Misraaea5dde2020-08-31 08:33:47 -0500307 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500308 catch (const sdbusplus::exception_t& e)
309 {
310 error(
311 "Error in getting Activation status,ERROR= {ERR_EXCEP}, INTERFACE={IMG_INTERFACE}, OBJECT PATH={OBJ_PATH}",
312 "ERR_EXCEP", e.what(), "IMG_INTERFACE", imageInterface,
313 "OBJ_PATH", imageObjPath);
314 }
Sampa Misraaea5dde2020-08-31 08:33:47 -0500315 }
Patrick Williams6da4f912023-05-10 07:50:53 -0500316 }
Patrick Williamsa6756622023-10-20 11:19:15 -0500317 }));
Sampa Misraaea5dde2020-08-31 08:33:47 -0500318}
319
320void CodeUpdate::processPriorityChangeNotification(
321 const DbusChangedProps& chProperties)
322{
323 static constexpr auto propName = "Priority";
324 const auto it = chProperties.find(propName);
325 if (it == chProperties.end())
326 {
327 return;
328 }
329 uint8_t newVal = std::get<uint8_t>(it->second);
330 nextBootSide = (newVal == 0) ? currBootSide
331 : ((currBootSide == Tside) ? Pside : Tside);
332}
333
334void CodeUpdate::setOemPlatformHandler(
335 pldm::responder::oem_platform::Handler* handler)
336{
337 oemPlatformHandler = handler;
338}
339
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500340void CodeUpdate::clearDirPath(const std::string& dirPath)
341{
Manojkiran Eda78124cf2022-08-29 11:22:43 +0530342 if (!fs::is_directory(dirPath))
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500343 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600344 error("The directory does not exist, dirPath = {DIR_PATH}", "DIR_PATH",
345 dirPath.c_str());
Manojkiran Eda78124cf2022-08-29 11:22:43 +0530346 return;
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500347 }
Manojkiran Eda78124cf2022-08-29 11:22:43 +0530348 for (const auto& iter : fs::directory_iterator(dirPath))
349 {
350 fs::remove_all(iter);
351 }
Varsha Kaverappa3ca29df2020-09-27 12:39:22 -0500352}
353
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500354void CodeUpdate::sendStateSensorEvent(
355 uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
356 uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
357{
358 pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler =
359 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
360 oemPlatformHandler);
361 oemIbmPlatformHandler->sendStateSensorEvent(
362 sensorId, sensorEventClass, sensorOffset, eventState, prevEventState);
363}
364
365void CodeUpdate::deleteImage()
366{
367 static constexpr auto UPDATER_SERVICE =
368 "xyz.openbmc_project.Software.BMC.Updater";
369 static constexpr auto SW_OBJ_PATH = "/xyz/openbmc_project/software";
370 static constexpr auto DELETE_INTF =
371 "xyz.openbmc_project.Collection.DeleteAll";
372
373 auto& bus = dBusIntf->getBus();
374 try
375 {
376 auto method = bus.new_method_call(UPDATER_SERVICE, SW_OBJ_PATH,
377 DELETE_INTF, "DeleteAll");
vkaverap@in.ibm.com5b71b862023-08-21 05:19:04 +0000378 bus.call_noreply(method, dbusTimeout);
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500379 }
380 catch (const std::exception& e)
381 {
Sagar Srinivas90403472023-08-21 06:08:55 -0500382 error(
383 "Failed to delete image, OBJ_PATH={OBJ_PATH}, INTERFACE={INTERFACE}, ERROR={ERR_EXCEP}",
384 "OBJ_PATH", SW_OBJ_PATH, "INTERFACE", DELETE_INTF, "ERR_EXCEP",
385 e.what());
Sampa Misra3a0e3b92020-10-21 05:58:00 -0500386 return;
387 }
388}
389
Sampa Misraaea5dde2020-08-31 08:33:47 -0500390uint8_t fetchBootSide(uint16_t entityInstance, CodeUpdate* codeUpdate)
391{
392 uint8_t sensorOpState = tSideNum;
Sampa Misraaea5dde2020-08-31 08:33:47 -0500393 if (entityInstance == 0)
394 {
395 auto currSide = codeUpdate->fetchCurrentBootSide();
396 if (currSide == Pside)
397 {
398 sensorOpState = pSideNum;
399 }
400 }
401 else if (entityInstance == 1)
402 {
403 auto nextSide = codeUpdate->fetchNextBootSide();
404 if (nextSide == Pside)
405 {
406 sensorOpState = pSideNum;
407 }
408 }
409 else
410 {
411 sensorOpState = PLDM_SENSOR_UNKNOWN;
412 }
413
414 return sensorOpState;
415}
416
417int setBootSide(uint16_t entityInstance, uint8_t currState,
418 const std::vector<set_effecter_state_field>& stateField,
419 CodeUpdate* codeUpdate)
420{
421 int rc = PLDM_SUCCESS;
422 auto side = (stateField[currState].effecter_state == pSideNum) ? "P" : "T";
423
424 if (entityInstance == 0)
425 {
426 rc = codeUpdate->setCurrentBootSide(side);
427 }
428 else if (entityInstance == 1)
429 {
430 rc = codeUpdate->setNextBootSide(side);
431 }
432 else
433 {
434 rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
435 }
436 return rc;
437}
438
Adriana Kobylak837fb472020-10-16 16:53:42 -0500439template <typename... T>
Patrick Williams6da4f912023-05-10 07:50:53 -0500440int executeCmd(const T&... t)
Adriana Kobylak837fb472020-10-16 16:53:42 -0500441{
442 std::stringstream cmd;
443 ((cmd << t << " "), ...) << std::endl;
444 FILE* pipe = popen(cmd.str().c_str(), "r");
445 if (!pipe)
446 {
447 throw std::runtime_error("popen() failed!");
448 }
449 int rc = pclose(pipe);
450 if (WEXITSTATUS(rc))
451 {
452 std::cerr << "Error executing: ";
453 ((std::cerr << " " << t), ...);
454 std::cerr << "\n";
455 return -1;
456 }
457
458 return 0;
459}
460
Adriana Kobylak727f7382020-09-01 14:38:25 -0500461int processCodeUpdateLid(const std::string& filePath)
462{
463 struct LidHeader
464 {
465 uint16_t magicNumber;
Adriana Kobylak86d14182020-10-16 16:11:08 -0500466 uint16_t headerVersion;
467 uint32_t lidNumber;
468 uint32_t lidDate;
469 uint16_t lidTime;
470 uint16_t lidClass;
471 uint32_t lidCrc;
472 uint32_t lidSize;
473 uint32_t headerSize;
Adriana Kobylak727f7382020-09-01 14:38:25 -0500474 };
475 LidHeader header;
476
477 std::ifstream ifs(filePath, std::ios::in | std::ios::binary);
478 if (!ifs)
479 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600480 error("ifstream open error: {DIR_PATH}", "DIR_PATH", filePath.c_str());
Adriana Kobylak727f7382020-09-01 14:38:25 -0500481 return PLDM_ERROR;
482 }
483 ifs.seekg(0);
484 ifs.read(reinterpret_cast<char*>(&header), sizeof(header));
Adriana Kobylak727f7382020-09-01 14:38:25 -0500485
Adriana Kobylak86d14182020-10-16 16:11:08 -0500486 // File size should be the value of lid size minus the header size
487 auto fileSize = fs::file_size(filePath);
488 fileSize -= htonl(header.headerSize);
489 if (fileSize < htonl(header.lidSize))
490 {
491 // File is not completely written yet
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500492 ifs.close();
Adriana Kobylak86d14182020-10-16 16:11:08 -0500493 return PLDM_SUCCESS;
494 }
495
Adriana Kobylak727f7382020-09-01 14:38:25 -0500496 constexpr auto magicNumber = 0x0222;
497 if (htons(header.magicNumber) != magicNumber)
498 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600499 error("Invalid magic number: {DIR_PATH}", "DIR_PATH", filePath.c_str());
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500500 ifs.close();
Adriana Kobylak727f7382020-09-01 14:38:25 -0500501 return PLDM_ERROR;
502 }
503
Adriana Kobylaka1f158c2020-11-09 12:47:29 -0600504 fs::create_directories(imageDirPath);
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500505 fs::create_directories(lidDirPath);
506
Adriana Kobylaka1f158c2020-11-09 12:47:29 -0600507 constexpr auto bmcClass = 0x2000;
508 if (htons(header.lidClass) == bmcClass)
509 {
510 // Skip the header and concatenate the BMC LIDs into a tar file
511 std::ofstream ofs(tarImagePath,
512 std::ios::out | std::ios::binary | std::ios::app);
513 ifs.seekg(htonl(header.headerSize));
514 ofs << ifs.rdbuf();
515 ofs.flush();
516 ofs.close();
517 }
518 else
519 {
520 std::stringstream lidFileName;
521 lidFileName << std::hex << htonl(header.lidNumber) << ".lid";
522 auto lidNoHeaderPath = fs::path(lidDirPath) / lidFileName.str();
523 std::ofstream ofs(lidNoHeaderPath,
524 std::ios::out | std::ios::binary | std::ios::trunc);
525 ifs.seekg(htonl(header.headerSize));
526 ofs << ifs.rdbuf();
527 ofs.flush();
528 ofs.close();
529 }
Adriana Kobylakfa810d72020-10-16 16:27:28 -0500530
531 ifs.close();
532 fs::remove(filePath);
Adriana Kobylak727f7382020-09-01 14:38:25 -0500533 return PLDM_SUCCESS;
534}
535
Adriana Kobylak9296f242021-09-22 15:52:00 +0000536int CodeUpdate::assembleCodeUpdateImage()
Adriana Kobylak837fb472020-10-16 16:53:42 -0500537{
Adriana Kobylak9296f242021-09-22 15:52:00 +0000538 pid_t pid = fork();
539
540 if (pid == 0)
Adriana Kobylak837fb472020-10-16 16:53:42 -0500541 {
Adriana Kobylak9296f242021-09-22 15:52:00 +0000542 pid_t nextPid = fork();
543 if (nextPid == 0)
544 {
545 // Create the hostfw squashfs image from the LID files without
546 // header
547 auto rc = executeCmd("/usr/sbin/mksquashfs", lidDirPath.c_str(),
548 hostfwImagePath.c_str(), "-all-root",
549 "-no-recovery");
550 if (rc < 0)
551 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600552 error("Error occurred during the mksqusquashfs call");
Adriana Kobylak9296f242021-09-22 15:52:00 +0000553 setCodeUpdateProgress(false);
554 auto sensorId = getFirmwareUpdateSensor();
555 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
556 uint8_t(CodeUpdateState::FAIL),
557 uint8_t(CodeUpdateState::START));
558 exit(EXIT_FAILURE);
559 }
560
561 fs::create_directories(updateDirPath);
562
563 // Extract the BMC tarball content
564 rc = executeCmd("/bin/tar", "-xf", tarImagePath.c_str(), "-C",
565 updateDirPath);
566 if (rc < 0)
567 {
568 setCodeUpdateProgress(false);
569 auto sensorId = getFirmwareUpdateSensor();
570 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
571 uint8_t(CodeUpdateState::FAIL),
572 uint8_t(CodeUpdateState::START));
573 exit(EXIT_FAILURE);
574 }
575
576 // Add the hostfw image to the directory where the contents were
577 // extracted
578 fs::copy_file(hostfwImagePath,
579 fs::path(updateDirPath) / hostfwImageName,
580 fs::copy_options::overwrite_existing);
581
582 // Remove the tarball file, then re-generate it with so that the
583 // hostfw image becomes part of the tarball
584 fs::remove(tarImagePath);
585 rc = executeCmd("/bin/tar", "-cf", tarImagePath, ".", "-C",
586 updateDirPath);
587 if (rc < 0)
588 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600589 error("Error occurred during the generation of the tarball");
Adriana Kobylak9296f242021-09-22 15:52:00 +0000590 setCodeUpdateProgress(false);
591 auto sensorId = getFirmwareUpdateSensor();
592 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
593 uint8_t(CodeUpdateState::FAIL),
594 uint8_t(CodeUpdateState::START));
595 exit(EXIT_FAILURE);
596 }
597
598 // Copy the tarball to the update directory to trigger the phosphor
599 // software manager to create a version interface
600 fs::copy_file(tarImagePath, updateImagePath,
601 fs::copy_options::overwrite_existing);
602
603 // Cleanup
604 fs::remove_all(updateDirPath);
605 fs::remove_all(lidDirPath);
606 fs::remove_all(imageDirPath);
607
608 exit(EXIT_SUCCESS);
609 }
610 else if (nextPid < 0)
611 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600612 error("Error occurred during fork. ERROR={ERR}", "ERR", errno);
Adriana Kobylak9296f242021-09-22 15:52:00 +0000613 exit(EXIT_FAILURE);
614 }
615
616 // Do nothing as parent. When parent exits, child will be reparented
617 // under init and be reaped properly.
618 exit(0);
619 }
620 else if (pid > 0)
621 {
622 int status;
623 if (waitpid(pid, &status, 0) < 0)
624 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600625 error("Error occurred during waitpid. ERROR={ERR}", "ERR", errno);
626
Adriana Kobylak9296f242021-09-22 15:52:00 +0000627 return PLDM_ERROR;
628 }
629 else if (WEXITSTATUS(status) != 0)
630 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600631 error(
632 "Failed to execute the assembling of the image. STATUS={IMG_STATUS}",
633 "IMG_STATUS", status);
Adriana Kobylak9296f242021-09-22 15:52:00 +0000634 return PLDM_ERROR;
635 }
636 }
637 else
638 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600639 error("Error occurred during fork. ERROR={ERR}", "ERR", errno);
Adriana Kobylak837fb472020-10-16 16:53:42 -0500640 return PLDM_ERROR;
641 }
642
Adriana Kobylak837fb472020-10-16 16:53:42 -0500643 return PLDM_SUCCESS;
644}
645
Sampa Misraaea5dde2020-08-31 08:33:47 -0500646} // namespace responder
647} // namespace pldm