1*3840547dSJayanth Othayoth #include "config.h"
2*3840547dSJayanth Othayoth 
313c57ad8SJayanth Othayoth #include "fw_update_watch.hpp"
413c57ad8SJayanth Othayoth 
5*3840547dSJayanth Othayoth #include "common_utils.hpp"
6*3840547dSJayanth Othayoth #include "create_pel.hpp"
7*3840547dSJayanth Othayoth #include "pdbg_utils.hpp"
813c57ad8SJayanth Othayoth 
9*3840547dSJayanth Othayoth #include <fmt/format.h>
10*3840547dSJayanth Othayoth #include <sys/stat.h>
11*3840547dSJayanth Othayoth #include <sys/wait.h>
12*3840547dSJayanth Othayoth #include <unistd.h>
13*3840547dSJayanth Othayoth 
14*3840547dSJayanth Othayoth #include <phosphor-logging/elog-errors.hpp>
1513c57ad8SJayanth Othayoth #include <phosphor-logging/elog.hpp>
1613c57ad8SJayanth Othayoth #include <sdbusplus/exception.hpp>
1713c57ad8SJayanth Othayoth 
18*3840547dSJayanth Othayoth #include <filesystem>
19*3840547dSJayanth 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;
27*3840547dSJayanth Othayoth namespace fs = std::filesystem;
28*3840547dSJayanth 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 
3613c57ad8SJayanth Othayoth void Watch::fwIntfAddedCallback(sdbusplus::message::message& 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     }
4613c57ad8SJayanth Othayoth     catch (const sdbusplus::exception::SdBusError& e)
4713c57ad8SJayanth Othayoth     {
4813c57ad8SJayanth Othayoth         log<level::ERR>(fmt::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 
89*3840547dSJayanth Othayoth         try
90*3840547dSJayanth Othayoth         {
9113c57ad8SJayanth Othayoth             // Colect device tree data
9213c57ad8SJayanth Othayoth             openpower::phal::fwupdate::exportDevtree();
9313c57ad8SJayanth Othayoth         }
94*3840547dSJayanth Othayoth         catch (fs::filesystem_error& e)
95*3840547dSJayanth Othayoth         {
96*3840547dSJayanth Othayoth             log<level::ERR>(
97*3840547dSJayanth Othayoth                 fmt::format("Filesystem error reported Error:({})", e.what())
98*3840547dSJayanth Othayoth                     .c_str());
99*3840547dSJayanth Othayoth             throw std::runtime_error(e.what());
100*3840547dSJayanth Othayoth         }
101*3840547dSJayanth Othayoth 
102*3840547dSJayanth Othayoth         log<level::INFO>("Successfully exported devtree attribute data");
103*3840547dSJayanth Othayoth     }
10413c57ad8SJayanth Othayoth 
10513c57ad8SJayanth Othayoth     return;
10613c57ad8SJayanth Othayoth }
10713c57ad8SJayanth Othayoth 
10813c57ad8SJayanth Othayoth void exportDevtree()
109*3840547dSJayanth Othayoth {
110*3840547dSJayanth Othayoth     constexpr auto ERROR_DEVTREE_BACKUP =
111*3840547dSJayanth Othayoth         "org.open_power.PHAL.Error.devtreeBackup";
112*3840547dSJayanth Othayoth 
113*3840547dSJayanth Othayoth     // Check devtree export filter file is present
114*3840547dSJayanth Othayoth     auto path = fs::path(DEVTREE_EXPORT_FILTER_FILE);
115*3840547dSJayanth Othayoth     if (!fs::exists(path))
116*3840547dSJayanth Othayoth     {
117*3840547dSJayanth Othayoth         log<level::ERR>(
118*3840547dSJayanth Othayoth             fmt::format("devtree export filter file is not available: ({})",
119*3840547dSJayanth Othayoth                         DEVTREE_EXPORT_FILTER_FILE)
120*3840547dSJayanth Othayoth                 .c_str());
121*3840547dSJayanth Othayoth         openpower::pel::createPEL(ERROR_DEVTREE_BACKUP);
122*3840547dSJayanth Othayoth         return;
123*3840547dSJayanth Othayoth     }
124*3840547dSJayanth Othayoth 
125*3840547dSJayanth Othayoth     // delete export data file if present
126*3840547dSJayanth Othayoth     auto expFile = fs::path(DEVTREE_EXP_FILE);
127*3840547dSJayanth Othayoth     if (fs::exists(expFile))
128*3840547dSJayanth Othayoth     {
129*3840547dSJayanth Othayoth         fs::remove_all(expFile);
130*3840547dSJayanth Othayoth     }
131*3840547dSJayanth Othayoth     else
132*3840547dSJayanth Othayoth     {
133*3840547dSJayanth Othayoth         // create directory
134*3840547dSJayanth Othayoth         fs::create_directory(expFile.parent_path());
135*3840547dSJayanth Othayoth     }
136*3840547dSJayanth Othayoth 
137*3840547dSJayanth Othayoth     // Update PDBG_DTB value
138*3840547dSJayanth Othayoth     openpower::phal::setDevtreeEnv();
139*3840547dSJayanth Othayoth 
140*3840547dSJayanth Othayoth     int status = 0;
141*3840547dSJayanth Othayoth     pid_t pid = fork();
142*3840547dSJayanth Othayoth     if (pid == 0)
143*3840547dSJayanth Othayoth     {
144*3840547dSJayanth Othayoth         std::string cmd("/usr/bin/attributes ");
145*3840547dSJayanth Othayoth         cmd += "export ";
146*3840547dSJayanth Othayoth         cmd += DEVTREE_EXPORT_FILTER_FILE;
147*3840547dSJayanth Othayoth         cmd += " > ";
148*3840547dSJayanth Othayoth         cmd += DEVTREE_EXP_FILE;
149*3840547dSJayanth Othayoth         execl("/bin/sh", "sh", "-c", cmd.c_str(), 0);
150*3840547dSJayanth Othayoth 
151*3840547dSJayanth Othayoth         auto error = errno;
152*3840547dSJayanth Othayoth         log<level::ERR>(fmt::format("Error occurred during attributes function "
153*3840547dSJayanth Othayoth                                     "execution, errno({})",
154*3840547dSJayanth Othayoth                                     error)
155*3840547dSJayanth Othayoth                             .c_str());
156*3840547dSJayanth Othayoth         // Creating PEL at one place.
157*3840547dSJayanth Othayoth     }
158*3840547dSJayanth Othayoth     else if (pid > 0)
159*3840547dSJayanth Othayoth     {
160*3840547dSJayanth Othayoth         waitpid(pid, &status, 0);
161*3840547dSJayanth Othayoth         if (WEXITSTATUS(status))
162*3840547dSJayanth Othayoth         {
163*3840547dSJayanth Othayoth             log<level::ERR>("Failed to collect attribute export data");
164*3840547dSJayanth Othayoth             openpower::pel::createPEL(ERROR_DEVTREE_BACKUP);
165*3840547dSJayanth Othayoth         }
166*3840547dSJayanth Othayoth     }
167*3840547dSJayanth Othayoth     else
168*3840547dSJayanth Othayoth     {
169*3840547dSJayanth Othayoth         log<level::ERR>("exportDevtree fork() failed");
170*3840547dSJayanth Othayoth         std::runtime_error("exportDevtree fork() failed");
171*3840547dSJayanth Othayoth     }
172*3840547dSJayanth Othayoth }
17313c57ad8SJayanth Othayoth 
17413c57ad8SJayanth Othayoth } // namespace fwupdate
17513c57ad8SJayanth Othayoth } // namespace phal
17613c57ad8SJayanth Othayoth } // namespace openpower
177