blob: 8f2c735f0bf8fbeef29fe3e082bb364ebba9c121 [file] [log] [blame]
Patrick Venture3ecb3502019-05-17 11:03:51 -07001/*
2 * Copyright 2019 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Venturecf066ac2019-08-06 09:03:47 -070017#include "general_systemd.hpp"
Patrick Venture3ecb3502019-05-17 11:03:51 -070018
19#include "status.hpp"
20
Patrick Venture9b37b092020-05-28 20:58:57 -070021#include <sdbusplus/bus.hpp>
22
Patrick Venture3ecb3502019-05-17 11:03:51 -070023#include <fstream>
24#include <memory>
Patrick Venture3ecb3502019-05-17 11:03:51 -070025#include <string>
26#include <vector>
27
Patrick Venture1d5a31c2019-05-20 11:38:22 -070028namespace ipmi_flash
Patrick Venture3ecb3502019-05-17 11:03:51 -070029{
30
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -080031static constexpr auto systemdService = "org.freedesktop.systemd1";
32static constexpr auto systemdRoot = "/org/freedesktop/systemd1";
33static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
William A. Kennington III01593f92020-04-11 23:21:11 -070034static constexpr auto jobInterface = "org.freedesktop.systemd1.Job";
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -080035
36bool SystemdNoFile::trigger()
37{
38 if (job)
39 {
40 std::fprintf(stderr, "Job alreading running %s: %s\n",
41 triggerService.c_str(), job->c_str());
42 return false;
43 }
44
45 try
46 {
47 jobMonitor.emplace(
48 bus,
49 "type='signal',"
50 "sender='org.freedesktop.systemd1',"
51 "path='/org/freedesktop/systemd1',"
52 "interface='org.freedesktop.systemd1.Manager',"
53 "member='JobRemoved',",
54 [&](sdbusplus::message::message& m) { this->match(m); });
55
56 auto method = bus.new_method_call(systemdService, systemdRoot,
57 systemdInterface, "StartUnit");
58 method.append(triggerService);
59 method.append(mode);
60
61 sdbusplus::message::object_path obj_path;
62 bus.call(method).read(obj_path);
63 job = std::move(obj_path);
64 std::fprintf(stderr, "Triggered %s mode %s: %s\n",
65 triggerService.c_str(), mode.c_str(), job->c_str());
66 currentStatus = ActionStatus::running;
67 return true;
68 }
69 catch (const std::exception& e)
70 {
71 job = std::nullopt;
72 jobMonitor = std::nullopt;
73 currentStatus = ActionStatus::failed;
74 std::fprintf(stderr, "Failed to trigger %s mode %s: %s\n",
75 triggerService.c_str(), mode.c_str(), e.what());
76 return false;
77 }
78}
79
80void SystemdNoFile::abort()
81{
82 if (!job)
83 {
84 std::fprintf(stderr, "No running job %s\n", triggerService.c_str());
85 return;
86 }
87
88 // Cancel the job
89 auto cancel_req = bus.new_method_call(systemdService, job->c_str(),
William A. Kennington III01593f92020-04-11 23:21:11 -070090 jobInterface, "Cancel");
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -080091 try
92 {
93 bus.call_noreply(cancel_req);
94 std::fprintf(stderr, "Canceled %s: %s\n", triggerService.c_str(),
95 job->c_str());
96 }
97 catch (const sdbusplus::exception::SdBusError& ex)
98 {
99 std::fprintf(stderr, "Failed to cancel job %s %s: %s\n",
100 triggerService.c_str(), job->c_str(), ex.what());
101 }
102}
103
104ActionStatus SystemdNoFile::status()
105{
106 return currentStatus;
107}
108
109const std::string& SystemdNoFile::getMode() const
110{
111 return mode;
112}
113
114void SystemdNoFile::match(sdbusplus::message::message& m)
115{
116 if (!job)
117 {
118 std::fprintf(stderr, "No running job %s\n", triggerService.c_str());
119 return;
120 }
121
122 uint32_t job_id;
123 sdbusplus::message::object_path job_path;
124 std::string unit;
125 std::string result;
126 try
127 {
128 m.read(job_id, job_path, unit, result);
129 }
130 catch (const sdbusplus::exception::SdBusError& e)
131 {
132 std::fprintf(stderr, "Bad JobRemoved signal %s: %s\n",
133 triggerService.c_str(), e.what());
134 return;
135 }
136
137 if (*job != job_path.str)
138 {
139 return;
140 }
141
142 std::fprintf(stderr, "Job Finished %s %s: %s\n", triggerService.c_str(),
143 job->c_str(), result.c_str());
144 jobMonitor = std::nullopt;
145 job = std::nullopt;
146 currentStatus =
147 result == "done" ? ActionStatus::success : ActionStatus::failed;
148}
149
150std::unique_ptr<TriggerableActionInterface>
151 SystemdNoFile::CreateSystemdNoFile(sdbusplus::bus::bus&& bus,
152 const std::string& service,
153 const std::string& mode)
154{
155 return std::make_unique<SystemdNoFile>(std::move(bus), service, mode);
156}
157
Patrick Venture1d66fe62019-06-03 14:57:27 -0700158std::unique_ptr<TriggerableActionInterface>
Patrick Venturecf066ac2019-08-06 09:03:47 -0700159 SystemdWithStatusFile::CreateSystemdWithStatusFile(
160 sdbusplus::bus::bus&& bus, const std::string& path,
161 const std::string& service, const std::string& mode)
Patrick Venture3ecb3502019-05-17 11:03:51 -0700162{
Patrick Venture29af1e32019-08-05 13:42:28 -0700163 return std::make_unique<SystemdWithStatusFile>(std::move(bus), path,
164 service, mode);
Patrick Venture3ecb3502019-05-17 11:03:51 -0700165}
166
William A. Kennington III93f3c552020-04-07 18:23:53 -0700167bool SystemdWithStatusFile::trigger()
168{
169 if (SystemdNoFile::status() != ActionStatus::running)
170 {
171 try
172 {
173 std::ofstream ofs;
174 ofs.open(checkPath);
175 ofs << "unknown";
176 }
177 catch (const std::exception& e)
178 {
179 return false;
180 }
181 }
182 return SystemdNoFile::trigger();
183}
184
Patrick Venture29af1e32019-08-05 13:42:28 -0700185ActionStatus SystemdWithStatusFile::status()
Patrick Venture3ecb3502019-05-17 11:03:51 -0700186{
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -0800187 // Assume a status based on job execution if there is no file
188 ActionStatus result = SystemdNoFile::status() == ActionStatus::running
189 ? ActionStatus::running
190 : ActionStatus::failed;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700191
192 std::ifstream ifs;
193 ifs.open(checkPath);
194 if (ifs.good())
195 {
196 /*
197 * Check for the contents of the file, accepting:
198 * running, success, or failed.
199 */
200 std::string status;
201 ifs >> status;
202 if (status == "running")
203 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700204 result = ActionStatus::running;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700205 }
206 else if (status == "success")
207 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700208 result = ActionStatus::success;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700209 }
210 else if (status == "failed")
211 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700212 result = ActionStatus::failed;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700213 }
William A. Kennington III93f3c552020-04-07 18:23:53 -0700214 else
215 {
216 result = ActionStatus::unknown;
217 }
Patrick Venture3ecb3502019-05-17 11:03:51 -0700218 }
219
220 return result;
221}
222
Patrick Venture1d5a31c2019-05-20 11:38:22 -0700223} // namespace ipmi_flash