blob: 1aa69e56dc8510253cf0d47f9baae1fc72610c55 [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>
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::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
William A. Kennington III3bb2f402018-09-13 00:35:47 -070031void printActionTargetMap(const Watchdog::ActionTargetMap& actionTargetMap)
William A. Kennington III93975262018-02-02 16:00:50 -080032{
33 std::cerr << "Action Targets:\n";
William A. Kennington III3bb2f402018-09-13 00:35:47 -070034 for (const auto& [action, target] : actionTargetMap)
William A. Kennington III93975262018-02-02 16:00:50 -080035 {
William A. Kennington III3bb2f402018-09-13 00:35:47 -070036 std::cerr << " " << convertForMessage(action) << " -> " << target
37 << "\n";
William A. Kennington III93975262018-02-02 16:00:50 -080038 }
39 std::cerr << std::flush;
40}
41
William A. Kennington III1eb97d92018-09-13 00:36:12 -070042void printFallback(const Watchdog::Fallback& fallback)
43{
44 std::cerr << "Fallback Options:\n";
45 std::cerr << " Action: " << convertForMessage(fallback.action) << "\n";
46 std::cerr << " Interval(ms): " << std::dec << fallback.interval << "\n";
47 std::cerr << " Always re-execute: " << std::boolalpha << fallback.always
48 << "\n";
49 std::cerr << std::flush;
50}
51
William A. Kennington III3bb2f402018-09-13 00:35:47 -070052int main(int argc, char* argv[])
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053053{
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +053054 using namespace phosphor::logging;
Patrick Venture8f6c5152018-09-11 17:45:33 -070055 using InternalFailure =
56 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053057
William A. Kennington III1eb97d92018-09-13 00:36:12 -070058 CLI::App app{"Canonical openbmc host watchdog daemon"};
Patrick Venture09eebe32017-08-11 15:23:17 -070059
William A. Kennington III1eb97d92018-09-13 00:36:12 -070060 // Service related options
61 const std::string serviceGroup = "Service Options";
62 std::string path;
63 app.add_option("-p,--path", path,
64 "DBus Object Path. "
65 "Ex: /xyz/openbmc_project/state/watchdog/host0")
66 ->required()
67 ->group(serviceGroup);
68 std::string service;
69 app.add_option("-s,--service", service,
70 "DBus Service Name. "
71 "Ex: xyz.openbmc_project.State.Watchdog.Host")
72 ->required()
73 ->group(serviceGroup);
74 bool continueAfterTimeout;
75 app.add_flag("-c,--continue", continueAfterTimeout,
76 "Continue daemon after watchdog timeout")
77 ->group(serviceGroup);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053078
William A. Kennington III1eb97d92018-09-13 00:36:12 -070079 // Target related options
80 const std::string targetGroup = "Target Options";
81 std::optional<std::string> target;
82 app.add_option("-t,--target", target,
83 "Systemd unit to be called on "
84 "timeout for all actions but NONE. "
85 "Deprecated, use --action_target instead.")
86 ->group(targetGroup);
87 std::vector<std::string> actionTargets;
88 app.add_option("-a,--action_target", actionTargets,
89 "Map of action to "
90 "systemd unit to be called on timeout if that action is "
91 "set for ExpireAction when the timer expires.")
92 ->group(targetGroup);
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +053093
William A. Kennington III1eb97d92018-09-13 00:36:12 -070094 // Fallback related options
95 const std::string fallbackGroup = "Fallback Options";
96 std::optional<std::string> fallbackAction;
97 auto fallbackActionOpt =
98 app.add_option("-f,--fallback_action", fallbackAction,
99 "Enables the "
100 "watchdog even when disabled via the dbus interface. "
101 "Perform this action when the fallback expires.")
102 ->group(fallbackGroup);
103 std::optional<unsigned> fallbackIntervalMs;
104 auto fallbackIntervalOpt =
105 app.add_option("-i,--fallback_interval", fallbackIntervalMs,
106 "Enables the "
107 "watchdog even when disabled via the dbus interface. "
108 "Waits for this interval before performing the fallback "
109 "action.")
110 ->group(fallbackGroup);
111 fallbackIntervalOpt->needs(fallbackActionOpt);
112 fallbackActionOpt->needs(fallbackIntervalOpt);
113 bool fallbackAlways;
114 app.add_flag("-e,--fallback_always", fallbackAlways,
115 "Enables the "
116 "watchdog even when disabled by the dbus interface. "
117 "This option is only valid with a fallback specified")
118 ->group(fallbackGroup)
119 ->needs(fallbackActionOpt)
120 ->needs(fallbackIntervalOpt);
121
122 CLI11_PARSE(app, argc, argv);
123
124 // Put together a list of actions and associated systemd targets
125 // The new --action_target options take precedence over the legacy
126 // --target
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700127 Watchdog::ActionTargetMap actionTargetMap;
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700128 if (target)
Patrick Venture8f6c5152018-09-11 17:45:33 -0700129 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700130 actionTargetMap[Watchdog::Action::HardReset] = *target;
131 actionTargetMap[Watchdog::Action::PowerOff] = *target;
132 actionTargetMap[Watchdog::Action::PowerCycle] = *target;
William A. Kennington III1232a152018-02-02 15:57:34 -0800133 }
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700134 for (const auto& actionTarget : actionTargets)
William A. Kennington III27df4b52018-02-02 16:02:05 -0800135 {
136 size_t keyValueSplit = actionTarget.find("=");
137 if (keyValueSplit == std::string::npos)
138 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700139 std::cerr << "Invalid action_target format, "
140 "expect <action>=<target>."
141 << std::endl;
142 return 1;
William A. Kennington III27df4b52018-02-02 16:02:05 -0800143 }
144
145 std::string key = actionTarget.substr(0, keyValueSplit);
Patrick Venture8f6c5152018-09-11 17:45:33 -0700146 std::string value = actionTarget.substr(keyValueSplit + 1);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800147
148 // Convert an action from a fully namespaced value
149 Watchdog::Action action;
150 try
151 {
152 action = Watchdog::convertActionFromString(key);
153 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700154 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington III27df4b52018-02-02 16:02:05 -0800155 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700156 std::cerr << "Bad action specified: " << key << std::endl;
157 return 1;
William A. Kennington III27df4b52018-02-02 16:02:05 -0800158 }
159
William A. Kennington IIIc2c26ce2018-09-13 18:35:56 -0700160 // Detect duplicate action target arguments
161 if (actionTargetMap.find(action) != actionTargetMap.end())
162 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700163 std::cerr << "Got duplicate action: " << key << std::endl;
164 return 1;
William A. Kennington IIIc2c26ce2018-09-13 18:35:56 -0700165 }
166
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700167 actionTargetMap[action] = std::move(value);
William A. Kennington III27df4b52018-02-02 16:02:05 -0800168 }
William A. Kennington III3bb2f402018-09-13 00:35:47 -0700169 printActionTargetMap(actionTargetMap);
William A. Kennington III93975262018-02-02 16:00:50 -0800170
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700171 // Build the fallback option used for the Watchdog
172 std::optional<Watchdog::Fallback> maybeFallback;
173 if (fallbackAction)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800174 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700175 Watchdog::Fallback fallback;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800176 try
177 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700178 fallback.action =
179 Watchdog::convertActionFromString(*fallbackAction);
William A. Kennington IIId1331082018-02-27 18:47:05 -0800180 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700181 catch (const sdbusplus::exception::InvalidEnumString&)
William A. Kennington IIId1331082018-02-27 18:47:05 -0800182 {
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700183 std::cerr << "Bad fallback action specified: " << *fallbackAction
184 << std::endl;
185 return 1;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800186 }
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700187 fallback.interval = *fallbackIntervalMs;
188 fallback.always = fallbackAlways;
William A. Kennington IIId1331082018-02-27 18:47:05 -0800189
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700190 printFallback(fallback);
191 maybeFallback = std::move(fallback);
William A. Kennington III22352192018-02-27 18:51:44 -0800192 }
193
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530194 try
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530195 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700196 // Get a default event loop
197 auto event = sdeventplus::Event::get_default();
198
199 // Get a handle to system dbus.
200 auto bus = sdbusplus::bus::new_default();
201
202 // Add systemd object manager.
203 sdbusplus::server::manager::manager(bus, path.c_str());
204
205 // Attach the bus to sd_event to service user requests
206 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
207
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530208 // Create a watchdog object
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700209 Watchdog watchdog(bus, path.c_str(), event, std::move(actionTargetMap),
William A. Kennington III1eb97d92018-09-13 00:36:12 -0700210 std::move(maybeFallback));
William A. Kennington IIId1331082018-02-27 18:47:05 -0800211
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530212 // Claim the bus
213 bus.request_name(service.c_str());
214
William A. Kennington III825f4982018-02-27 19:10:56 -0800215 // Loop until our timer expires and we don't want to continue
216 while (continueAfterTimeout || !watchdog.timerExpired())
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530217 {
William A. Kennington IIIf505fc02018-09-12 18:30:09 -0700218 // Run and never timeout
219 event.run(std::nullopt);
Vishwanatha Subbanna7e146552017-05-29 17:03:33 +0530220 }
221 }
Patrick Venture8f6c5152018-09-11 17:45:33 -0700222 catch (InternalFailure& e)
Vishwanatha Subbanna4d5ef3f2017-05-31 18:54:22 +0530223 {
224 phosphor::logging::commit<InternalFailure>();
225
226 // Need a coredump in the error cases.
227 std::terminate();
228 }
Vishwanatha Subbanna15b1dc12017-05-23 15:16:13 +0530229 return 0;
230}