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