| /* |
| * Copyright 2019 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "general_systemd.hpp" |
| |
| #include "status.hpp" |
| |
| #include <fstream> |
| #include <memory> |
| #include <sdbusplus/bus.hpp> |
| #include <string> |
| #include <vector> |
| |
| namespace ipmi_flash |
| { |
| |
| static constexpr auto systemdService = "org.freedesktop.systemd1"; |
| static constexpr auto systemdRoot = "/org/freedesktop/systemd1"; |
| static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager"; |
| |
| bool SystemdNoFile::trigger() |
| { |
| if (job) |
| { |
| std::fprintf(stderr, "Job alreading running %s: %s\n", |
| triggerService.c_str(), job->c_str()); |
| return false; |
| } |
| |
| try |
| { |
| jobMonitor.emplace( |
| bus, |
| "type='signal'," |
| "sender='org.freedesktop.systemd1'," |
| "path='/org/freedesktop/systemd1'," |
| "interface='org.freedesktop.systemd1.Manager'," |
| "member='JobRemoved',", |
| [&](sdbusplus::message::message& m) { this->match(m); }); |
| |
| auto method = bus.new_method_call(systemdService, systemdRoot, |
| systemdInterface, "StartUnit"); |
| method.append(triggerService); |
| method.append(mode); |
| |
| sdbusplus::message::object_path obj_path; |
| bus.call(method).read(obj_path); |
| job = std::move(obj_path); |
| std::fprintf(stderr, "Triggered %s mode %s: %s\n", |
| triggerService.c_str(), mode.c_str(), job->c_str()); |
| currentStatus = ActionStatus::running; |
| return true; |
| } |
| catch (const std::exception& e) |
| { |
| job = std::nullopt; |
| jobMonitor = std::nullopt; |
| currentStatus = ActionStatus::failed; |
| std::fprintf(stderr, "Failed to trigger %s mode %s: %s\n", |
| triggerService.c_str(), mode.c_str(), e.what()); |
| return false; |
| } |
| } |
| |
| void SystemdNoFile::abort() |
| { |
| if (!job) |
| { |
| std::fprintf(stderr, "No running job %s\n", triggerService.c_str()); |
| return; |
| } |
| |
| // Cancel the job |
| auto cancel_req = bus.new_method_call(systemdService, job->c_str(), |
| systemdInterface, "Cancel"); |
| try |
| { |
| bus.call_noreply(cancel_req); |
| std::fprintf(stderr, "Canceled %s: %s\n", triggerService.c_str(), |
| job->c_str()); |
| } |
| catch (const sdbusplus::exception::SdBusError& ex) |
| { |
| std::fprintf(stderr, "Failed to cancel job %s %s: %s\n", |
| triggerService.c_str(), job->c_str(), ex.what()); |
| } |
| } |
| |
| ActionStatus SystemdNoFile::status() |
| { |
| return currentStatus; |
| } |
| |
| const std::string& SystemdNoFile::getMode() const |
| { |
| return mode; |
| } |
| |
| void SystemdNoFile::match(sdbusplus::message::message& m) |
| { |
| if (!job) |
| { |
| std::fprintf(stderr, "No running job %s\n", triggerService.c_str()); |
| return; |
| } |
| |
| uint32_t job_id; |
| sdbusplus::message::object_path job_path; |
| std::string unit; |
| std::string result; |
| try |
| { |
| m.read(job_id, job_path, unit, result); |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| std::fprintf(stderr, "Bad JobRemoved signal %s: %s\n", |
| triggerService.c_str(), e.what()); |
| return; |
| } |
| |
| if (*job != job_path.str) |
| { |
| return; |
| } |
| |
| std::fprintf(stderr, "Job Finished %s %s: %s\n", triggerService.c_str(), |
| job->c_str(), result.c_str()); |
| jobMonitor = std::nullopt; |
| job = std::nullopt; |
| currentStatus = |
| result == "done" ? ActionStatus::success : ActionStatus::failed; |
| } |
| |
| std::unique_ptr<TriggerableActionInterface> |
| SystemdNoFile::CreateSystemdNoFile(sdbusplus::bus::bus&& bus, |
| const std::string& service, |
| const std::string& mode) |
| { |
| return std::make_unique<SystemdNoFile>(std::move(bus), service, mode); |
| } |
| |
| std::unique_ptr<TriggerableActionInterface> |
| SystemdWithStatusFile::CreateSystemdWithStatusFile( |
| sdbusplus::bus::bus&& bus, const std::string& path, |
| const std::string& service, const std::string& mode) |
| { |
| return std::make_unique<SystemdWithStatusFile>(std::move(bus), path, |
| service, mode); |
| } |
| |
| ActionStatus SystemdWithStatusFile::status() |
| { |
| // Assume a status based on job execution if there is no file |
| ActionStatus result = SystemdNoFile::status() == ActionStatus::running |
| ? ActionStatus::running |
| : ActionStatus::failed; |
| |
| std::ifstream ifs; |
| ifs.open(checkPath); |
| if (ifs.good()) |
| { |
| /* |
| * Check for the contents of the file, accepting: |
| * running, success, or failed. |
| */ |
| std::string status; |
| ifs >> status; |
| if (status == "running") |
| { |
| result = ActionStatus::running; |
| } |
| else if (status == "success") |
| { |
| result = ActionStatus::success; |
| } |
| else if (status == "failed") |
| { |
| result = ActionStatus::failed; |
| } |
| } |
| |
| return result; |
| } |
| |
| } // namespace ipmi_flash |