mainapp: Parse action -> target mappings on the command line

This adds the argument --action_target=<action>=<systemd_target>.
Depending on the HostAction that is set when the watchdog expires we can
start different systemd targets. The configuration of this mapping is
now configurable at the command line.

Change-Id: I7482e038d9abafc81cec0df15345cbfc670dbed2
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/argument.cpp b/argument.cpp
index edbaa65..f37524e 100644
--- a/argument.cpp
+++ b/argument.cpp
@@ -90,17 +90,19 @@
 {
     std::cerr << "Usage: " << argv[0] << " options\n";
     std::cerr << "Options:\n";
-    std::cerr << " --help                        Print this menu\n";
-    std::cerr << " --path=<Dbus Object path>     Dbus Object path."
-                                                 " Ex: /xyz/openbmc_project/"
-                                                 "state/watchdog/host0\n";
-    std::cerr << " --service=<Dbus Service name> Dbus Service name."
-                                                 " Ex: xyz.openbmc_project."
-                                                 "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";
+    std::cerr << " --help                           Print this menu\n";
+    std::cerr << " --path=<Dbus Object path>        Dbus Object path."
+                     " Ex: /xyz/openbmc_project/state/watchdog/host0\n";
+    std::cerr << " --service=<Dbus Service name>    Dbus Service name."
+                     " Ex: xyz.openbmc_project.State.Watchdog.Host\n";
+    std::cerr << " [--target=<systemd unit>]        Systemd unit to be called"
+                     " on timeout for all actions but NONE. Deprecated, use"
+                     "--action_target instead.\n";
+    std::cerr << " [--action_target=<action>=<systemd unit>] Map of action to"
+                     "systemd unit to be called on timeout if that action is"
+                     "set for ExpireAction when the timer expires.\n";
+    std::cerr << " [--continue]                     Continue daemon after"
+                     " watchdog timeout.\n";
 }
 } // namespace watchdog
 } // namespace phosphor
diff --git a/mainapp.cpp b/mainapp.cpp
index bf60c88..845e291 100644
--- a/mainapp.cpp
+++ b/mainapp.cpp
@@ -103,6 +103,34 @@
         actionTargets[Watchdog::Action::PowerCycle] = target;
     }
 
+    // Parse out the action_target arguments. We allow one target to map
+    // to an action. These targets can replace the target specified above.
+    for (const auto& actionTarget : (options)["action_target"])
+    {
+        size_t keyValueSplit = actionTarget.find("=");
+        if (keyValueSplit == std::string::npos)
+        {
+            exitWithError(
+                    "Invalid action_target format, expect <action>=<target>.",
+                    argv);
+        }
+
+        std::string key = actionTarget.substr(0, keyValueSplit);
+        std::string value = actionTarget.substr(keyValueSplit+1);
+
+        // Convert an action from a fully namespaced value
+        Watchdog::Action action;
+        try
+        {
+            action = Watchdog::convertActionFromString(key);
+        }
+        catch (const sdbusplus::exception::InvalidEnumString &)
+        {
+            exitWithError("Bad action specified.", argv);
+        }
+
+        actionTargets[action] = std::move(value);
+    }
     printActionTargets(actionTargets);
 
     sd_event* event = nullptr;