boot-block: add option to query blocking errors

Being able to easily see if any blocking errors are present in the
system is a useful feature. A future commit will use this new interface
to tell the user if any blocking errors are present when they request a
boot of the system.

See the following design for more details:
https://github.com/openbmc/docs/blob/master/designs/fail-boot-on-hw-error.md

Tested:
- Verify blocking errors are printed
root@witherspoon:~# obmcutil bootblock
Blocking Error: /xyz/openbmc_project/logging/entry/19
Blocking Error: /xyz/openbmc_project/logging/entry/20

- Verify after resolving them, they are not printed
root@witherspoon:~# busctl set-property xyz.openbmc_project.Logging /xyz/openbmc_project/logging/entry/19 xyz.openbmc_project.Logging.Entry Resolved b 1
root@witherspoon:~# busctl set-property xyz.openbmc_project.Logging /xyz/openbmc_project/logging/entry/20 xyz.openbmc_project.Logging.Entry Resolved b 1
root@witherspoon:~# obmcutil bootblock
No blocking errors present

Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: I25e9a398a914372a4f051ad2034f2945c776901e
diff --git a/obmcutil b/obmcutil
index 0afa678..81fba8f 100755
--- a/obmcutil
+++ b/obmcutil
@@ -4,7 +4,7 @@
 
 OPTS="bmcstate,bootprogress,chassiskill,chassisoff,chassison,chassisstate,hoststate,\
 osstate,power,poweroff,poweron,state,status,hostrebootoff,hostrebooton,recoveryoff,recoveryon,\
-bmcrebootoff, bmcrebooton"
+bmcrebootoff, bmcrebooton, listbootblock"
 
 USAGE="Usage: obmcutil [-h] [--wait] [--verbose]
                 {$OPTS}"
@@ -60,6 +60,9 @@
     echo "obmcutil recoveryon    Enable handling boot watchdog timeout and host crash"
     echo "                       Also, enable BMC and Host auto reboots"
     echo ""
+    echo "obmcutil listbootblock Check for and list any errors blocking the boot"
+    echo "                       of the system"
+    echo ""
     echo "optional arguments:"
     echo "  -h, --help          show this help message and exit"
     echo "  -w, --wait          block until state transition succeeds or fails"
@@ -181,6 +184,46 @@
     done
 }
 
+# will write blocking errors to stdout
+check_boot_block_errors ()
+{
+    # array of boot block objects
+    blockArray=()
+
+    # Look for any objects under logging that implement the
+    # xyz.openbmc_project.Logging.ErrorBlocksTransition
+    subtree="$(busctl call xyz.openbmc_project.ObjectMapper \
+               /xyz/openbmc_project/object_mapper \
+               xyz.openbmc_project.ObjectMapper \
+               GetSubTree sias "/xyz/openbmc_project/logging/" 0 1 \
+               xyz.openbmc_project.Logging.ErrorBlocksTransition)"
+
+    # remove quotation marks
+    subtree="$(echo $subtree | sed 's/\"//g')"
+
+    for entry in $subtree; do
+        if [[ ${entry} =~ "xyz/openbmc_project/logging/block"* ]]; then
+            blockArray+=( $entry )
+        fi
+    done
+
+    # now find associated error log for each boot block error
+    for berror in "${blockArray[@]}"; do
+        assocs="$(busctl call xyz.openbmc_project.Logging $berror \
+                  org.freedesktop.DBus.Properties Get \
+                  ss xyz.openbmc_project.Association.Definitions Associations)"
+
+        # remove quotation marks
+        assocs="$(echo $assocs | sed 's/\"//g')"
+
+        for entry in $assocs; do
+            if [[ ${entry} =~ "xyz/openbmc_project/logging/entry"* ]]; then
+                echo "Blocking Error: $entry"
+            fi
+        done
+    done
+}
+
 handle_cmd ()
 {
     case "$1" in
@@ -317,6 +360,14 @@
             unmask_systemd_target $HOST_TIMEOUT_TARGET
             unmask_systemd_target $HOST_CRASH_TARGET
             ;;
+        listbootblock)
+            blockingErrors=$(check_boot_block_errors)
+            if [ -z "$blockingErrors" ]; then
+                echo "No blocking errors present"
+            else
+                echo "$blockingErrors"
+            fi
+            ;;
         *)
             print_usage_err "Invalid command '$1'"
             ;;