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 
storeToFile(const std::string & versionId,uint8_t priority)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 
restoreFromFile(const std::string & versionId,uint8_t & priority)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 
removeFile(const std::string & versionId)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 =
120         "obmc-flash-bmc-setenv@pnor\\x2d" + versionId + ".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