Log failing path after sysfs access failures

Log failing device path and error after a sysfs access failure.
Gracefully exit rather than crash.

Change-Id: I41316e84a70ceda8c166f31ab3269f97978da3ab
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/Makefile.am b/Makefile.am
index 5ce260f..ee6e7a8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,8 +6,13 @@
 phosphor_hwmon_readd_CFLAGS = $(SDBUSPLUS_CFLAGS)
 
 noinst_LTLIBRARIES = libhwmon.la
-libhwmon_la_LDFLAGS = $(SDBUSPLUS_LIBS) $(PHOSPHOR_DBUS_INTERFACES_LIBS)
-libhwmon_la_CFLAGS = $(SDBUSPLUS_CFLAGS) $(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
+libhwmon_la_LDFLAGS = \
+	$(SDBUSPLUS_LIBS) \
+	$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+	$(PHOSPHOR_LOGGING_LIBS)
+libhwmon_la_CFLAGS = $(SDBUSPLUS_CFLAGS) \
+	$(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \
+	$(PHOSPHOR_LOGGING_CFLAGS)
 
 libhwmon_la_SOURCES = \
 	argument.cpp \
diff --git a/configure.ac b/configure.ac
index 303d6ff..c7bfa46 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,6 +15,7 @@
 # Checks for libraries.
 PKG_CHECK_MODULES([SDBUSPLUS], [sdbusplus], [], [AC_MSG_ERROR(["sdbusplus required and not found."])])
 PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces], [], [AC_MSG_ERROR(["phosphor-dbus-interfaces required and not found."])])
+PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging], [], [AC_MSG_ERROR(["phosphor-logging required and not found."])])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AX_CXX_COMPILE_STDCXX_14([noext])
diff --git a/mainloop.cpp b/mainloop.cpp
index 31b02ac..0077d33 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -110,7 +110,9 @@
 }
 
 auto addValue(const SensorSet::key_type& sensor,
-              const std::string& sysfsRoot, ObjectInfo& info)
+              const std::string& hwmonRoot,
+              const std::string& instance,
+              ObjectInfo& info)
 {
     static constexpr bool deferSignals = true;
 
@@ -119,14 +121,11 @@
     auto& obj = std::get<Object>(info);
     auto& objPath = std::get<std::string>(info);
 
-    auto sysfsPath = make_sysfs_path(
-                         sysfsRoot,
-                         sensor.first,
-                         sensor.second,
-                         hwmon::entry::input);
-    int val = 0;
-    read_sysfs(sysfsPath, val);
-
+    int val = readSysfsWithCallout(hwmonRoot,
+                                   instance,
+                                   sensor.first,
+                                   sensor.second,
+                                   hwmon::entry::input);
     auto iface = std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
     iface->value(val);
 
@@ -180,8 +179,7 @@
 void MainLoop::run()
 {
     // Check sysfs for available sensors.
-    std::string hwmonPath = _hwmonRoot + '/' + _instance;
-    auto sensors = std::make_unique<SensorSet>(hwmonPath);
+    auto sensors = std::make_unique<SensorSet>(_hwmonRoot + '/' + _instance);
 
     for (auto& i : *sensors)
     {
@@ -207,7 +205,7 @@
         objectPath.append(label);
 
         ObjectInfo info(&_bus, std::move(objectPath), Object());
-        auto valueInterface = addValue(i.first, hwmonPath, info);
+        auto valueInterface = addValue(i.first, _hwmonRoot, _instance, info);
         auto sensorValue = valueInterface->value();
         addThreshold<WarningObject>(i.first, sensorValue, info);
         addThreshold<CriticalObject>(i.first, sensorValue, info);
@@ -244,12 +242,11 @@
             if (attrs.find(hwmon::entry::input) != attrs.end())
             {
                 // Read value from sensor.
-                int value = 0;
-                read_sysfs(make_sysfs_path(hwmonPath,
-                                           i.first.first, i.first.second,
-                                           hwmon::entry::input),
-                           value);
-
+                int value = readSysfsWithCallout(_hwmonRoot,
+                                                 _instance,
+                                                 i.first.first,
+                                                 i.first.second,
+                                                 hwmon::entry::input);
                 auto& objInfo = std::get<ObjectInfo>(i.second);
                 auto& obj = std::get<Object>(objInfo);
 
diff --git a/sysfs.cpp b/sysfs.cpp
index f1f46db..0cc11ef 100644
--- a/sysfs.cpp
+++ b/sysfs.cpp
@@ -15,6 +15,7 @@
  */
 #include <cstdlib>
 #include <memory>
+#include <phosphor-logging/log.hpp>
 #include "sysfs.hpp"
 #include "util.hpp"
 #include "directory.hpp"
@@ -51,4 +52,46 @@
     return std::string();
 }
 
+int readSysfsWithCallout(const std::string& root,
+                         const std::string& instance,
+                         const std::string& type,
+                         const std::string& id,
+                         const std::string& sensor)
+{
+    int value = 0;
+    std::string instancePath = root + '/' + instance;
+    std::string fullPath = make_sysfs_path(instancePath,
+                                           type, id, sensor);
+    std::ifstream ifs;
+
+    ifs.exceptions(std::ifstream::failbit
+                   | std::ifstream::badbit
+                   | std::ifstream::eofbit);
+    try
+    {
+        ifs.open(fullPath);
+        ifs >> value;
+    }
+    catch (const std::exception& e)
+    {
+        // Too many GCC bugs (53984, 66145) to do
+        // this the right way...
+        using Cleanup = phosphor::utility::Free<char>;
+
+        // errno should still reflect the error from the failing open
+        // or read system calls that got us here.
+        auto rc = errno;
+        std::string devicePath = instancePath + "/device";
+        auto real = std::unique_ptr<char, Cleanup>(
+                        realpath(devicePath.c_str(), nullptr));
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            strerror(rc),
+            phosphor::logging::entry("CALLOUT_DEVICE_PATH=%s", real.get()),
+            phosphor::logging::entry("CALLOUT_ERRNO=%d", rc));
+        exit(EXIT_FAILURE);
+    }
+
+    return value;
+}
+
 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/sysfs.hpp b/sysfs.hpp
index 8f09e03..c38ed9e 100644
--- a/sysfs.hpp
+++ b/sysfs.hpp
@@ -40,4 +40,22 @@
  */
 std::string findHwmon(const std::string& ofNode);
 
+/** @brief Read an hwmon sysfs value.
+ *
+ *  Calls exit(3) with bad status on failure.
+ *
+ *  @param[in] root - The hwmon class root.
+ *  @param[in] instance - The hwmon instance (ex. hwmon1).
+ *  @param[in] type - The hwmon type (ex. temp).
+ *  @param[in] id - The hwmon id (ex. 1).
+ *  @param[in] sensor - The hwmon sensor (ex. input).
+ *
+ *  @returns - The read value.
+ */
+int readSysfsWithCallout(const std::string& root,
+                         const std::string& instance,
+                         const std::string& type,
+                         const std::string& id,
+                         const std::string& sensor);
+
 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4