blob: 06b22ec7f253429cd171fd07db9190e620a620ee [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 Subbannad7a3f132017-05-29 19:39:08 +053017#include "watchdog.hpp"
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053018
William A. Kennington III1eb97d92018-09-13 00:36:12 -070019#include <CLI/CLI.hpp>
William A. Kennington III26eef262019-04-04 15:30:30 -070020#include <functional>
Patrick Venture8f6c5152018-09-11 17:45:33 -070021#include <iostream>
William A. Kennington III73c2cfb2018-09-12 18:01:37 -070022#include <optional>
Patrick Venture8f6c5152018-09-11 17:45:33 -070023#include <phosphor-logging/elog-errors.hpp>
24#include <phosphor-logging/elog.hpp>
25#include <phosphor-logging/log.hpp>
William A. Kennington III8d8bc462019-01-16 14:59:07 -080026#include <sdbusplus/bus.hpp>
27#include <sdbusplus/exception.hpp>
28#include <sdbusplus/server/manager.hpp>
29#include <sdeventplus/event.hpp>
Patrick Venture8f6c5152018-09-11 17:45:33 -070030#include <string>
31#include <xyz/openbmc_project/Common/error.hpp>
32
William A. Kennington III1232a152018-02-02 15:57:34 -080033using phosphor::watchdog::Watchdog;
William A. Kennington III93975262018-02-02 16:00:50 -080034using sdbusplus::xyz::openbmc_project::State::server::convertForMessage;
William A. Kennington III1232a152018-02-02 15:57:34 -080035
William A. Kennington III3bb2f402018-09-13 00:35:47 -070036void printActionTargetMap(const Watchdog::ActionTargetMap& actionTargetMap)
William A. Kennington III93975262018-02-02 16:00:50 -080037{
38 std::cerr << "Action Targets:\n";
William A. Kennington III3bb2f402018-09-13 00:35:47 -070039 for (const auto& [action, target] : actionTargetMap)
William A. Kennington III93975262018-02-02 16:00:50 -080040 {
William A. Kennington III3bb2f402018-09-13 00:35:47 -070041 std::cerr << " " << convertForMessage(action) << " -> " << target
42 << "\n";
William A. Kennington III93975262018-02-02 16:00:50 -080043 }
44 std::cerr << std::flush;
45}
46
William A. Kennington III1eb97d92018-09-13 00:36:12 -070047void printFallback(const Watchdog::Fallback& fallback)
48{
49 std::cerr << "Fallback Options:\n";
50 std::cerr << " Action: " << convertForMessage(fallback.action) << "\n";
51 std::cerr << " Interval(ms): " << std::dec << fallback.interval << "\n";
52 std::cerr << " Always re-execute: " << std::boolalpha << fallback.always
53 << "\n";
54 std::cerr << std::flush;
55}
56
William A. Kennington III3bb2f402018-09-13 00:35:47 -070057int main(int argc, char* argv[])
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053058{
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053059 using namespace phosphor::logging;
Patrick Venture8f6c5152018-09-11 17:45:33 -070060 using InternalFailure =
61 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053062
William A. Kennington III1eb97d92018-09-13 00:36:12 -070063 CLI::App app{"Canonical openbmc host watchdog daemon"};
Patrick Venture09eebe32017-08-11 15:23:17 -070064
William A. Kennington III1eb97d92018-09-13 00:36:12 -070065 // Service related options
66 const std::string serviceGroup = "Service Options";
67 std::string path;
68 app.add_option("-p,--path", path,
69 "DBus Object Path. "
70 "Ex: /xyz/openbmc_project/state/watchdog/host0")
71 ->required()
72 ->group(serviceGroup);
73 std::string service;
74 app.add_option("-s,--service", service,
75 "DBus Service Name. "
76 "Ex: xyz.openbmc_project.State.Watchdog.Host")
77 ->required()
78 ->group(serviceGroup);
79 bool continueAfterTimeout;
80 app.add_flag("-c,--continue", continueAfterTimeout,
81 "Continue daemon after watchdog timeout")
82 ->group(serviceGroup);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053083
William A. Kennington III1eb97d92018-09-13 00:36:12 -070084 // Target related options
85 const std::string targetGroup = "Target Options";
86 std::optional<std::string> target;
87 app.add_option("-t,--target", target,
88 "Systemd unit to be called on "
89 "timeout for all actions but NONE. "
90 "Deprecated, use --action_target instead.")
91 ->group(targetGroup);
92 std::vector<std::string> actionTargets;
93 app.add_option("-a,--action_target", actionTargets,
94 "Map of action to "
95 "systemd unit to be called on timeout if that action is "
96 "set for ExpireAction when the timer expires.")
97 ->group(targetGroup);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053098
William A. Kennington III1eb97d92018-09-13 00:36:12 -070099 // Fallback related options
100 const std::string fallbackGroup = "Fallback Options";
101 std::optional<std::string> fallbackAction;
102 auto fallbackActionOpt =
103 app.add_option("-f,--fallback_action", fallbackAction,
104 "Enables the "
105 "watchdog even when disabled via the dbus interface. "
106 "Perform this action when the fallback expires.")
107 ->group(fallbackGroup);
108 std::optional<unsigned> fallbackIntervalMs;
109 auto fallbackIntervalOpt =
110 app.add_option("-i,--fallback_interval", fallbackIntervalMs,
111 "Enables the "
112 "watchdog even when disabled via the dbus interface. "
113 "Waits for this interval before performing the fallback "
114 "action.")
115 ->group(fallbackGroup);
116 fallbackIntervalOpt->needs(fallbackActionOpt);
117 fallbackActionOpt->needs(fallbackIntervalOpt);
118 bool fallbackAlways;
119 app.add_flag("-e,--fallback_always", fallbackAlways,
120 "Enables the "
121 "watchdog even when disabled by the dbus interface. "
122 "This option is only valid with a fallback specified")
123 ->group(fallbackGroup)
124 ->needs(fallbackActionOpt)
125 ->needs(fallbackIntervalOpt);
126
William A. Kennington III26eef262019-04-04 15:30:30 -0700127 // Should we watch for postcodes
128 bool watchPostcodes;
129 app.add_flag("-w,--watch_postcodes", watchPostcodes,
130 "Should we reset the time remaining any time a postcode "
131 "is signaled.");
132
Ofer Yehiellic35135d2019-06-14 11:30:25 -0700133 uint64_t minInterval = phosphor::watchdog::DEFAULT_MIN_INTERVAL_MS;
Kun Yi08683752019-12-05 10:34:45 -0800134 app.add_option("-m,--min_interval", minInterval,
135 "Set minimum interval for watchdog in milliseconds");
Ofer Yehiellic35135d2019-06-14 11:30:25 -0700136
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700137 CLI11_PARSE(app, argc, argv);
138
139 // Put together a list of actions and associated systemd targets
140 // The new --action_target options take precedence over the legacy
141 // --target
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700142 Watchdog::ActionTargetMap actionTargetMap;
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700143 if (target)
Patrick Venture8f6c5152018-09-11 17:45:33 -0700144 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700145 actionTargetMap[Watchdog::Action::HardReset] = *target;
146 actionTargetMap[Watchdog::Action::PowerOff] = *target;
147 actionTargetMap[Watchdog::Action::PowerCycle] = *target;
William A. Kennington III1232a152018-02-02 15:57:34 -0800148 }
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700149 for (const auto& actionTarget : actionTargets)
William A. Kennington III27df4b52018-02-02 16:02:05 -0800150 {
151 size_t keyValueSplit = actionTarget.find("=");
152 if (keyValueSplit == std::string::npos)
153 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700154 std::cerr << "Invalid action_target format, "
155 "expect <action>=<target>."
156 << std::endl;
157 return 1;
William A. Kennington III27df4b52018-02-02 16:02:05 -0800158 }
159
160 std::string key = actionTarget.substr(0, keyValueSplit);
Patrick Venture8f6c5152018-09-11 17:45:33 -0700161 std::string value = actionTarget.substr(keyValueSplit + 1);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800162
163 // Convert an action from a fully namespaced value
164 Watchdog::Action action;
165 try
166 {
167 action = Watchdog::convertActionFromString(key);
168 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700169 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington III27df4b52018-02-02 16:02:05 -0800170 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700171 std::cerr << "Bad action specified: " << key << std::endl;
172 return 1;
William A. Kennington III27df4b52018-02-02 16:02:05 -0800173 }
174
William A. Kennington IIIc2c26ce2018-09-13 18:35:56 -0700175 // Detect duplicate action target arguments
176 if (actionTargetMap.find(action) != actionTargetMap.end())
177 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700178 std::cerr << "Got duplicate action: " << key << std::endl;
179 return 1;
William A. Kennington IIIc2c26ce2018-09-13 18:35:56 -0700180 }
181
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700182 actionTargetMap[action] = std::move(value);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800183 }
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700184 printActionTargetMap(actionTargetMap);
William A. Kennington III93975262018-02-02 16:00:50 -0800185
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700186 // Build the fallback option used for the Watchdog
187 std::optional<Watchdog::Fallback> maybeFallback;
188 if (fallbackAction)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800189 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700190 Watchdog::Fallback fallback;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800191 try
192 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700193 fallback.action =
194 Watchdog::convertActionFromString(*fallbackAction);
William A. Kennington IIId1331082018-02-27 18:47:05 -0800195 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700196 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800197 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700198 std::cerr << "Bad fallback action specified: " << *fallbackAction
199 << std::endl;
200 return 1;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800201 }
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700202 fallback.interval = *fallbackIntervalMs;
203 fallback.always = fallbackAlways;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800204
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700205 printFallback(fallback);
206 maybeFallback = std::move(fallback);
William A. Kennington III22352192018-02-27 18:51:44 -0800207 }
208
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530209 try
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530210 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700211 // Get a default event loop
212 auto event = sdeventplus::Event::get_default();
213
214 // Get a handle to system dbus.
215 auto bus = sdbusplus::bus::new_default();
216
217 // Add systemd object manager.
218 sdbusplus::server::manager::manager(bus, path.c_str());
219
220 // Attach the bus to sd_event to service user requests
221 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
222
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530223 // Create a watchdog object
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700224 Watchdog watchdog(bus, path.c_str(), event, std::move(actionTargetMap),
Ofer Yehiellic35135d2019-06-14 11:30:25 -0700225 std::move(maybeFallback), minInterval);
William A. Kennington IIId1331082018-02-27 18:47:05 -0800226
William A. Kennington III26eef262019-04-04 15:30:30 -0700227 std::optional<sdbusplus::bus::match::match> watchPostcodeMatch;
228 if (watchPostcodes)
229 {
230 watchPostcodeMatch.emplace(
231 bus,
232 sdbusplus::bus::match::rules::propertiesChanged(
233 "/xyz/openbmc_project/state/boot/raw",
234 "xyz.openbmc_project.State.Boot.Raw"),
235 std::bind(&Watchdog::resetTimeRemaining, std::ref(watchdog),
236 false));
237 }
238
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530239 // Claim the bus
240 bus.request_name(service.c_str());
241
William A. Kennington III825f4982018-02-27 19:10:56 -0800242 // Loop until our timer expires and we don't want to continue
243 while (continueAfterTimeout || !watchdog.timerExpired())
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530244 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700245 // Run and never timeout
246 event.run(std::nullopt);
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530247 }
248 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700249 catch (InternalFailure& e)
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530250 {
251 phosphor::logging::commit<InternalFailure>();
252
253 // Need a coredump in the error cases.
254 std::terminate();
255 }
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530256 return 0;
257}