blob: b98b1086b03fa2cd93065953f49d07ed50ea99da [file] [log] [blame]
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +05301/**
2 * Copyright © 2017 IBM Corporation
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
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053017#include "argument.hpp"
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053018#include "watchdog.hpp"
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053019
Patrick Venture8f6c5152018-09-11 17:45:33 -070020#include <iostream>
William A. Kennington III73c2cfb2018-09-12 18:01:37 -070021#include <optional>
Patrick Venture8f6c5152018-09-11 17:45:33 -070022#include <phosphor-logging/elog-errors.hpp>
23#include <phosphor-logging/elog.hpp>
24#include <phosphor-logging/log.hpp>
25#include <string>
26#include <xyz/openbmc_project/Common/error.hpp>
27
William A. Kennington III1232a152018-02-02 15:57:34 -080028using phosphor::watchdog::ArgumentParser;
29using phosphor::watchdog::Watchdog;
William A. Kennington III93975262018-02-02 16:00:50 -080030using sdbusplus::xyz::openbmc_project::State::server::convertForMessage;
William A. Kennington III1232a152018-02-02 15:57:34 -080031
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053032static void exitWithError(const char* err, char** argv)
33{
William A. Kennington III1232a152018-02-02 15:57:34 -080034 ArgumentParser::usage(argv);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053035 std::cerr << "ERROR: " << err << "\n";
36 exit(EXIT_FAILURE);
37}
38
William A. Kennington III3bb2f402018-09-13 00:35:47 -070039void printActionTargetMap(const Watchdog::ActionTargetMap& actionTargetMap)
William A. Kennington III93975262018-02-02 16:00:50 -080040{
41 std::cerr << "Action Targets:\n";
William A. Kennington III3bb2f402018-09-13 00:35:47 -070042 for (const auto& [action, target] : actionTargetMap)
William A. Kennington III93975262018-02-02 16:00:50 -080043 {
William A. Kennington III3bb2f402018-09-13 00:35:47 -070044 std::cerr << " " << convertForMessage(action) << " -> " << target
45 << "\n";
William A. Kennington III93975262018-02-02 16:00:50 -080046 }
47 std::cerr << std::flush;
48}
49
William A. Kennington III3bb2f402018-09-13 00:35:47 -070050int main(int argc, char* argv[])
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053051{
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053052 using namespace phosphor::logging;
Patrick Venture8f6c5152018-09-11 17:45:33 -070053 using InternalFailure =
54 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053055 // Read arguments.
William A. Kennington III1232a152018-02-02 15:57:34 -080056 auto options = ArgumentParser(argc, argv);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053057
Patrick Venture09eebe32017-08-11 15:23:17 -070058 // Parse out continue argument.
59 auto continueParam = (options)["continue"];
60 // Default it to exit on watchdog timeout
61 auto continueAfterTimeout = false;
William A. Kennington III5d307182018-01-23 22:00:55 -080062 if (!continueParam.empty())
Patrick Venture09eebe32017-08-11 15:23:17 -070063 {
64 continueAfterTimeout = true;
65 }
66
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053067 // Parse out path argument.
William A. Kennington III5d307182018-01-23 22:00:55 -080068 auto pathParam = (options)["path"];
69 if (pathParam.empty())
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053070 {
71 exitWithError("Path not specified.", argv);
72 }
William A. Kennington III5d307182018-01-23 22:00:55 -080073 if (pathParam.size() > 1)
74 {
75 exitWithError("Multiple paths specified.", argv);
76 }
77 auto path = pathParam.back();
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053078
79 // Parse out service name argument
William A. Kennington III5d307182018-01-23 22:00:55 -080080 auto serviceParam = (options)["service"];
81 if (serviceParam.empty())
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053082 {
83 exitWithError("Service not specified.", argv);
84 }
William A. Kennington III5d307182018-01-23 22:00:55 -080085 if (serviceParam.size() > 1)
86 {
87 exitWithError("Multiple services specified.", argv);
88 }
89 auto service = serviceParam.back();
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053090
91 // Parse out target argument. It is fine if the caller does not
92 // pass this if they are not interested in calling into any target
93 // on meeting a condition.
William A. Kennington III5d307182018-01-23 22:00:55 -080094 auto targetParam = (options)["target"];
95 if (targetParam.size() > 1)
96 {
97 exitWithError("Multiple targets specified.", argv);
98 }
William A. Kennington III3bb2f402018-09-13 00:35:47 -070099 Watchdog::ActionTargetMap actionTargetMap;
Patrick Venture8f6c5152018-09-11 17:45:33 -0700100 if (!targetParam.empty())
101 {
William A. Kennington III1232a152018-02-02 15:57:34 -0800102 auto target = targetParam.back();
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700103 actionTargetMap[Watchdog::Action::HardReset] = target;
104 actionTargetMap[Watchdog::Action::PowerOff] = target;
105 actionTargetMap[Watchdog::Action::PowerCycle] = target;
William A. Kennington III1232a152018-02-02 15:57:34 -0800106 }
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530107
William A. Kennington III27df4b52018-02-02 16:02:05 -0800108 // Parse out the action_target arguments. We allow one target to map
109 // to an action. These targets can replace the target specified above.
110 for (const auto& actionTarget : (options)["action_target"])
111 {
112 size_t keyValueSplit = actionTarget.find("=");
113 if (keyValueSplit == std::string::npos)
114 {
115 exitWithError(
Patrick Venture8f6c5152018-09-11 17:45:33 -0700116 "Invalid action_target format, expect <action>=<target>.",
117 argv);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800118 }
119
120 std::string key = actionTarget.substr(0, keyValueSplit);
Patrick Venture8f6c5152018-09-11 17:45:33 -0700121 std::string value = actionTarget.substr(keyValueSplit + 1);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800122
123 // Convert an action from a fully namespaced value
124 Watchdog::Action action;
125 try
126 {
127 action = Watchdog::convertActionFromString(key);
128 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700129 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington III27df4b52018-02-02 16:02:05 -0800130 {
131 exitWithError("Bad action specified.", argv);
132 }
133
William A. Kennington IIIc2c26ce2018-09-13 18:35:56 -0700134 // Detect duplicate action target arguments
135 if (actionTargetMap.find(action) != actionTargetMap.end())
136 {
137 exitWithError("Duplicate action specified", argv);
138 }
139
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700140 actionTargetMap[action] = std::move(value);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800141 }
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700142 printActionTargetMap(actionTargetMap);
William A. Kennington III93975262018-02-02 16:00:50 -0800143
William A. Kennington IIId1331082018-02-27 18:47:05 -0800144 // Parse out the fallback settings for the watchdog. Note that we require
145 // both of the fallback arguments to do anything here, but having a fallback
146 // is entirely optional.
147 auto fallbackActionParam = (options)["fallback_action"];
148 auto fallbackIntervalParam = (options)["fallback_interval"];
149 if (fallbackActionParam.empty() ^ fallbackIntervalParam.empty())
150 {
151 exitWithError("Only one of the fallback options was specified.", argv);
152 }
153 if (fallbackActionParam.size() > 1 || fallbackIntervalParam.size() > 1)
154 {
155 exitWithError("Multiple fallbacks specified.", argv);
156 }
William A. Kennington III73c2cfb2018-09-12 18:01:37 -0700157 std::optional<Watchdog::Fallback> fallback;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800158 if (!fallbackActionParam.empty())
159 {
160 Watchdog::Action action;
161 try
162 {
Patrick Venture8f6c5152018-09-11 17:45:33 -0700163 action =
164 Watchdog::convertActionFromString(fallbackActionParam.back());
William A. Kennington IIId1331082018-02-27 18:47:05 -0800165 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700166 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800167 {
168 exitWithError("Bad action specified.", argv);
169 }
170 uint64_t interval;
171 try
172 {
173 interval = std::stoull(fallbackIntervalParam.back());
174 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700175 catch (const std::logic_error&)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800176 {
Patrick Venture8f6c5152018-09-11 17:45:33 -0700177 exitWithError("Failed to convert fallback interval to integer.",
178 argv);
William A. Kennington IIId1331082018-02-27 18:47:05 -0800179 }
180 fallback = Watchdog::Fallback{
181 .action = action,
182 .interval = interval,
William A. Kennington III22352192018-02-27 18:51:44 -0800183 .always = false,
William A. Kennington IIId1331082018-02-27 18:47:05 -0800184 };
185 }
186
William A. Kennington III22352192018-02-27 18:51:44 -0800187 auto fallbackAlwaysParam = (options)["fallback_always"];
188 if (!fallbackAlwaysParam.empty())
189 {
190 if (!fallback)
191 {
192 exitWithError("Specified the fallback should always be enabled but "
Patrick Venture8f6c5152018-09-11 17:45:33 -0700193 "no fallback provided.",
194 argv);
William A. Kennington III22352192018-02-27 18:51:44 -0800195 }
196 fallback->always = true;
197 }
198
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530199 try
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530200 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700201 // Get a default event loop
202 auto event = sdeventplus::Event::get_default();
203
204 // Get a handle to system dbus.
205 auto bus = sdbusplus::bus::new_default();
206
207 // Add systemd object manager.
208 sdbusplus::server::manager::manager(bus, path.c_str());
209
210 // Attach the bus to sd_event to service user requests
211 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
212
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530213 // Create a watchdog object
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700214 Watchdog watchdog(bus, path.c_str(), event, std::move(actionTargetMap),
Patrick Venture8f6c5152018-09-11 17:45:33 -0700215 std::move(fallback));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800216
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530217 // Claim the bus
218 bus.request_name(service.c_str());
219
William A. Kennington III825f4982018-02-27 19:10:56 -0800220 // Loop until our timer expires and we don't want to continue
221 while (continueAfterTimeout || !watchdog.timerExpired())
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530222 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700223 // Run and never timeout
224 event.run(std::nullopt);
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530225 }
226 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700227 catch (InternalFailure& e)
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530228 {
229 phosphor::logging::commit<InternalFailure>();
230
231 // Need a coredump in the error cases.
232 std::terminate();
233 }
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530234 return 0;
235}