blob: 29bd6400f867d1d0f24508630581bf506c91e069 [file] [log] [blame]
Saqib Khan5d532672017-08-09 10:44:50 -05001#include "config.h"
2#include <experimental/filesystem>
3#include <cereal/archives/json.hpp>
4#include <fstream>
Michael Tritz2225fda2018-03-06 10:35:36 -06005#include <unistd.h>
Saqib Khan5d532672017-08-09 10:44:50 -05006#include "serialize.hpp"
Saqib Khan1eef62d2017-08-10 15:29:34 -05007#include <sdbusplus/server.hpp>
Michael Tritz2225fda2018-03-06 10:35:36 -06008#include <phosphor-logging/log.hpp>
9#include <chrono>
Saqib Khan5d532672017-08-09 10:44:50 -050010
11namespace phosphor
12{
13namespace software
14{
15namespace updater
16{
17
18namespace fs = std::experimental::filesystem;
19
Michael Tritz2225fda2018-03-06 10:35:36 -060020using namespace phosphor::logging;
21using namespace std::chrono_literals;
22
Saqib Khan5d532672017-08-09 10:44:50 -050023void storeToFile(std::string versionId, uint8_t priority)
24{
Saqib Khan1eef62d2017-08-10 15:29:34 -050025 auto bus = sdbusplus::bus::new_default();
26
Gunnar Millsffe04922017-10-06 13:20:43 -050027 if (!fs::is_directory(PERSIST_DIR))
Saqib Khan5d532672017-08-09 10:44:50 -050028 {
Michael Tritz49860e12017-09-18 14:33:54 -050029 fs::create_directories(PERSIST_DIR);
Saqib Khan5d532672017-08-09 10:44:50 -050030 }
31 std::string path = PERSIST_DIR + versionId;
32
33 std::ofstream os(path.c_str());
34 cereal::JSONOutputArchive oarchive(os);
35 oarchive(cereal::make_nvp("priority", priority));
Saqib Khan1eef62d2017-08-10 15:29:34 -050036
37 std::string serviceFile = "obmc-flash-bmc-setenv@" + versionId + "\\x3d" +
Adriana Kobylak2285fe02018-02-27 15:36:59 -060038 std::to_string(priority) + ".service";
39 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
40 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khan1eef62d2017-08-10 15:29:34 -050041 method.append(serviceFile, "replace");
42 bus.call_noreply(method);
Michael Tritz2225fda2018-03-06 10:35:36 -060043
44 // On average it takes 1-2 seconds for the service to complete.
45 // Therefore timeout is set to 3x average completion time.
46 waitForServiceFile(serviceFile, 6);
Saqib Khan5d532672017-08-09 10:44:50 -050047}
48
Saqib Khan1eef62d2017-08-10 15:29:34 -050049bool restoreFromFile(std::string versionId, uint8_t& priority)
Saqib Khan5d532672017-08-09 10:44:50 -050050{
51 std::string path = PERSIST_DIR + versionId;
52 if (fs::exists(path))
53 {
54 std::ifstream is(path.c_str(), std::ios::in);
Saqib Khan1eef62d2017-08-10 15:29:34 -050055 try
56 {
57 cereal::JSONInputArchive iarchive(is);
58 iarchive(cereal::make_nvp("priority", priority));
59 return true;
60 }
Gunnar Millsffe04922017-10-06 13:20:43 -050061 catch (cereal::RapidJSONException& e)
Saqib Khan1eef62d2017-08-10 15:29:34 -050062 {
63 fs::remove(path);
64 }
Saqib Khan5d532672017-08-09 10:44:50 -050065 }
Saqib Khan1eef62d2017-08-10 15:29:34 -050066
67 // Find the mtd device "u-boot-env" to retrieve the environment variables
68 std::ifstream mtdDevices("/proc/mtd");
69 std::string device, devicePath;
70
71 try
72 {
Gunnar Millsffe04922017-10-06 13:20:43 -050073 while (std::getline(mtdDevices, device))
74 {
Saqib Khan1eef62d2017-08-10 15:29:34 -050075 if (device.find("u-boot-env") != std::string::npos)
76 {
77 devicePath = "/dev/" + device.substr(0, device.find(':'));
78 break;
79 }
80 }
81
82 if (!devicePath.empty())
83 {
84 std::ifstream input(devicePath.c_str());
85 std::string envVars;
86 std::getline(input, envVars);
87
Michael Tritz6273efd2017-12-14 15:21:18 -060088 std::string versionVar = versionId + "=";
89 auto varPosition = envVars.find(versionVar);
90
91 if (varPosition != std::string::npos)
Saqib Khan1eef62d2017-08-10 15:29:34 -050092 {
93 // Grab the environment variable for this versionId. These
94 // variables follow the format "versionId=priority\0"
Michael Tritz6273efd2017-12-14 15:21:18 -060095 auto var = envVars.substr(varPosition);
96 priority = std::stoi(var.substr(versionVar.length()));
Saqib Khan1eef62d2017-08-10 15:29:34 -050097 return true;
98 }
99 }
100 }
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600101 catch (const std::exception& e)
102 {
103 }
Saqib Khan1eef62d2017-08-10 15:29:34 -0500104
105 return false;
Saqib Khan5d532672017-08-09 10:44:50 -0500106}
107
108void removeFile(std::string versionId)
109{
110 std::string path = PERSIST_DIR + versionId;
111 if (fs::exists(path))
112 {
113 fs::remove(path);
114 }
115}
116
Michael Tritz2225fda2018-03-06 10:35:36 -0600117void waitForServiceFile(const std::string& serviceFile, int timeout)
118{
119 auto bus = sdbusplus::bus::new_default();
120
121 std::time_t start = time(0);
122 std::time_t end = time(0);
123
124 while (end - start < timeout)
125 {
126 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
127 SYSTEMD_INTERFACE, "GetUnit");
128 method.append(serviceFile);
129 auto result = bus.call(method);
130
131 // "GetUnit" returns the unit object path for a unit name.
132 // If the unit is not found because it hasn't been loaded yet,
133 // or in this case because it has finished and exited, the call
134 // will fail.
135 if (result.is_method_error())
136 {
137 return;
138 }
139
140 std::this_thread::sleep_for(1s);
141 end = time(0);
142 }
143
144 log<level::ERR>("Service file timed out!",
145 entry("FILENAME=%s", serviceFile.c_str()));
146}
147
Saqib Khan5d532672017-08-09 10:44:50 -0500148} // namespace phosphor
149} // namespace software
150} // namespace openpower