13840547dSJayanth Othayoth #include "config.h"
23840547dSJayanth Othayoth 
313c57ad8SJayanth Othayoth #include "fw_update_watch.hpp"
413c57ad8SJayanth Othayoth 
53840547dSJayanth Othayoth #include "common_utils.hpp"
63840547dSJayanth Othayoth #include "create_pel.hpp"
73840547dSJayanth Othayoth #include "pdbg_utils.hpp"
813c57ad8SJayanth Othayoth 
93840547dSJayanth Othayoth #include <sys/stat.h>
103840547dSJayanth Othayoth #include <sys/wait.h>
113840547dSJayanth Othayoth #include <unistd.h>
123840547dSJayanth Othayoth 
133840547dSJayanth Othayoth #include <phosphor-logging/elog-errors.hpp>
1413c57ad8SJayanth Othayoth #include <phosphor-logging/elog.hpp>
1513c57ad8SJayanth Othayoth #include <sdbusplus/exception.hpp>
1613c57ad8SJayanth Othayoth 
173840547dSJayanth Othayoth #include <filesystem>
18*e0dd7af4SJayanth Othayoth #include <format>
193840547dSJayanth Othayoth 
2013c57ad8SJayanth Othayoth namespace openpower
2113c57ad8SJayanth Othayoth {
2213c57ad8SJayanth Othayoth namespace phal
2313c57ad8SJayanth Othayoth {
2413c57ad8SJayanth Othayoth namespace fwupdate
2513c57ad8SJayanth Othayoth {
2613c57ad8SJayanth Othayoth using namespace phosphor::logging;
273840547dSJayanth Othayoth namespace fs = std::filesystem;
283840547dSJayanth Othayoth 
2913c57ad8SJayanth Othayoth using Message = std::string;
3013c57ad8SJayanth Othayoth using Attributes = std::variant<Message>;
3113c57ad8SJayanth Othayoth using PropertyName = std::string;
3213c57ad8SJayanth Othayoth using PropertyMap = std::map<PropertyName, Attributes>;
3313c57ad8SJayanth Othayoth using InterfaceName = std::string;
3413c57ad8SJayanth Othayoth using InterfaceMap = std::map<InterfaceName, PropertyMap>;
3513c57ad8SJayanth Othayoth 
fwIntfAddedCallback(sdbusplus::message_t & msg)36aaea6867SPatrick Williams void Watch::fwIntfAddedCallback(sdbusplus::message_t& msg)
3713c57ad8SJayanth Othayoth {
3813c57ad8SJayanth Othayoth     //  DBusInterfaceAdded interfaces;
3913c57ad8SJayanth Othayoth     sdbusplus::message::object_path objectPath;
4013c57ad8SJayanth Othayoth     InterfaceMap interfaceMap;
4113c57ad8SJayanth Othayoth 
4213c57ad8SJayanth Othayoth     try
4313c57ad8SJayanth Othayoth     {
4413c57ad8SJayanth Othayoth         msg.read(objectPath, interfaceMap);
4513c57ad8SJayanth Othayoth     }
46aaea6867SPatrick Williams     catch (const sdbusplus::exception_t& e)
4713c57ad8SJayanth Othayoth     {
48*e0dd7af4SJayanth Othayoth         log<level::ERR>(std::format("Failed to parse software add signal"
4913c57ad8SJayanth Othayoth                                     "Exception [{}] REPLY_SIG [{}]",
5013c57ad8SJayanth Othayoth                                     e.what(), msg.get_signature())
5113c57ad8SJayanth Othayoth                             .c_str());
5213c57ad8SJayanth Othayoth         return;
5313c57ad8SJayanth Othayoth     }
5413c57ad8SJayanth Othayoth 
5513c57ad8SJayanth Othayoth     auto iter = interfaceMap.find("xyz.openbmc_project.Software.Activation");
5613c57ad8SJayanth Othayoth     if (iter == interfaceMap.end())
5713c57ad8SJayanth Othayoth     {
5813c57ad8SJayanth Othayoth         // Skip not related Software Activation
5913c57ad8SJayanth Othayoth         return;
6013c57ad8SJayanth Othayoth     }
6113c57ad8SJayanth Othayoth 
6213c57ad8SJayanth Othayoth     auto attr = iter->second.find("Activation");
6313c57ad8SJayanth Othayoth     if (attr == iter->second.end())
6413c57ad8SJayanth Othayoth     {
6513c57ad8SJayanth Othayoth         // Skip not related to Activation property.
6613c57ad8SJayanth Othayoth         return;
6713c57ad8SJayanth Othayoth     }
6813c57ad8SJayanth Othayoth 
6913c57ad8SJayanth Othayoth     auto& imageProperty = std::get<InterfaceName>(attr->second);
7013c57ad8SJayanth Othayoth     if (imageProperty.empty())
7113c57ad8SJayanth Othayoth     {
7213c57ad8SJayanth Othayoth         // Skip, no image property
7313c57ad8SJayanth Othayoth         return;
7413c57ad8SJayanth Othayoth     }
7513c57ad8SJayanth Othayoth 
7613c57ad8SJayanth Othayoth     if (imageProperty ==
7713c57ad8SJayanth Othayoth             "xyz.openbmc_project.Software.Activation.Activations.Ready" &&
7813c57ad8SJayanth Othayoth         !isSoftwareUpdateInProgress())
7913c57ad8SJayanth Othayoth     {
8013c57ad8SJayanth Othayoth         log<level::INFO>("Software path interface add signal received");
8113c57ad8SJayanth Othayoth 
8213c57ad8SJayanth Othayoth         // Set status to code update in progress.
8313c57ad8SJayanth Othayoth         // Interface added signal triggered multiple times in code update path,
8413c57ad8SJayanth Othayoth         // it's due to additional interfaces added by the software manager app
8513c57ad8SJayanth Othayoth         // after the version interface is created.
8613c57ad8SJayanth Othayoth         // Device tree data collection is required only for the first trigger
8713c57ad8SJayanth Othayoth         setSoftwareUpdateProgress(true);
8813c57ad8SJayanth Othayoth 
893840547dSJayanth Othayoth         try
903840547dSJayanth Othayoth         {
9113c57ad8SJayanth Othayoth             // Colect device tree data
9213c57ad8SJayanth Othayoth             openpower::phal::fwupdate::exportDevtree();
9313c57ad8SJayanth Othayoth         }
941a9a5a6aSPatrick Williams         catch (const fs::filesystem_error& e)
953840547dSJayanth Othayoth         {
963840547dSJayanth Othayoth             log<level::ERR>(
97*e0dd7af4SJayanth Othayoth                 std::format("Filesystem error reported Error:({})", e.what())
983840547dSJayanth Othayoth                     .c_str());
993840547dSJayanth Othayoth             throw std::runtime_error(e.what());
1003840547dSJayanth Othayoth         }
1013840547dSJayanth Othayoth 
1023840547dSJayanth Othayoth         log<level::INFO>("Successfully exported devtree attribute data");
1033840547dSJayanth Othayoth     }
10413c57ad8SJayanth Othayoth 
10513c57ad8SJayanth Othayoth     return;
10613c57ad8SJayanth Othayoth }
10713c57ad8SJayanth Othayoth 
exportDevtree()10813c57ad8SJayanth Othayoth void exportDevtree()
1093840547dSJayanth Othayoth {
1103840547dSJayanth Othayoth     constexpr auto ERROR_DEVTREE_BACKUP =
1113840547dSJayanth Othayoth         "org.open_power.PHAL.Error.devtreeBackup";
1123840547dSJayanth Othayoth 
1133840547dSJayanth Othayoth     // Check devtree export filter file is present
1143840547dSJayanth Othayoth     auto path = fs::path(DEVTREE_EXPORT_FILTER_FILE);
1153840547dSJayanth Othayoth     if (!fs::exists(path))
1163840547dSJayanth Othayoth     {
1173840547dSJayanth Othayoth         log<level::ERR>(
118*e0dd7af4SJayanth Othayoth             std::format("devtree export filter file is not available: ({})",
1193840547dSJayanth Othayoth                         DEVTREE_EXPORT_FILTER_FILE)
1203840547dSJayanth Othayoth                 .c_str());
1213840547dSJayanth Othayoth         openpower::pel::createPEL(ERROR_DEVTREE_BACKUP);
1223840547dSJayanth Othayoth         return;
1233840547dSJayanth Othayoth     }
1243840547dSJayanth Othayoth 
1253840547dSJayanth Othayoth     // delete export data file if present
1263840547dSJayanth Othayoth     auto expFile = fs::path(DEVTREE_EXP_FILE);
1273840547dSJayanth Othayoth     if (fs::exists(expFile))
1283840547dSJayanth Othayoth     {
1293840547dSJayanth Othayoth         fs::remove_all(expFile);
1303840547dSJayanth Othayoth     }
1313840547dSJayanth Othayoth     else
1323840547dSJayanth Othayoth     {
1333840547dSJayanth Othayoth         // create directory
1343840547dSJayanth Othayoth         fs::create_directory(expFile.parent_path());
1353840547dSJayanth Othayoth     }
1363840547dSJayanth Othayoth 
1373840547dSJayanth Othayoth     // Update PDBG_DTB value
1383840547dSJayanth Othayoth     openpower::phal::setDevtreeEnv();
1393840547dSJayanth Othayoth 
14041e122fdSJayanth Othayoth     // Update PDATA_INFODB value
14141e122fdSJayanth Othayoth     openpower::phal::setPdataInfoDBEnv();
14241e122fdSJayanth Othayoth 
1433840547dSJayanth Othayoth     int status = 0;
1443840547dSJayanth Othayoth     pid_t pid = fork();
1453840547dSJayanth Othayoth     if (pid == 0)
1463840547dSJayanth Othayoth     {
1473840547dSJayanth Othayoth         std::string cmd("/usr/bin/attributes ");
1483840547dSJayanth Othayoth         cmd += "export ";
1493840547dSJayanth Othayoth         cmd += DEVTREE_EXPORT_FILTER_FILE;
1503840547dSJayanth Othayoth         cmd += " > ";
1513840547dSJayanth Othayoth         cmd += DEVTREE_EXP_FILE;
1523840547dSJayanth Othayoth         execl("/bin/sh", "sh", "-c", cmd.c_str(), 0);
1533840547dSJayanth Othayoth 
1543840547dSJayanth Othayoth         auto error = errno;
155*e0dd7af4SJayanth Othayoth         log<level::ERR>(std::format("Error occurred during attributes function "
1563840547dSJayanth Othayoth                                     "execution, errno({})",
1573840547dSJayanth Othayoth                                     error)
1583840547dSJayanth Othayoth                             .c_str());
1593840547dSJayanth Othayoth         // Creating PEL at one place.
1603840547dSJayanth Othayoth     }
1613840547dSJayanth Othayoth     else if (pid > 0)
1623840547dSJayanth Othayoth     {
1633840547dSJayanth Othayoth         waitpid(pid, &status, 0);
1643840547dSJayanth Othayoth         if (WEXITSTATUS(status))
1653840547dSJayanth Othayoth         {
1663840547dSJayanth Othayoth             log<level::ERR>("Failed to collect attribute export data");
1673840547dSJayanth Othayoth             openpower::pel::createPEL(ERROR_DEVTREE_BACKUP);
1683840547dSJayanth Othayoth         }
1693840547dSJayanth Othayoth     }
1703840547dSJayanth Othayoth     else
1713840547dSJayanth Othayoth     {
1723840547dSJayanth Othayoth         log<level::ERR>("exportDevtree fork() failed");
1733840547dSJayanth Othayoth         std::runtime_error("exportDevtree fork() failed");
1743840547dSJayanth Othayoth     }
1753840547dSJayanth Othayoth }
17613c57ad8SJayanth Othayoth 
17713c57ad8SJayanth Othayoth } // namespace fwupdate
17813c57ad8SJayanth Othayoth } // namespace phal
17913c57ad8SJayanth Othayoth } // namespace openpower
180