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
fwIntfAddedCallback(sdbusplus::message_t & msg)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
exportDevtree()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