1 #include "config.h" 2 3 #include "serialize.hpp" 4 5 #include <cereal/archives/json.hpp> 6 #include <sdbusplus/server.hpp> 7 8 #include <filesystem> 9 #include <fstream> 10 11 namespace openpower 12 { 13 namespace software 14 { 15 namespace updater 16 { 17 18 void storeToFile(const std::string& versionId, uint8_t priority) 19 { 20 auto bus = sdbusplus::bus::new_default(); 21 22 if (!std::filesystem::is_directory(PERSIST_DIR)) 23 { 24 std::filesystem::create_directories(PERSIST_DIR); 25 } 26 27 // store one copy in /var/lib/obmc/openpower-pnor-code-mgmt/[versionId] 28 auto varPath = PERSIST_DIR + versionId; 29 std::ofstream varOutput(varPath.c_str()); 30 cereal::JSONOutputArchive varArchive(varOutput); 31 varArchive(cereal::make_nvp("priority", priority)); 32 33 if (std::filesystem::is_directory(PNOR_RW_PREFIX + versionId)) 34 { 35 // store another copy in /media/pnor-rw-[versionId]/[versionId] 36 auto rwPath = PNOR_RW_PREFIX + versionId + "/" + versionId; 37 std::ofstream rwOutput(rwPath.c_str()); 38 cereal::JSONOutputArchive rwArchive(rwOutput); 39 rwArchive(cereal::make_nvp("priority", priority)); 40 } 41 42 // lastly, store the priority as an environment variable pnor-[versionId] 43 std::string serviceFile = "obmc-flash-bmc-setenv@pnor\\x2d" + versionId + 44 "\\x3d" + std::to_string(priority) + ".service"; 45 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 46 SYSTEMD_INTERFACE, "StartUnit"); 47 method.append(serviceFile, "replace"); 48 bus.call_noreply(method); 49 } 50 51 bool restoreFromFile(const std::string& versionId, uint8_t& priority) 52 { 53 auto varPath = PERSIST_DIR + versionId; 54 if (std::filesystem::exists(varPath)) 55 { 56 std::ifstream varInput(varPath.c_str(), std::ios::in); 57 try 58 { 59 cereal::JSONInputArchive varArchive(varInput); 60 varArchive(cereal::make_nvp("priority", priority)); 61 return true; 62 } 63 catch (const cereal::RapidJSONException& e) 64 { 65 std::filesystem::remove(varPath); 66 } 67 } 68 69 auto rwPath = PNOR_RW_PREFIX + versionId + "/" + versionId; 70 if (std::filesystem::exists(rwPath)) 71 { 72 std::ifstream rwInput(rwPath.c_str(), std::ios::in); 73 try 74 { 75 cereal::JSONInputArchive rwArchive(rwInput); 76 rwArchive(cereal::make_nvp("priority", priority)); 77 return true; 78 } 79 catch (const cereal::RapidJSONException& e) 80 { 81 std::filesystem::remove(rwPath); 82 } 83 } 84 85 try 86 { 87 std::string devicePath = "/dev/mtd/u-boot-env"; 88 89 if (std::filesystem::exists(devicePath) && !devicePath.empty()) 90 { 91 std::ifstream input(devicePath.c_str()); 92 std::string envVars; 93 std::getline(input, envVars); 94 95 std::string versionVar = "pnor-" + versionId + "="; 96 auto varPosition = envVars.find(versionVar); 97 98 if (varPosition != std::string::npos) 99 { 100 // Grab the environment variable for this versionId. These 101 // variables follow the format "pnor-[versionId]=[priority]\0" 102 auto var = envVars.substr(varPosition); 103 priority = std::stoi(var.substr(versionVar.length())); 104 return true; 105 } 106 } 107 } 108 catch (const std::exception& e) 109 {} 110 111 return false; 112 } 113 114 void removeFile(const std::string& versionId) 115 { 116 auto bus = sdbusplus::bus::new_default(); 117 118 // Clear the environment variable pnor-[versionId]. 119 std::string serviceFile = "obmc-flash-bmc-setenv@pnor\\x2d" + versionId + 120 ".service"; 121 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 122 SYSTEMD_INTERFACE, "StartUnit"); 123 method.append(serviceFile, "replace"); 124 bus.call_noreply(method); 125 126 // Delete the file /var/lib/obmc/openpower-pnor-code-mgmt/[versionId]. 127 // Note that removeFile() is called in the case of a version being deleted, 128 // so the file /media/pnor-rw-[versionId]/[versionId] will also be deleted 129 // along with its surrounding directory. 130 std::string path = PERSIST_DIR + versionId; 131 if (std::filesystem::exists(path)) 132 { 133 std::filesystem::remove(path); 134 } 135 } 136 137 } // namespace updater 138 } // namespace software 139 } // namespace openpower 140