xref: /openbmc/phosphor-ipmi-flash/bmc/general_systemd.cpp (revision 4175b4ca8372fd4452245db4f9328afa773e4d93)
1cf066aceSPatrick Venture /*
2cf066aceSPatrick Venture  * Copyright 2019 Google Inc.
3cf066aceSPatrick Venture  *
4cf066aceSPatrick Venture  * Licensed under the Apache License, Version 2.0 (the "License");
5cf066aceSPatrick Venture  * you may not use this file except in compliance with the License.
6cf066aceSPatrick Venture  * You may obtain a copy of the License at
7cf066aceSPatrick Venture  *
8cf066aceSPatrick Venture  *     http://www.apache.org/licenses/LICENSE-2.0
9cf066aceSPatrick Venture  *
10cf066aceSPatrick Venture  * Unless required by applicable law or agreed to in writing, software
11cf066aceSPatrick Venture  * distributed under the License is distributed on an "AS IS" BASIS,
12cf066aceSPatrick Venture  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cf066aceSPatrick Venture  * See the License for the specific language governing permissions and
14cf066aceSPatrick Venture  * limitations under the License.
15cf066aceSPatrick Venture  */
16cf066aceSPatrick Venture 
17cf066aceSPatrick Venture #include "general_systemd.hpp"
18cf066aceSPatrick Venture 
19cf066aceSPatrick Venture #include "status.hpp"
20cf066aceSPatrick Venture 
219b37b095SPatrick Venture #include <sdbusplus/bus.hpp>
229b37b095SPatrick Venture 
23cf066aceSPatrick Venture #include <fstream>
24cf066aceSPatrick Venture #include <memory>
25cf066aceSPatrick Venture #include <string>
26cf066aceSPatrick Venture #include <vector>
27cf066aceSPatrick Venture 
28cf066aceSPatrick Venture namespace ipmi_flash
29cf066aceSPatrick Venture {
30cf066aceSPatrick Venture 
31b22ebbf3SWilliam A. Kennington III static constexpr auto systemdService = "org.freedesktop.systemd1";
32b22ebbf3SWilliam A. Kennington III static constexpr auto systemdRoot = "/org/freedesktop/systemd1";
33b22ebbf3SWilliam A. Kennington III static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
3401593f96SWilliam A. Kennington III static constexpr auto jobInterface = "org.freedesktop.systemd1.Job";
35b22ebbf3SWilliam A. Kennington III 
36b22ebbf3SWilliam A. Kennington III bool SystemdNoFile::trigger()
37b22ebbf3SWilliam A. Kennington III {
38b22ebbf3SWilliam A. Kennington III     if (job)
39b22ebbf3SWilliam A. Kennington III     {
40b22ebbf3SWilliam A. Kennington III         std::fprintf(stderr, "Job alreading running %s: %s\n",
41b22ebbf3SWilliam A. Kennington III                      triggerService.c_str(), job->c_str());
42b22ebbf3SWilliam A. Kennington III         return false;
43b22ebbf3SWilliam A. Kennington III     }
44b22ebbf3SWilliam A. Kennington III 
45b22ebbf3SWilliam A. Kennington III     try
46b22ebbf3SWilliam A. Kennington III     {
47b22ebbf3SWilliam A. Kennington III         jobMonitor.emplace(
48b22ebbf3SWilliam A. Kennington III             bus,
49b22ebbf3SWilliam A. Kennington III             "type='signal',"
50b22ebbf3SWilliam A. Kennington III             "sender='org.freedesktop.systemd1',"
51b22ebbf3SWilliam A. Kennington III             "path='/org/freedesktop/systemd1',"
52b22ebbf3SWilliam A. Kennington III             "interface='org.freedesktop.systemd1.Manager',"
53b22ebbf3SWilliam A. Kennington III             "member='JobRemoved',",
54b22ebbf3SWilliam A. Kennington III             [&](sdbusplus::message::message& m) { this->match(m); });
55b22ebbf3SWilliam A. Kennington III 
56b22ebbf3SWilliam A. Kennington III         auto method = bus.new_method_call(systemdService, systemdRoot,
57b22ebbf3SWilliam A. Kennington III                                           systemdInterface, "StartUnit");
58b22ebbf3SWilliam A. Kennington III         method.append(triggerService);
59b22ebbf3SWilliam A. Kennington III         method.append(mode);
60b22ebbf3SWilliam A. Kennington III 
61b22ebbf3SWilliam A. Kennington III         sdbusplus::message::object_path obj_path;
62b22ebbf3SWilliam A. Kennington III         bus.call(method).read(obj_path);
63b22ebbf3SWilliam A. Kennington III         job = std::move(obj_path);
64b22ebbf3SWilliam A. Kennington III         std::fprintf(stderr, "Triggered %s mode %s: %s\n",
65b22ebbf3SWilliam A. Kennington III                      triggerService.c_str(), mode.c_str(), job->c_str());
66b22ebbf3SWilliam A. Kennington III         currentStatus = ActionStatus::running;
67b22ebbf3SWilliam A. Kennington III         return true;
68b22ebbf3SWilliam A. Kennington III     }
69b22ebbf3SWilliam A. Kennington III     catch (const std::exception& e)
70b22ebbf3SWilliam A. Kennington III     {
71b22ebbf3SWilliam A. Kennington III         job = std::nullopt;
72b22ebbf3SWilliam A. Kennington III         jobMonitor = std::nullopt;
73b22ebbf3SWilliam A. Kennington III         currentStatus = ActionStatus::failed;
74b22ebbf3SWilliam A. Kennington III         std::fprintf(stderr, "Failed to trigger %s mode %s: %s\n",
75b22ebbf3SWilliam A. Kennington III                      triggerService.c_str(), mode.c_str(), e.what());
76b22ebbf3SWilliam A. Kennington III         return false;
77b22ebbf3SWilliam A. Kennington III     }
78b22ebbf3SWilliam A. Kennington III }
79b22ebbf3SWilliam A. Kennington III 
80b22ebbf3SWilliam A. Kennington III void SystemdNoFile::abort()
81b22ebbf3SWilliam A. Kennington III {
82b22ebbf3SWilliam A. Kennington III     if (!job)
83b22ebbf3SWilliam A. Kennington III     {
84b22ebbf3SWilliam A. Kennington III         return;
85b22ebbf3SWilliam A. Kennington III     }
86b22ebbf3SWilliam A. Kennington III 
87b22ebbf3SWilliam A. Kennington III     // Cancel the job
88b22ebbf3SWilliam A. Kennington III     auto cancel_req = bus.new_method_call(systemdService, job->c_str(),
8901593f96SWilliam A. Kennington III                                           jobInterface, "Cancel");
90b22ebbf3SWilliam A. Kennington III     try
91b22ebbf3SWilliam A. Kennington III     {
92b22ebbf3SWilliam A. Kennington III         bus.call_noreply(cancel_req);
93b22ebbf3SWilliam A. Kennington III         std::fprintf(stderr, "Canceled %s: %s\n", triggerService.c_str(),
94b22ebbf3SWilliam A. Kennington III                      job->c_str());
95b22ebbf3SWilliam A. Kennington III     }
96b22ebbf3SWilliam A. Kennington III     catch (const sdbusplus::exception::SdBusError& ex)
97b22ebbf3SWilliam A. Kennington III     {
98b22ebbf3SWilliam A. Kennington III         std::fprintf(stderr, "Failed to cancel job %s %s: %s\n",
99b22ebbf3SWilliam A. Kennington III                      triggerService.c_str(), job->c_str(), ex.what());
100b22ebbf3SWilliam A. Kennington III     }
101b22ebbf3SWilliam A. Kennington III }
102b22ebbf3SWilliam A. Kennington III 
103b22ebbf3SWilliam A. Kennington III ActionStatus SystemdNoFile::status()
104b22ebbf3SWilliam A. Kennington III {
105b22ebbf3SWilliam A. Kennington III     return currentStatus;
106b22ebbf3SWilliam A. Kennington III }
107b22ebbf3SWilliam A. Kennington III 
108b22ebbf3SWilliam A. Kennington III const std::string& SystemdNoFile::getMode() const
109b22ebbf3SWilliam A. Kennington III {
110b22ebbf3SWilliam A. Kennington III     return mode;
111b22ebbf3SWilliam A. Kennington III }
112b22ebbf3SWilliam A. Kennington III 
113b22ebbf3SWilliam A. Kennington III void SystemdNoFile::match(sdbusplus::message::message& m)
114b22ebbf3SWilliam A. Kennington III {
115b22ebbf3SWilliam A. Kennington III     if (!job)
116b22ebbf3SWilliam A. Kennington III     {
117b22ebbf3SWilliam A. Kennington III         std::fprintf(stderr, "No running job %s\n", triggerService.c_str());
118b22ebbf3SWilliam A. Kennington III         return;
119b22ebbf3SWilliam A. Kennington III     }
120b22ebbf3SWilliam A. Kennington III 
121b22ebbf3SWilliam A. Kennington III     uint32_t job_id;
122b22ebbf3SWilliam A. Kennington III     sdbusplus::message::object_path job_path;
123b22ebbf3SWilliam A. Kennington III     std::string unit;
124b22ebbf3SWilliam A. Kennington III     std::string result;
125b22ebbf3SWilliam A. Kennington III     try
126b22ebbf3SWilliam A. Kennington III     {
127b22ebbf3SWilliam A. Kennington III         m.read(job_id, job_path, unit, result);
128b22ebbf3SWilliam A. Kennington III     }
129b22ebbf3SWilliam A. Kennington III     catch (const sdbusplus::exception::SdBusError& e)
130b22ebbf3SWilliam A. Kennington III     {
131b22ebbf3SWilliam A. Kennington III         std::fprintf(stderr, "Bad JobRemoved signal %s: %s\n",
132b22ebbf3SWilliam A. Kennington III                      triggerService.c_str(), e.what());
133b22ebbf3SWilliam A. Kennington III         return;
134b22ebbf3SWilliam A. Kennington III     }
135b22ebbf3SWilliam A. Kennington III 
136b22ebbf3SWilliam A. Kennington III     if (*job != job_path.str)
137b22ebbf3SWilliam A. Kennington III     {
138b22ebbf3SWilliam A. Kennington III         return;
139b22ebbf3SWilliam A. Kennington III     }
140b22ebbf3SWilliam A. Kennington III 
141b22ebbf3SWilliam A. Kennington III     std::fprintf(stderr, "Job Finished %s %s: %s\n", triggerService.c_str(),
142b22ebbf3SWilliam A. Kennington III                  job->c_str(), result.c_str());
143b22ebbf3SWilliam A. Kennington III     jobMonitor = std::nullopt;
144b22ebbf3SWilliam A. Kennington III     job = std::nullopt;
145b22ebbf3SWilliam A. Kennington III     currentStatus =
146b22ebbf3SWilliam A. Kennington III         result == "done" ? ActionStatus::success : ActionStatus::failed;
147*4175b4caSWilliam A. Kennington III 
148*4175b4caSWilliam A. Kennington III     if (cb)
149*4175b4caSWilliam A. Kennington III     {
150*4175b4caSWilliam A. Kennington III         cb(*this);
151*4175b4caSWilliam A. Kennington III     }
152b22ebbf3SWilliam A. Kennington III }
153b22ebbf3SWilliam A. Kennington III 
154b22ebbf3SWilliam A. Kennington III std::unique_ptr<TriggerableActionInterface>
155b22ebbf3SWilliam A. Kennington III     SystemdNoFile::CreateSystemdNoFile(sdbusplus::bus::bus&& bus,
156b22ebbf3SWilliam A. Kennington III                                        const std::string& service,
157b22ebbf3SWilliam A. Kennington III                                        const std::string& mode)
158b22ebbf3SWilliam A. Kennington III {
159b22ebbf3SWilliam A. Kennington III     return std::make_unique<SystemdNoFile>(std::move(bus), service, mode);
160b22ebbf3SWilliam A. Kennington III }
161b22ebbf3SWilliam A. Kennington III 
162cf066aceSPatrick Venture std::unique_ptr<TriggerableActionInterface>
163cf066aceSPatrick Venture     SystemdWithStatusFile::CreateSystemdWithStatusFile(
164cf066aceSPatrick Venture         sdbusplus::bus::bus&& bus, const std::string& path,
165cf066aceSPatrick Venture         const std::string& service, const std::string& mode)
166cf066aceSPatrick Venture {
167cf066aceSPatrick Venture     return std::make_unique<SystemdWithStatusFile>(std::move(bus), path,
168cf066aceSPatrick Venture                                                    service, mode);
169cf066aceSPatrick Venture }
170cf066aceSPatrick Venture 
17193f3c550SWilliam A. Kennington III bool SystemdWithStatusFile::trigger()
17293f3c550SWilliam A. Kennington III {
17393f3c550SWilliam A. Kennington III     if (SystemdNoFile::status() != ActionStatus::running)
17493f3c550SWilliam A. Kennington III     {
17593f3c550SWilliam A. Kennington III         try
17693f3c550SWilliam A. Kennington III         {
17793f3c550SWilliam A. Kennington III             std::ofstream ofs;
17893f3c550SWilliam A. Kennington III             ofs.open(checkPath);
17993f3c550SWilliam A. Kennington III             ofs << "unknown";
18093f3c550SWilliam A. Kennington III         }
18193f3c550SWilliam A. Kennington III         catch (const std::exception& e)
18293f3c550SWilliam A. Kennington III         {
18393f3c550SWilliam A. Kennington III             return false;
18493f3c550SWilliam A. Kennington III         }
18593f3c550SWilliam A. Kennington III     }
18693f3c550SWilliam A. Kennington III     return SystemdNoFile::trigger();
18793f3c550SWilliam A. Kennington III }
18893f3c550SWilliam A. Kennington III 
189cf066aceSPatrick Venture ActionStatus SystemdWithStatusFile::status()
190cf066aceSPatrick Venture {
191b22ebbf3SWilliam A. Kennington III     // Assume a status based on job execution if there is no file
192b22ebbf3SWilliam A. Kennington III     ActionStatus result = SystemdNoFile::status() == ActionStatus::running
193b22ebbf3SWilliam A. Kennington III                               ? ActionStatus::running
194b22ebbf3SWilliam A. Kennington III                               : ActionStatus::failed;
195cf066aceSPatrick Venture 
196cf066aceSPatrick Venture     std::ifstream ifs;
197cf066aceSPatrick Venture     ifs.open(checkPath);
198cf066aceSPatrick Venture     if (ifs.good())
199cf066aceSPatrick Venture     {
200cf066aceSPatrick Venture         /*
201cf066aceSPatrick Venture          * Check for the contents of the file, accepting:
202cf066aceSPatrick Venture          * running, success, or failed.
203cf066aceSPatrick Venture          */
204cf066aceSPatrick Venture         std::string status;
205cf066aceSPatrick Venture         ifs >> status;
206cf066aceSPatrick Venture         if (status == "running")
207cf066aceSPatrick Venture         {
208cf066aceSPatrick Venture             result = ActionStatus::running;
209cf066aceSPatrick Venture         }
210cf066aceSPatrick Venture         else if (status == "success")
211cf066aceSPatrick Venture         {
212cf066aceSPatrick Venture             result = ActionStatus::success;
213cf066aceSPatrick Venture         }
214cf066aceSPatrick Venture         else if (status == "failed")
215cf066aceSPatrick Venture         {
216cf066aceSPatrick Venture             result = ActionStatus::failed;
217cf066aceSPatrick Venture         }
21893f3c550SWilliam A. Kennington III         else
21993f3c550SWilliam A. Kennington III         {
22093f3c550SWilliam A. Kennington III             result = ActionStatus::unknown;
22193f3c550SWilliam A. Kennington III         }
222cf066aceSPatrick Venture     }
223cf066aceSPatrick Venture 
224cf066aceSPatrick Venture     return result;
225cf066aceSPatrick Venture }
226cf066aceSPatrick Venture 
227cf066aceSPatrick Venture } // namespace ipmi_flash
228