ups: do not power on if power status is bad

This will be a configurable feature that people can bring in via an
optional package within the phosphor-state-manager recipe.

Tested:
- Set CurrentPowerStatus to Good and verified app returned 0 with
  success log
- Set CurrentPowerStatus to UninterruptiblePowerSupply and verified
  error was logged and non-zero rc was returned
- Built full flash image and verified expected behavior in simulation

Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: I0fd5dc43b4476fd99f07d79169a71d102bb065e8
diff --git a/chassis_check_power_status.cpp b/chassis_check_power_status.cpp
new file mode 100644
index 0000000..1045369
--- /dev/null
+++ b/chassis_check_power_status.cpp
@@ -0,0 +1,68 @@
+#include "config.h"
+
+#include "utils.hpp"
+
+#include <getopt.h>
+#include <systemd/sd-bus.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/exception.hpp>
+#include <sdbusplus/server.hpp>
+
+#include <iostream>
+#include <map>
+#include <string>
+
+PHOSPHOR_LOG2_USING;
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+int main(int argc, char** argv)
+{
+    std::string chassisPath = "/xyz/openbmc_project/state/chassis0";
+    int arg;
+    int optIndex = 0;
+
+    static struct option longOpts[] = {{"chassis", required_argument, 0, 'c'},
+                                       {0, 0, 0, 0}};
+
+    while ((arg = getopt_long(argc, argv, "c:", longOpts, &optIndex)) != -1)
+    {
+        switch (arg)
+        {
+            case 'c':
+                chassisPath =
+                    std::string("/xyz/openbmc_project/state/chassis") + optarg;
+                break;
+            default:
+                break;
+        }
+    }
+
+    auto bus = sdbusplus::bus::new_default();
+
+    // If the chassis power status is not good, log an error and exit with
+    // a non-zero rc so the system does not power on
+    auto currentPowerStatus = phosphor::state::manager::utils::getProperty(
+        bus, chassisPath, CHASSIS_BUSNAME, "CurrentPowerStatus");
+    if (currentPowerStatus !=
+        "xyz.openbmc_project.State.Chassis.PowerStatus.Good")
+    {
+        error("Chassis power status is not good: {CURRENT_PWR_STATUS}",
+              "CURRENT_PWR_STATUS", currentPowerStatus);
+
+        // Generate log telling user why system is not powering on
+        const std::string errorMsg =
+            "xyz.openbmc_project.State.ChassisPowerBad";
+        phosphor::state::manager::utils::createError(
+            bus, errorMsg,
+            sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
+                Critical);
+        return -1;
+    }
+    // all good
+    info("Chassis power status good, start power on");
+    return 0;
+}
diff --git a/meson.build b/meson.build
index 9dad57f..d87b837 100644
--- a/meson.build
+++ b/meson.build
@@ -109,6 +109,17 @@
     install: true
 )
 
+executable('phosphor-chassis-check-power-status',
+            'chassis_check_power_status.cpp',
+            'utils.cpp',
+            dependencies: [
+            sdbusplus, phosphorlogging,
+            phosphordbusinterfaces, cppfs, libgpiod
+            ],
+    implicit_include_directories: true,
+    install: true
+)
+
 executable('phosphor-bmc-state-manager',
             'bmc_state_manager.cpp',
             'bmc_state_manager_main.cpp',
diff --git a/service_files/meson.build b/service_files/meson.build
index 649bd69..42b08db 100644
--- a/service_files/meson.build
+++ b/service_files/meson.build
@@ -13,7 +13,8 @@
     'xyz.openbmc_project.State.ScheduledHostTransition.service',
     'phosphor-clear-one-time@.service',
     'phosphor-set-host-transition-to-off@.service',
-    'phosphor-set-host-transition-to-running@.service'
+    'phosphor-set-host-transition-to-running@.service',
+    'phosphor-chassis-check-power-status@.service'
 ]
 
 foreach u : unit_files
diff --git a/service_files/phosphor-chassis-check-power-status@.service b/service_files/phosphor-chassis-check-power-status@.service
new file mode 100644
index 0000000..2c7812d
--- /dev/null
+++ b/service_files/phosphor-chassis-check-power-status@.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=Check chassis power status
+Wants=obmc-power-start-pre@%i.target
+Before=obmc-power-start-pre@%i.target
+Wants=mapper-wait@-xyz-openbmc_project-state-chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-state-chassis%i.service
+After=op-reset-chassis-on@%i.service
+Conflicts=obmc-chassis-poweroff@%i.target
+ConditionPathExists=!/run/openbmc/chassis@%i-on
+
+[Service]
+Restart=no
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/usr/bin/phosphor-chassis-check-power-status --chassis %i
+
+[Install]
+RequiredBy=obmc-chassis-poweron@%i.target