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