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