blob: b036bbf751f7baffccb405e4242f0b91e78f10a4 [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
21#include <fstream>
22#include <memory>
23#include <sdbusplus/bus.hpp>
24#include <string>
25#include <vector>
26
Patrick Venture1d5a31c2019-05-20 11:38:22 -070027namespace ipmi_flash
Patrick Venture3ecb3502019-05-17 11:03:51 -070028{
29
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -080030static constexpr auto systemdService = "org.freedesktop.systemd1";
31static constexpr auto systemdRoot = "/org/freedesktop/systemd1";
32static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
William A. Kennington III01593f92020-04-11 23:21:11 -070033static constexpr auto jobInterface = "org.freedesktop.systemd1.Job";
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -080034
35bool SystemdNoFile::trigger()
36{
37 if (job)
38 {
39 std::fprintf(stderr, "Job alreading running %s: %s\n",
40 triggerService.c_str(), job->c_str());
41 return false;
42 }
43
44 try
45 {
46 jobMonitor.emplace(
47 bus,
48 "type='signal',"
49 "sender='org.freedesktop.systemd1',"
50 "path='/org/freedesktop/systemd1',"
51 "interface='org.freedesktop.systemd1.Manager',"
52 "member='JobRemoved',",
53 [&](sdbusplus::message::message& m) { this->match(m); });
54
55 auto method = bus.new_method_call(systemdService, systemdRoot,
56 systemdInterface, "StartUnit");
57 method.append(triggerService);
58 method.append(mode);
59
60 sdbusplus::message::object_path obj_path;
61 bus.call(method).read(obj_path);
62 job = std::move(obj_path);
63 std::fprintf(stderr, "Triggered %s mode %s: %s\n",
64 triggerService.c_str(), mode.c_str(), job->c_str());
65 currentStatus = ActionStatus::running;
66 return true;
67 }
68 catch (const std::exception& e)
69 {
70 job = std::nullopt;
71 jobMonitor = std::nullopt;
72 currentStatus = ActionStatus::failed;
73 std::fprintf(stderr, "Failed to trigger %s mode %s: %s\n",
74 triggerService.c_str(), mode.c_str(), e.what());
75 return false;
76 }
77}
78
79void SystemdNoFile::abort()
80{
81 if (!job)
82 {
83 std::fprintf(stderr, "No running job %s\n", triggerService.c_str());
84 return;
85 }
86
87 // Cancel the job
88 auto cancel_req = bus.new_method_call(systemdService, job->c_str(),
William A. Kennington III01593f92020-04-11 23:21:11 -070089 jobInterface, "Cancel");
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -080090 try
91 {
92 bus.call_noreply(cancel_req);
93 std::fprintf(stderr, "Canceled %s: %s\n", triggerService.c_str(),
94 job->c_str());
95 }
96 catch (const sdbusplus::exception::SdBusError& ex)
97 {
98 std::fprintf(stderr, "Failed to cancel job %s %s: %s\n",
99 triggerService.c_str(), job->c_str(), ex.what());
100 }
101}
102
103ActionStatus SystemdNoFile::status()
104{
105 return currentStatus;
106}
107
108const std::string& SystemdNoFile::getMode() const
109{
110 return mode;
111}
112
113void SystemdNoFile::match(sdbusplus::message::message& m)
114{
115 if (!job)
116 {
117 std::fprintf(stderr, "No running job %s\n", triggerService.c_str());
118 return;
119 }
120
121 uint32_t job_id;
122 sdbusplus::message::object_path job_path;
123 std::string unit;
124 std::string result;
125 try
126 {
127 m.read(job_id, job_path, unit, result);
128 }
129 catch (const sdbusplus::exception::SdBusError& e)
130 {
131 std::fprintf(stderr, "Bad JobRemoved signal %s: %s\n",
132 triggerService.c_str(), e.what());
133 return;
134 }
135
136 if (*job != job_path.str)
137 {
138 return;
139 }
140
141 std::fprintf(stderr, "Job Finished %s %s: %s\n", triggerService.c_str(),
142 job->c_str(), result.c_str());
143 jobMonitor = std::nullopt;
144 job = std::nullopt;
145 currentStatus =
146 result == "done" ? ActionStatus::success : ActionStatus::failed;
147}
148
149std::unique_ptr<TriggerableActionInterface>
150 SystemdNoFile::CreateSystemdNoFile(sdbusplus::bus::bus&& bus,
151 const std::string& service,
152 const std::string& mode)
153{
154 return std::make_unique<SystemdNoFile>(std::move(bus), service, mode);
155}
156
Patrick Venture1d66fe62019-06-03 14:57:27 -0700157std::unique_ptr<TriggerableActionInterface>
Patrick Venturecf066ac2019-08-06 09:03:47 -0700158 SystemdWithStatusFile::CreateSystemdWithStatusFile(
159 sdbusplus::bus::bus&& bus, const std::string& path,
160 const std::string& service, const std::string& mode)
Patrick Venture3ecb3502019-05-17 11:03:51 -0700161{
Patrick Venture29af1e32019-08-05 13:42:28 -0700162 return std::make_unique<SystemdWithStatusFile>(std::move(bus), path,
163 service, mode);
Patrick Venture3ecb3502019-05-17 11:03:51 -0700164}
165
William A. Kennington III93f3c552020-04-07 18:23:53 -0700166bool SystemdWithStatusFile::trigger()
167{
168 if (SystemdNoFile::status() != ActionStatus::running)
169 {
170 try
171 {
172 std::ofstream ofs;
173 ofs.open(checkPath);
174 ofs << "unknown";
175 }
176 catch (const std::exception& e)
177 {
178 return false;
179 }
180 }
181 return SystemdNoFile::trigger();
182}
183
Patrick Venture29af1e32019-08-05 13:42:28 -0700184ActionStatus SystemdWithStatusFile::status()
Patrick Venture3ecb3502019-05-17 11:03:51 -0700185{
William A. Kennington IIIb22ebbf2019-11-19 17:03:48 -0800186 // Assume a status based on job execution if there is no file
187 ActionStatus result = SystemdNoFile::status() == ActionStatus::running
188 ? ActionStatus::running
189 : ActionStatus::failed;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700190
191 std::ifstream ifs;
192 ifs.open(checkPath);
193 if (ifs.good())
194 {
195 /*
196 * Check for the contents of the file, accepting:
197 * running, success, or failed.
198 */
199 std::string status;
200 ifs >> status;
201 if (status == "running")
202 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700203 result = ActionStatus::running;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700204 }
205 else if (status == "success")
206 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700207 result = ActionStatus::success;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700208 }
209 else if (status == "failed")
210 {
Patrick Ventureda66fd82019-06-03 11:11:24 -0700211 result = ActionStatus::failed;
Patrick Venture3ecb3502019-05-17 11:03:51 -0700212 }
William A. Kennington III93f3c552020-04-07 18:23:53 -0700213 else
214 {
215 result = ActionStatus::unknown;
216 }
Patrick Venture3ecb3502019-05-17 11:03:51 -0700217 }
218
219 return result;
220}
221
Patrick Venture1d5a31c2019-05-20 11:38:22 -0700222} // namespace ipmi_flash