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