| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 1 | /** | 
 | 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 III | d133108 | 2018-02-27 18:47:05 -0800 | [diff] [blame] | 18 | #include <experimental/optional> | 
| Vishwanatha Subbanna | 7e14655 | 2017-05-29 17:03:33 +0530 | [diff] [blame] | 19 | #include <phosphor-logging/log.hpp> | 
| Vishwanatha Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 20 | #include <phosphor-logging/elog.hpp> | 
 | 21 | #include <phosphor-logging/elog-errors.hpp> | 
| William A. Kennington III | 9397526 | 2018-02-02 16:00:50 -0800 | [diff] [blame] | 22 | #include <string> | 
| Vishwanatha Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 23 | #include <xyz/openbmc_project/Common/error.hpp> | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 24 | #include "argument.hpp" | 
| Vishwanatha Subbanna | d7a3f13 | 2017-05-29 19:39:08 +0530 | [diff] [blame] | 25 | #include "watchdog.hpp" | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 26 |  | 
| William A. Kennington III | 1232a15 | 2018-02-02 15:57:34 -0800 | [diff] [blame] | 27 | using phosphor::watchdog::ArgumentParser; | 
 | 28 | using phosphor::watchdog::Watchdog; | 
| William A. Kennington III | 9397526 | 2018-02-02 16:00:50 -0800 | [diff] [blame] | 29 | using sdbusplus::xyz::openbmc_project::State::server::convertForMessage; | 
| William A. Kennington III | 1232a15 | 2018-02-02 15:57:34 -0800 | [diff] [blame] | 30 |  | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 31 | static void exitWithError(const char* err, char** argv) | 
 | 32 | { | 
| William A. Kennington III | 1232a15 | 2018-02-02 15:57:34 -0800 | [diff] [blame] | 33 |     ArgumentParser::usage(argv); | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 34 |     std::cerr << "ERROR: " << err << "\n"; | 
 | 35 |     exit(EXIT_FAILURE); | 
 | 36 | } | 
 | 37 |  | 
| William A. Kennington III | 9397526 | 2018-02-02 16:00:50 -0800 | [diff] [blame] | 38 | void 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 Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 50 | int main(int argc, char** argv) | 
 | 51 | { | 
| Vishwanatha Subbanna | 7e14655 | 2017-05-29 17:03:33 +0530 | [diff] [blame] | 52 |     using namespace phosphor::logging; | 
| Vishwanatha Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 53 |     using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: | 
 | 54 |                                 Error::InternalFailure; | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 55 |     // Read arguments. | 
| William A. Kennington III | 1232a15 | 2018-02-02 15:57:34 -0800 | [diff] [blame] | 56 |     auto options = ArgumentParser(argc, argv); | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 57 |  | 
| Patrick Venture | 09eebe3 | 2017-08-11 15:23:17 -0700 | [diff] [blame] | 58 |     // Parse out continue argument. | 
 | 59 |     auto continueParam = (options)["continue"]; | 
 | 60 |     // Default it to exit on watchdog timeout | 
 | 61 |     auto continueAfterTimeout = false; | 
| William A. Kennington III | 5d30718 | 2018-01-23 22:00:55 -0800 | [diff] [blame] | 62 |     if (!continueParam.empty()) | 
| Patrick Venture | 09eebe3 | 2017-08-11 15:23:17 -0700 | [diff] [blame] | 63 |     { | 
 | 64 |         continueAfterTimeout = true; | 
 | 65 |     } | 
 | 66 |  | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 67 |     // Parse out path argument. | 
| William A. Kennington III | 5d30718 | 2018-01-23 22:00:55 -0800 | [diff] [blame] | 68 |     auto pathParam = (options)["path"]; | 
 | 69 |     if (pathParam.empty()) | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 70 |     { | 
 | 71 |         exitWithError("Path not specified.", argv); | 
 | 72 |     } | 
| William A. Kennington III | 5d30718 | 2018-01-23 22:00:55 -0800 | [diff] [blame] | 73 |     if (pathParam.size() > 1) | 
 | 74 |     { | 
 | 75 |         exitWithError("Multiple paths specified.", argv); | 
 | 76 |     } | 
 | 77 |     auto path = pathParam.back(); | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 78 |  | 
 | 79 |     // Parse out service name argument | 
| William A. Kennington III | 5d30718 | 2018-01-23 22:00:55 -0800 | [diff] [blame] | 80 |     auto serviceParam = (options)["service"]; | 
 | 81 |     if (serviceParam.empty()) | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 82 |     { | 
 | 83 |         exitWithError("Service not specified.", argv); | 
 | 84 |     } | 
| William A. Kennington III | 5d30718 | 2018-01-23 22:00:55 -0800 | [diff] [blame] | 85 |     if (serviceParam.size() > 1) | 
 | 86 |     { | 
 | 87 |         exitWithError("Multiple services specified.", argv); | 
 | 88 |     } | 
 | 89 |     auto service = serviceParam.back(); | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 90 |  | 
 | 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 III | 5d30718 | 2018-01-23 22:00:55 -0800 | [diff] [blame] | 94 |     auto targetParam = (options)["target"]; | 
 | 95 |     if (targetParam.size() > 1) | 
 | 96 |     { | 
 | 97 |         exitWithError("Multiple targets specified.", argv); | 
 | 98 |     } | 
| William A. Kennington III | 1232a15 | 2018-02-02 15:57:34 -0800 | [diff] [blame] | 99 |     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 Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 106 |  | 
| William A. Kennington III | 27df4b5 | 2018-02-02 16:02:05 -0800 | [diff] [blame] | 107 |     // 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 III | 9397526 | 2018-02-02 16:00:50 -0800 | [diff] [blame] | 135 |     printActionTargets(actionTargets); | 
 | 136 |  | 
| William A. Kennington III | d133108 | 2018-02-27 18:47:05 -0800 | [diff] [blame] | 137 |     // 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 III | 2235219 | 2018-02-27 18:51:44 -0800 | [diff] [blame] | 175 |             .always = false, | 
| William A. Kennington III | d133108 | 2018-02-27 18:47:05 -0800 | [diff] [blame] | 176 |         }; | 
 | 177 |     } | 
 | 178 |  | 
| William A. Kennington III | 2235219 | 2018-02-27 18:51:44 -0800 | [diff] [blame] | 179 |     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 Subbanna | 7e14655 | 2017-05-29 17:03:33 +0530 | [diff] [blame] | 190 |     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 Subbanna | d7a3f13 | 2017-05-29 19:39:08 +0530 | [diff] [blame] | 200 |     // Get a handle to system dbus. | 
 | 201 |     auto bus = sdbusplus::bus::new_default(); | 
| Vishwanatha Subbanna | 7e14655 | 2017-05-29 17:03:33 +0530 | [diff] [blame] | 202 |  | 
| Vishwanatha Subbanna | d7a3f13 | 2017-05-29 19:39:08 +0530 | [diff] [blame] | 203 |     // 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 Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 209 |     try | 
| Vishwanatha Subbanna | 7e14655 | 2017-05-29 17:03:33 +0530 | [diff] [blame] | 210 |     { | 
| Vishwanatha Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 211 |         // Create a watchdog object | 
| William A. Kennington III | d133108 | 2018-02-27 18:47:05 -0800 | [diff] [blame] | 212 |         Watchdog watchdog(bus, path.c_str(), eventP, std::move(actionTargets), | 
 | 213 |             std::move(fallback)); | 
 | 214 |  | 
| Vishwanatha Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 215 |         // Claim the bus | 
 | 216 |         bus.request_name(service.c_str()); | 
 | 217 |  | 
| William A. Kennington III | 825f498 | 2018-02-27 19:10:56 -0800 | [diff] [blame] | 218 |         // Loop until our timer expires and we don't want to continue | 
 | 219 |         while (continueAfterTimeout || !watchdog.timerExpired()) | 
| Vishwanatha Subbanna | 7e14655 | 2017-05-29 17:03:33 +0530 | [diff] [blame] | 220 |         { | 
| Vishwanatha Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 221 |             // -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 Subbanna | 7e14655 | 2017-05-29 17:03:33 +0530 | [diff] [blame] | 228 |         } | 
 | 229 |     } | 
| Vishwanatha Subbanna | 4d5ef3f | 2017-05-31 18:54:22 +0530 | [diff] [blame] | 230 |     catch(InternalFailure& e) | 
 | 231 |     { | 
 | 232 |         phosphor::logging::commit<InternalFailure>(); | 
 | 233 |  | 
 | 234 |         // Need a coredump in the error cases. | 
 | 235 |         std::terminate(); | 
 | 236 |     } | 
| Vishwanatha Subbanna | 15b1dc1 | 2017-05-23 15:16:13 +0530 | [diff] [blame] | 237 |     return 0; | 
 | 238 | } |