blob: de09ba3310994416232c4a73ff889eabfd1a82c4 [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
17#include <iostream>
William A. Kennington IIId1331082018-02-27 18:47:05 -080018#include <experimental/optional>
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053019#include <phosphor-logging/log.hpp>
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053020#include <phosphor-logging/elog.hpp>
21#include <phosphor-logging/elog-errors.hpp>
William A. Kennington III93975262018-02-02 16:00:50 -080022#include <string>
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053023#include <xyz/openbmc_project/Common/error.hpp>
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053024#include "argument.hpp"
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +053025#include "watchdog.hpp"
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053026
William A. Kennington III1232a152018-02-02 15:57:34 -080027using phosphor::watchdog::ArgumentParser;
28using phosphor::watchdog::Watchdog;
William A. Kennington III93975262018-02-02 16:00:50 -080029using sdbusplus::xyz::openbmc_project::State::server::convertForMessage;
William A. Kennington III1232a152018-02-02 15:57:34 -080030
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053031static void exitWithError(const char* err, char** argv)
32{
William A. Kennington III1232a152018-02-02 15:57:34 -080033 ArgumentParser::usage(argv);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053034 std::cerr << "ERROR: " << err << "\n";
35 exit(EXIT_FAILURE);
36}
37
William A. Kennington III93975262018-02-02 16:00:50 -080038void printActionTargets(
39 const std::map<Watchdog::Action, std::string>& actionTargets)
40{
41 std::cerr << "Action Targets:\n";
42 for (const auto& actionTarget : actionTargets)
43 {
44 std::cerr << " " << convertForMessage(actionTarget.first) << " -> " <<
45 actionTarget.second << "\n";
46 }
47 std::cerr << std::flush;
48}
49
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053050int main(int argc, char** argv)
51{
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053052 using namespace phosphor::logging;
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +053053 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
54 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 III1232a152018-02-02 15:57:34 -080099 std::map<Watchdog::Action, Watchdog::TargetName> actionTargets;
100 if (!targetParam.empty()) {
101 auto target = targetParam.back();
102 actionTargets[Watchdog::Action::HardReset] = target;
103 actionTargets[Watchdog::Action::PowerOff] = target;
104 actionTargets[Watchdog::Action::PowerCycle] = target;
105 }
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530106
William A. Kennington III27df4b52018-02-02 16:02:05 -0800107 // Parse out the action_target arguments. We allow one target to map
108 // to an action. These targets can replace the target specified above.
109 for (const auto& actionTarget : (options)["action_target"])
110 {
111 size_t keyValueSplit = actionTarget.find("=");
112 if (keyValueSplit == std::string::npos)
113 {
114 exitWithError(
115 "Invalid action_target format, expect <action>=<target>.",
116 argv);
117 }
118
119 std::string key = actionTarget.substr(0, keyValueSplit);
120 std::string value = actionTarget.substr(keyValueSplit+1);
121
122 // Convert an action from a fully namespaced value
123 Watchdog::Action action;
124 try
125 {
126 action = Watchdog::convertActionFromString(key);
127 }
128 catch (const sdbusplus::exception::InvalidEnumString &)
129 {
130 exitWithError("Bad action specified.", argv);
131 }
132
133 actionTargets[action] = std::move(value);
134 }
William A. Kennington III93975262018-02-02 16:00:50 -0800135 printActionTargets(actionTargets);
136
William A. Kennington IIId1331082018-02-27 18:47:05 -0800137 // Parse out the fallback settings for the watchdog. Note that we require
138 // both of the fallback arguments to do anything here, but having a fallback
139 // is entirely optional.
140 auto fallbackActionParam = (options)["fallback_action"];
141 auto fallbackIntervalParam = (options)["fallback_interval"];
142 if (fallbackActionParam.empty() ^ fallbackIntervalParam.empty())
143 {
144 exitWithError("Only one of the fallback options was specified.", argv);
145 }
146 if (fallbackActionParam.size() > 1 || fallbackIntervalParam.size() > 1)
147 {
148 exitWithError("Multiple fallbacks specified.", argv);
149 }
150 std::experimental::optional<Watchdog::Fallback> fallback;
151 if (!fallbackActionParam.empty())
152 {
153 Watchdog::Action action;
154 try
155 {
156 action = Watchdog::convertActionFromString(
157 fallbackActionParam.back());
158 }
159 catch (const sdbusplus::exception::InvalidEnumString &)
160 {
161 exitWithError("Bad action specified.", argv);
162 }
163 uint64_t interval;
164 try
165 {
166 interval = std::stoull(fallbackIntervalParam.back());
167 }
168 catch (const std::logic_error &)
169 {
170 exitWithError("Failed to convert fallback interval to integer.", argv);
171 }
172 fallback = Watchdog::Fallback{
173 .action = action,
174 .interval = interval,
William A. Kennington III22352192018-02-27 18:51:44 -0800175 .always = false,
William A. Kennington IIId1331082018-02-27 18:47:05 -0800176 };
177 }
178
William A. Kennington III22352192018-02-27 18:51:44 -0800179 auto fallbackAlwaysParam = (options)["fallback_always"];
180 if (!fallbackAlwaysParam.empty())
181 {
182 if (!fallback)
183 {
184 exitWithError("Specified the fallback should always be enabled but "
185 "no fallback provided.", argv);
186 }
187 fallback->always = true;
188 }
189
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530190 sd_event* event = nullptr;
191 auto r = sd_event_default(&event);
192 if (r < 0)
193 {
194 log<level::ERR>("Error creating a default sd_event handler");
195 return r;
196 }
197 phosphor::watchdog::EventPtr eventP{event};
198 event = nullptr;
199
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530200 // Get a handle to system dbus.
201 auto bus = sdbusplus::bus::new_default();
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530202
Vishwanatha Subbannad7a3f132017-05-29 19:39:08 +0530203 // Add systemd object manager.
204 sdbusplus::server::manager::manager(bus, path.c_str());
205
206 // Attach the bus to sd_event to service user requests
207 bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL);
208
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530209 try
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530210 {
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530211 // Create a watchdog object
William A. Kennington IIId1331082018-02-27 18:47:05 -0800212 Watchdog watchdog(bus, path.c_str(), eventP, std::move(actionTargets),
213 std::move(fallback));
214
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530215 // Claim the bus
216 bus.request_name(service.c_str());
217
William A. Kennington III825f4982018-02-27 19:10:56 -0800218 // Loop until our timer expires and we don't want to continue
219 while (continueAfterTimeout || !watchdog.timerExpired())
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530220 {
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530221 // -1 denotes wait for ever
222 r = sd_event_run(eventP.get(), (uint64_t)-1);
223 if (r < 0)
224 {
225 log<level::ERR>("Error waiting for events");
226 elog<InternalFailure>();
227 }
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530228 }
229 }
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530230 catch(InternalFailure& e)
231 {
232 phosphor::logging::commit<InternalFailure>();
233
234 // Need a coredump in the error cases.
235 std::terminate();
236 }
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530237 return 0;
238}