Add option for daemon to continue running after timeout

Added new command line option that lets someone disable the
watchdog timer on timer expiration instead of the default
action of it exiting.

Change-Id: I1c3414d4378872860ac083836cda4809fa26237a
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/argument.cpp b/argument.cpp
index 61b1f65..41ea9ae 100644
--- a/argument.cpp
+++ b/argument.cpp
@@ -28,12 +28,13 @@
 const std::string ArgumentParser::trueString = "true"s;
 const std::string ArgumentParser::emptyString = ""s;
 
-const char* ArgumentParser::optionStr = "p:s:t:?h";
+const char* ArgumentParser::optionStr = "p:s:t:c:?h";
 const option ArgumentParser::options[] =
 {
     { "path",     required_argument,  nullptr,   'o' },
     { "service",  required_argument,  nullptr,   's' },
     { "target",   required_argument,  nullptr,   't' },
+    { "continue", no_argument,        nullptr,   'c' },
     { "help",     no_argument,        nullptr,   'h' },
     { 0, 0, 0, 0},
 };
@@ -88,6 +89,8 @@
                                                  "State.Watchdog.Host\n";
     std::cerr << " [--target=<systemd unit>]     Systemd unit to be called on"
                                                  " timeout\n";
+    std::cerr << " [--continue]                  Continue daemon after"
+                                                 " watchdog timeout.\n";
 }
 } // namespace watchdog
 } // namespace phosphor
diff --git a/mainapp.cpp b/mainapp.cpp
index 43328c3..2469363 100644
--- a/mainapp.cpp
+++ b/mainapp.cpp
@@ -37,6 +37,15 @@
     // Read arguments.
     auto options = phosphor::watchdog::ArgumentParser(argc, argv);
 
+    // Parse out continue argument.
+    auto continueParam = (options)["continue"];
+    // Default it to exit on watchdog timeout
+    auto continueAfterTimeout = false;
+    if (continueParam == phosphor::watchdog::ArgumentParser::trueString)
+    {
+        continueAfterTimeout = true;
+    }
+
     // Parse out path argument.
     auto path = (options)["path"];
     if (path == phosphor::watchdog::ArgumentParser::emptyString)
@@ -83,8 +92,8 @@
         // Claim the bus
         bus.request_name(service.c_str());
 
-        // Wait until the timer has expired
-        while(!watchdog.timerExpired())
+        // Loop forever processing events
+        while (true)
         {
             // -1 denotes wait for ever
             r = sd_event_run(eventP.get(), (uint64_t)-1);
@@ -93,6 +102,23 @@
                 log<level::ERR>("Error waiting for events");
                 elog<InternalFailure>();
             }
+
+            // The timer expiring is an event that breaks from the above.
+            if (watchdog.timerExpired())
+            {
+                // Either disable the timer or exit.
+                if (continueAfterTimeout)
+                {
+                    // The watchdog will be disabled but left running to be
+                    // re-enabled.
+                    watchdog.enabled(false);
+                }
+                else
+                {
+                    // The watchdog daemon will now exit.
+                    break;
+                }
+            }
         }
     }
     catch(InternalFailure& e)
diff --git a/timer.hpp b/timer.hpp
index 2ade017..e6b0693 100644
--- a/timer.hpp
+++ b/timer.hpp
@@ -56,6 +56,11 @@
             initialize();
         }
 
+        void clearExpired(void)
+        {
+            expire = false;
+        }
+
         /** @brief Tells whether the timer is expired or not */
         inline auto expired() const
         {
diff --git a/watchdog.cpp b/watchdog.cpp
index de90567..0c93d31 100644
--- a/watchdog.cpp
+++ b/watchdog.cpp
@@ -36,6 +36,7 @@
         else
         {
             timer.setEnabled<std::false_type>();
+            timer.clearExpired();
             log<level::INFO>("watchdog: disabled");
         }
     }