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