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 <phosphor-logging/log.hpp>
9 #include <sdbusplus/server.hpp>
10 
11 namespace phosphor
12 {
13 namespace software
14 {
15 namespace updater
16 {
17 
18 using namespace phosphor::logging;
19 namespace fs = std::experimental::filesystem;
20 
21 const std::string priorityName = "priority";
22 const std::string purposeName = "purpose";
23 
24 void storePriority(const std::string& versionId, uint8_t priority)
25 {
26     auto path = fs::path(PERSIST_DIR) / versionId;
27     if (!fs::is_directory(path))
28     {
29         if (fs::exists(path))
30         {
31             // Delete if it's a non-directory file
32             log<level::WARNING>("Removing non-directory file",
33                                 entry("PATH=%s", path.c_str()));
34             fs::remove_all(path);
35         }
36         fs::create_directories(path);
37     }
38     path = path / priorityName;
39 
40     std::ofstream os(path.c_str());
41     cereal::JSONOutputArchive oarchive(os);
42     oarchive(cereal::make_nvp(priorityName, priority));
43 }
44 
45 void storePurpose(const std::string& versionId, VersionPurpose purpose)
46 {
47     auto path = fs::path(PERSIST_DIR) / versionId;
48     if (!fs::is_directory(path))
49     {
50         if (fs::exists(path))
51         {
52             // Delete if it's a non-directory file
53             log<level::WARNING>("Removing non-directory file",
54                                 entry("PATH=%s", path.c_str()));
55             fs::remove_all(path);
56         }
57         fs::create_directories(path);
58     }
59     path = path / purposeName;
60 
61     std::ofstream os(path.c_str());
62     cereal::JSONOutputArchive oarchive(os);
63     oarchive(cereal::make_nvp(purposeName, purpose));
64 }
65 
66 bool restorePriority(const std::string& versionId, uint8_t& priority)
67 {
68     auto path = fs::path(PERSIST_DIR) / versionId / priorityName;
69     if (fs::exists(path))
70     {
71         std::ifstream is(path.c_str(), std::ios::in);
72         try
73         {
74             cereal::JSONInputArchive iarchive(is);
75             iarchive(cereal::make_nvp(priorityName, priority));
76             return true;
77         }
78         catch (cereal::Exception& e)
79         {
80             fs::remove_all(path);
81         }
82     }
83 
84     // Find the mtd device "u-boot-env" to retrieve the environment variables
85     std::ifstream mtdDevices("/proc/mtd");
86     std::string device, devicePath;
87 
88     try
89     {
90         while (std::getline(mtdDevices, device))
91         {
92             if (device.find("u-boot-env") != std::string::npos)
93             {
94                 devicePath = "/dev/" + device.substr(0, device.find(':'));
95                 break;
96             }
97         }
98 
99         if (!devicePath.empty())
100         {
101             std::ifstream input(devicePath.c_str());
102             std::string envVars;
103             std::getline(input, envVars);
104 
105             std::string versionVar = versionId + "=";
106             auto varPosition = envVars.find(versionVar);
107 
108             if (varPosition != std::string::npos)
109             {
110                 // Grab the environment variable for this versionId. These
111                 // variables follow the format "versionId=priority\0"
112                 auto var = envVars.substr(varPosition);
113                 priority = std::stoi(var.substr(versionVar.length()));
114                 return true;
115             }
116         }
117     }
118     catch (const std::exception& e)
119     {
120     }
121 
122     return false;
123 }
124 
125 bool restorePurpose(const std::string& versionId, VersionPurpose& purpose)
126 {
127     auto path = fs::path(PERSIST_DIR) / versionId / purposeName;
128     if (fs::exists(path))
129     {
130         std::ifstream is(path.c_str(), std::ios::in);
131         try
132         {
133             cereal::JSONInputArchive iarchive(is);
134             iarchive(cereal::make_nvp(purposeName, purpose));
135             return true;
136         }
137         catch (cereal::Exception& e)
138         {
139             fs::remove_all(path);
140         }
141     }
142 
143     return false;
144 }
145 
146 void removePersistDataDirectory(const std::string& versionId)
147 {
148     auto path = fs::path(PERSIST_DIR) / versionId;
149     if (fs::exists(path))
150     {
151         fs::remove_all(path);
152     }
153 }
154 
155 } // namespace updater
156 } // namespace software
157 } // namespace phosphor
158