1 #include "config.h"
2 
3 #include "fw_update_watch.hpp"
4 
5 #include "common_utils.hpp"
6 #include "create_pel.hpp"
7 #include "pdbg_utils.hpp"
8 
9 #include <sys/stat.h>
10 #include <sys/wait.h>
11 #include <unistd.h>
12 
13 #include <phosphor-logging/elog-errors.hpp>
14 #include <phosphor-logging/elog.hpp>
15 #include <sdbusplus/exception.hpp>
16 
17 #include <filesystem>
18 #include <format>
19 
20 namespace openpower
21 {
22 namespace phal
23 {
24 namespace fwupdate
25 {
26 using namespace phosphor::logging;
27 namespace fs = std::filesystem;
28 
29 using Message = std::string;
30 using Attributes = std::variant<Message>;
31 using PropertyName = std::string;
32 using PropertyMap = std::map<PropertyName, Attributes>;
33 using InterfaceName = std::string;
34 using InterfaceMap = std::map<InterfaceName, PropertyMap>;
35 
36 void Watch::fwIntfAddedCallback(sdbusplus::message_t& msg)
37 {
38     //  DBusInterfaceAdded interfaces;
39     sdbusplus::message::object_path objectPath;
40     InterfaceMap interfaceMap;
41 
42     try
43     {
44         msg.read(objectPath, interfaceMap);
45     }
46     catch (const sdbusplus::exception_t& e)
47     {
48         log<level::ERR>(std::format("Failed to parse software add signal"
49                                     "Exception [{}] REPLY_SIG [{}]",
50                                     e.what(), msg.get_signature())
51                             .c_str());
52         return;
53     }
54 
55     auto iter = interfaceMap.find("xyz.openbmc_project.Software.Activation");
56     if (iter == interfaceMap.end())
57     {
58         // Skip not related Software Activation
59         return;
60     }
61 
62     auto attr = iter->second.find("Activation");
63     if (attr == iter->second.end())
64     {
65         // Skip not related to Activation property.
66         return;
67     }
68 
69     auto& imageProperty = std::get<InterfaceName>(attr->second);
70     if (imageProperty.empty())
71     {
72         // Skip, no image property
73         return;
74     }
75 
76     if (imageProperty ==
77             "xyz.openbmc_project.Software.Activation.Activations.Ready" &&
78         !isSoftwareUpdateInProgress())
79     {
80         log<level::INFO>("Software path interface add signal received");
81 
82         // Set status to code update in progress.
83         // Interface added signal triggered multiple times in code update path,
84         // it's due to additional interfaces added by the software manager app
85         // after the version interface is created.
86         // Device tree data collection is required only for the first trigger
87         setSoftwareUpdateProgress(true);
88 
89         try
90         {
91             // Colect device tree data
92             openpower::phal::fwupdate::exportDevtree();
93         }
94         catch (const fs::filesystem_error& e)
95         {
96             log<level::ERR>(
97                 std::format("Filesystem error reported Error:({})", e.what())
98                     .c_str());
99             throw std::runtime_error(e.what());
100         }
101 
102         log<level::INFO>("Successfully exported devtree attribute data");
103     }
104 
105     return;
106 }
107 
108 void exportDevtree()
109 {
110     constexpr auto ERROR_DEVTREE_BACKUP =
111         "org.open_power.PHAL.Error.devtreeBackup";
112 
113     // Check devtree export filter file is present
114     auto path = fs::path(DEVTREE_EXPORT_FILTER_FILE);
115     if (!fs::exists(path))
116     {
117         log<level::ERR>(
118             std::format("devtree export filter file is not available: ({})",
119                         DEVTREE_EXPORT_FILTER_FILE)
120                 .c_str());
121         openpower::pel::createPEL(ERROR_DEVTREE_BACKUP);
122         return;
123     }
124 
125     // delete export data file if present
126     auto expFile = fs::path(DEVTREE_EXP_FILE);
127     if (fs::exists(expFile))
128     {
129         fs::remove_all(expFile);
130     }
131     else
132     {
133         // create directory
134         fs::create_directory(expFile.parent_path());
135     }
136 
137     // Update PDBG_DTB value
138     openpower::phal::setDevtreeEnv();
139 
140     // Update PDATA_INFODB value
141     openpower::phal::setPdataInfoDBEnv();
142 
143     int status = 0;
144     pid_t pid = fork();
145     if (pid == 0)
146     {
147         std::string cmd("/usr/bin/attributes ");
148         cmd += "export ";
149         cmd += DEVTREE_EXPORT_FILTER_FILE;
150         cmd += " > ";
151         cmd += DEVTREE_EXP_FILE;
152         execl("/bin/sh", "sh", "-c", cmd.c_str(), 0);
153 
154         auto error = errno;
155         log<level::ERR>(std::format("Error occurred during attributes function "
156                                     "execution, errno({})",
157                                     error)
158                             .c_str());
159         // Creating PEL at one place.
160     }
161     else if (pid > 0)
162     {
163         waitpid(pid, &status, 0);
164         if (WEXITSTATUS(status))
165         {
166             log<level::ERR>("Failed to collect attribute export data");
167             openpower::pel::createPEL(ERROR_DEVTREE_BACKUP);
168         }
169     }
170     else
171     {
172         log<level::ERR>("exportDevtree fork() failed");
173         std::runtime_error("exportDevtree fork() failed");
174     }
175 }
176 
177 } // namespace fwupdate
178 } // namespace phal
179 } // namespace openpower
180