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 
12 namespace phosphor
13 {
14 namespace software
15 {
16 namespace updater
17 {
18 
19 PHOSPHOR_LOG2_USING;
20 namespace fs = std::filesystem;
21 
22 const std::string priorityName = "priority";
23 const std::string purposeName = "purpose";
24 
25 void storePriority(const std::string& versionId, uint8_t priority)
26 {
27     auto path = fs::path(PERSIST_DIR) / versionId;
28     if (!fs::is_directory(path))
29     {
30         if (fs::exists(path))
31         {
32             // Delete if it's a non-directory file
33             warning("Removing non-directory file: {PATH}", "PATH", path);
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             warning("Removing non-directory file: {PATH}", "PATH", path);
54             fs::remove_all(path);
55         }
56         fs::create_directories(path);
57     }
58     path = path / purposeName;
59 
60     std::ofstream os(path.c_str());
61     cereal::JSONOutputArchive oarchive(os);
62     oarchive(cereal::make_nvp(purposeName, purpose));
63 }
64 
65 bool restorePriority(const std::string& versionId, uint8_t& priority)
66 {
67     auto path = fs::path(PERSIST_DIR) / versionId / priorityName;
68     if (fs::exists(path))
69     {
70         std::ifstream is(path.c_str(), std::ios::in);
71         try
72         {
73             cereal::JSONInputArchive iarchive(is);
74             iarchive(cereal::make_nvp(priorityName, priority));
75             return true;
76         }
77         catch (const cereal::Exception& e)
78         {
79             fs::remove_all(path);
80         }
81     }
82 
83     // Find the mtd device "u-boot-env" to retrieve the environment variables
84     std::ifstream mtdDevices("/proc/mtd");
85     std::string device, devicePath;
86 
87     try
88     {
89         while (std::getline(mtdDevices, device))
90         {
91             if (device.find("u-boot-env") != std::string::npos)
92             {
93                 devicePath = "/dev/" + device.substr(0, device.find(':'));
94                 break;
95             }
96         }
97 
98         if (!devicePath.empty())
99         {
100             std::ifstream input(devicePath.c_str());
101             std::string envVars;
102             std::getline(input, envVars);
103 
104             std::string versionVar = versionId + "=";
105             auto varPosition = envVars.find(versionVar);
106 
107             if (varPosition != std::string::npos)
108             {
109                 // Grab the environment variable for this versionId. These
110                 // variables follow the format "versionId=priority\0"
111                 auto var = envVars.substr(varPosition);
112                 priority = std::stoi(var.substr(versionVar.length()));
113                 return true;
114             }
115         }
116     }
117     catch (const std::exception& e)
118     {
119         error("Error during processing: {ERROR}", "ERROR", e);
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 (const 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