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