blob: bd65335b2879ff011d3a364c6deda18faaf5cc31 [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>
William A. Kennington III658527b2021-12-19 20:43:22 -080030#include <sdeventplus/source/signal.hpp>
William A. Kennington IIId1b1e792022-11-21 18:29:11 -080031#include <sdeventplus/utility/sdbus.hpp>
William A. Kennington III658527b2021-12-19 20:43:22 -080032#include <stdplus/signal.hpp>
Patrick Venture8f6c5152018-09-11 17:45:33 -070033#include <string>
34#include <xyz/openbmc_project/Common/error.hpp>
35
William A. Kennington III1232a152018-02-02 15:57:34 -080036using phosphor::watchdog::Watchdog;
William A. Kennington III93975262018-02-02 16:00:50 -080037using sdbusplus::xyz::openbmc_project::State::server::convertForMessage;
William A. Kennington III1232a152018-02-02 15:57:34 -080038
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 III1eb97d92018-09-13 00:36:12 -070050void printFallback(const Watchdog::Fallback& fallback)
51{
52 std::cerr << "Fallback Options:\n";
53 std::cerr << " Action: " << convertForMessage(fallback.action) << "\n";
54 std::cerr << " Interval(ms): " << std::dec << fallback.interval << "\n";
55 std::cerr << " Always re-execute: " << std::boolalpha << fallback.always
56 << "\n";
57 std::cerr << std::flush;
58}
59
William A. Kennington III3bb2f402018-09-13 00:35:47 -070060int main(int argc, char* argv[])
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053061{
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053062 using namespace phosphor::logging;
Patrick Venture8f6c5152018-09-11 17:45:33 -070063 using InternalFailure =
64 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053065
William A. Kennington III1eb97d92018-09-13 00:36:12 -070066 CLI::App app{"Canonical openbmc host watchdog daemon"};
Patrick Venture09eebe32017-08-11 15:23:17 -070067
William A. Kennington III1eb97d92018-09-13 00:36:12 -070068 // Service related options
69 const std::string serviceGroup = "Service Options";
70 std::string path;
71 app.add_option("-p,--path", path,
72 "DBus Object Path. "
73 "Ex: /xyz/openbmc_project/state/watchdog/host0")
74 ->required()
75 ->group(serviceGroup);
76 std::string service;
77 app.add_option("-s,--service", service,
78 "DBus Service Name. "
79 "Ex: xyz.openbmc_project.State.Watchdog.Host")
80 ->required()
81 ->group(serviceGroup);
Jae Hyun Yoo61bc6cd2021-07-01 14:48:41 -070082 bool continueAfterTimeout{false};
William A. Kennington III1eb97d92018-09-13 00:36:12 -070083 app.add_flag("-c,--continue", continueAfterTimeout,
84 "Continue daemon after watchdog timeout")
85 ->group(serviceGroup);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053086
William A. Kennington III1eb97d92018-09-13 00:36:12 -070087 // Target related options
88 const std::string targetGroup = "Target Options";
89 std::optional<std::string> target;
90 app.add_option("-t,--target", target,
91 "Systemd unit to be called on "
92 "timeout for all actions but NONE. "
93 "Deprecated, use --action_target instead.")
94 ->group(targetGroup);
95 std::vector<std::string> actionTargets;
96 app.add_option("-a,--action_target", actionTargets,
97 "Map of action to "
98 "systemd unit to be called on timeout if that action is "
99 "set for ExpireAction when the timer expires.")
100 ->group(targetGroup);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530101
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700102 // Fallback related options
103 const std::string fallbackGroup = "Fallback Options";
104 std::optional<std::string> fallbackAction;
105 auto fallbackActionOpt =
106 app.add_option("-f,--fallback_action", fallbackAction,
107 "Enables the "
108 "watchdog even when disabled via the dbus interface. "
109 "Perform this action when the fallback expires.")
110 ->group(fallbackGroup);
111 std::optional<unsigned> fallbackIntervalMs;
112 auto fallbackIntervalOpt =
113 app.add_option("-i,--fallback_interval", fallbackIntervalMs,
114 "Enables the "
115 "watchdog even when disabled via the dbus interface. "
116 "Waits for this interval before performing the fallback "
117 "action.")
118 ->group(fallbackGroup);
119 fallbackIntervalOpt->needs(fallbackActionOpt);
120 fallbackActionOpt->needs(fallbackIntervalOpt);
Jae Hyun Yoo61bc6cd2021-07-01 14:48:41 -0700121 bool fallbackAlways{false};
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700122 app.add_flag("-e,--fallback_always", fallbackAlways,
123 "Enables the "
124 "watchdog even when disabled by the dbus interface. "
125 "This option is only valid with a fallback specified")
126 ->group(fallbackGroup)
127 ->needs(fallbackActionOpt)
128 ->needs(fallbackIntervalOpt);
129
William A. Kennington III26eef262019-04-04 15:30:30 -0700130 // Should we watch for postcodes
Jae Hyun Yoo61bc6cd2021-07-01 14:48:41 -0700131 bool watchPostcodes{false};
William A. Kennington III26eef262019-04-04 15:30:30 -0700132 app.add_flag("-w,--watch_postcodes", watchPostcodes,
133 "Should we reset the time remaining any time a postcode "
134 "is signaled.");
135
Andrew Geisslerafc369a2021-06-03 14:17:16 -0500136 // Interval related options
Ofer Yehiellic35135d2019-06-14 11:30:25 -0700137 uint64_t minInterval = phosphor::watchdog::DEFAULT_MIN_INTERVAL_MS;
Kun Yi08683752019-12-05 10:34:45 -0800138 app.add_option("-m,--min_interval", minInterval,
139 "Set minimum interval for watchdog in milliseconds");
Ofer Yehiellic35135d2019-06-14 11:30:25 -0700140
Andrew Geisslerafc369a2021-06-03 14:17:16 -0500141 // 0 to indicate to use default from PDI if not passed in
142 uint64_t defaultInterval = 0;
143 app.add_option("-d,--default_interval", defaultInterval,
144 "Set default interval for watchdog in milliseconds");
145
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700146 CLI11_PARSE(app, argc, argv);
147
148 // Put together a list of actions and associated systemd targets
149 // The new --action_target options take precedence over the legacy
150 // --target
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700151 Watchdog::ActionTargetMap actionTargetMap;
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700152 if (target)
Patrick Venture8f6c5152018-09-11 17:45:33 -0700153 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700154 actionTargetMap[Watchdog::Action::HardReset] = *target;
155 actionTargetMap[Watchdog::Action::PowerOff] = *target;
156 actionTargetMap[Watchdog::Action::PowerCycle] = *target;
William A. Kennington III1232a152018-02-02 15:57:34 -0800157 }
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700158 for (const auto& actionTarget : actionTargets)
William A. Kennington III27df4b52018-02-02 16:02:05 -0800159 {
160 size_t keyValueSplit = actionTarget.find("=");
161 if (keyValueSplit == std::string::npos)
162 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700163 std::cerr << "Invalid action_target format, "
164 "expect <action>=<target>."
165 << std::endl;
166 return 1;
William A. Kennington III27df4b52018-02-02 16:02:05 -0800167 }
168
169 std::string key = actionTarget.substr(0, keyValueSplit);
Patrick Venture8f6c5152018-09-11 17:45:33 -0700170 std::string value = actionTarget.substr(keyValueSplit + 1);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800171
172 // Convert an action from a fully namespaced value
173 Watchdog::Action action;
174 try
175 {
176 action = Watchdog::convertActionFromString(key);
177 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700178 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington III27df4b52018-02-02 16:02:05 -0800179 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700180 std::cerr << "Bad action specified: " << key << std::endl;
181 return 1;
William A. Kennington III27df4b52018-02-02 16:02:05 -0800182 }
183
William A. Kennington IIIc2c26ce2018-09-13 18:35:56 -0700184 // Detect duplicate action target arguments
185 if (actionTargetMap.find(action) != actionTargetMap.end())
186 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700187 std::cerr << "Got duplicate action: " << key << std::endl;
188 return 1;
William A. Kennington IIIc2c26ce2018-09-13 18:35:56 -0700189 }
190
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700191 actionTargetMap[action] = std::move(value);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800192 }
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700193 printActionTargetMap(actionTargetMap);
William A. Kennington III93975262018-02-02 16:00:50 -0800194
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700195 // Build the fallback option used for the Watchdog
196 std::optional<Watchdog::Fallback> maybeFallback;
197 if (fallbackAction)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800198 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700199 Watchdog::Fallback fallback;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800200 try
201 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700202 fallback.action =
203 Watchdog::convertActionFromString(*fallbackAction);
William A. Kennington IIId1331082018-02-27 18:47:05 -0800204 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700205 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800206 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700207 std::cerr << "Bad fallback action specified: " << *fallbackAction
208 << std::endl;
209 return 1;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800210 }
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700211 fallback.interval = *fallbackIntervalMs;
212 fallback.always = fallbackAlways;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800213
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700214 printFallback(fallback);
Willy Tucf4ce3c2021-12-09 20:39:37 -0800215 maybeFallback = fallback;
William A. Kennington III22352192018-02-27 18:51:44 -0800216 }
217
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530218 try
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530219 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700220 // Get a default event loop
221 auto event = sdeventplus::Event::get_default();
222
223 // Get a handle to system dbus.
224 auto bus = sdbusplus::bus::new_default();
225
226 // Add systemd object manager.
Patrick Williams73bd5272022-07-22 19:26:57 -0500227 sdbusplus::server::manager_t watchdogManager(bus, path.c_str());
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700228
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530229 // Create a watchdog object
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700230 Watchdog watchdog(bus, path.c_str(), event, std::move(actionTargetMap),
Andrew Geisslerafc369a2021-06-03 14:17:16 -0500231 std::move(maybeFallback), minInterval,
William A. Kennington IIId1b1e792022-11-21 18:29:11 -0800232 defaultInterval,
233 /*exitAfterTimeout=*/!continueAfterTimeout);
William A. Kennington IIId1331082018-02-27 18:47:05 -0800234
Patrick Williams73bd5272022-07-22 19:26:57 -0500235 std::optional<sdbusplus::bus::match_t> watchPostcodeMatch;
William A. Kennington III26eef262019-04-04 15:30:30 -0700236 if (watchPostcodes)
237 {
238 watchPostcodeMatch.emplace(
239 bus,
240 sdbusplus::bus::match::rules::propertiesChanged(
William A. Kennington III459b6c72021-05-12 12:02:48 -0700241 "/xyz/openbmc_project/state/boot/raw0",
William A. Kennington III26eef262019-04-04 15:30:30 -0700242 "xyz.openbmc_project.State.Boot.Raw"),
243 std::bind(&Watchdog::resetTimeRemaining, std::ref(watchdog),
244 false));
245 }
246
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530247 // Claim the bus
248 bus.request_name(service.c_str());
249
William A. Kennington IIId1b1e792022-11-21 18:29:11 -0800250 auto intCb = [](sdeventplus::source::Signal& s,
251 const struct signalfd_siginfo*) {
252 s.get_event().exit(0);
253 };
William A. Kennington III658527b2021-12-19 20:43:22 -0800254 stdplus::signal::block(SIGINT);
255 sdeventplus::source::Signal sigint(event, SIGINT, intCb);
256 stdplus::signal::block(SIGTERM);
257 sdeventplus::source::Signal sigterm(event, SIGTERM, std::move(intCb));
William A. Kennington IIId1b1e792022-11-21 18:29:11 -0800258 return sdeventplus::utility::loopWithBus(event, bus);
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530259 }
Patrick Williams120bc4c2021-10-06 14:41:25 -0500260 catch (const InternalFailure& e)
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530261 {
262 phosphor::logging::commit<InternalFailure>();
263
264 // Need a coredump in the error cases.
265 std::terminate();
266 }
William A. Kennington IIId1b1e792022-11-21 18:29:11 -0800267 return 1;
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530268}