Refactor: Move watch to ubi
watch is ubi specific functions, move it to ubi dir.
Tested: On the last commit of the patch series, run code update and
factory reset on Witherspoon and all work fine.
Change-Id: Ia7f6b6de845ddd40e2a32ad626d3b7af9074c7f3
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/ubi/Makefile.am.include b/ubi/Makefile.am.include
index fba30d9..a836661 100644
--- a/ubi/Makefile.am.include
+++ b/ubi/Makefile.am.include
@@ -1,2 +1,3 @@
openpower_update_manager_SOURCES += \
- %reldir%/item_updater_ubi.cpp
+ %reldir%/item_updater_ubi.cpp \
+ %reldir%/watch.cpp
diff --git a/ubi/watch.cpp b/ubi/watch.cpp
new file mode 100644
index 0000000..192d3d9
--- /dev/null
+++ b/ubi/watch.cpp
@@ -0,0 +1,121 @@
+#include "config.h"
+
+#include "watch.hpp"
+
+#include "item_updater.hpp"
+
+#include <sys/inotify.h>
+#include <unistd.h>
+
+#include <cstddef>
+#include <cstring>
+#include <experimental/filesystem>
+#include <functional>
+#include <phosphor-logging/log.hpp>
+#include <stdexcept>
+#include <string>
+
+namespace openpower
+{
+namespace software
+{
+namespace updater
+{
+
+using namespace phosphor::logging;
+namespace fs = std::experimental::filesystem;
+
+Watch::Watch(sd_event* loop,
+ std::function<void(const std::string&)> functionalCallback) :
+ functionalCallback(functionalCallback),
+ fd(inotifyInit())
+
+{
+ // Create PNOR_ACTIVE_PATH if doesn't exist.
+ if (!fs::is_directory(PNOR_ACTIVE_PATH))
+ {
+ fs::create_directories(PNOR_ACTIVE_PATH);
+ }
+
+ wd = inotify_add_watch(fd(), PNOR_ACTIVE_PATH, IN_CREATE);
+ if (-1 == wd)
+ {
+ auto error = errno;
+ throw std::system_error(error, std::generic_category(),
+ "Error occurred during the inotify_init1");
+ }
+
+ decltype(eventSource.get()) sourcePtr = nullptr;
+ auto rc = sd_event_add_io(loop, &sourcePtr, fd(), EPOLLIN, callback, this);
+
+ eventSource.reset(sourcePtr);
+
+ if (0 > rc)
+ {
+ throw std::system_error(-rc, std::generic_category(),
+ "Error occurred during the inotify_init1");
+ }
+}
+
+Watch::~Watch()
+{
+ if ((-1 != fd()) && (-1 != wd))
+ {
+ inotify_rm_watch(fd(), wd);
+ }
+}
+
+int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
+ void* userdata)
+{
+ if (!(revents & EPOLLIN))
+ {
+ return 0;
+ }
+
+ constexpr auto maxBytes = 1024;
+ uint8_t buffer[maxBytes];
+ auto bytes = read(fd, buffer, maxBytes);
+ if (0 > bytes)
+ {
+ auto error = errno;
+ throw std::system_error(error, std::generic_category(),
+ "failed to read inotify event");
+ }
+
+ auto offset = 0;
+ while (offset < bytes)
+ {
+ auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
+ // Update the functional association on a RO
+ // active image symlink change
+ fs::path path(PNOR_ACTIVE_PATH);
+ path /= event->name;
+ if (fs::equivalent(path, PNOR_RO_ACTIVE_PATH))
+ {
+ auto id = ItemUpdater::determineId(path);
+ static_cast<Watch*>(userdata)->functionalCallback(id);
+ }
+ offset += offsetof(inotify_event, name) + event->len;
+ }
+
+ return 0;
+}
+
+int Watch::inotifyInit()
+{
+ auto fd = inotify_init1(IN_NONBLOCK);
+
+ if (-1 == fd)
+ {
+ auto error = errno;
+ throw std::system_error(error, std::generic_category(),
+ "Error occurred during the inotify_init1");
+ }
+
+ return fd;
+}
+
+} // namespace updater
+} // namespace software
+} // namespace openpower
diff --git a/ubi/watch.hpp b/ubi/watch.hpp
new file mode 100644
index 0000000..a04967e
--- /dev/null
+++ b/ubi/watch.hpp
@@ -0,0 +1,126 @@
+#pragma once
+
+#include <systemd/sd-event.h>
+#include <unistd.h>
+
+#include <functional>
+#include <memory>
+
+namespace openpower
+{
+namespace software
+{
+namespace updater
+{
+
+/* Need a custom deleter for freeing up sd_event_source */
+struct EventSourceDeleter
+{
+ void operator()(sd_event_source* eventSource) const
+ {
+ eventSource = sd_event_source_unref(eventSource);
+ }
+};
+using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>;
+
+/** @struct CustomFd
+ *
+ * RAII wrapper for file descriptor.
+ */
+struct CustomFd
+{
+ public:
+ CustomFd() = delete;
+ CustomFd(const CustomFd&) = delete;
+ CustomFd& operator=(const CustomFd&) = delete;
+ CustomFd(CustomFd&&) = delete;
+ CustomFd& operator=(CustomFd&&) = delete;
+
+ /** @brief Saves File descriptor and uses it to do file operation
+ *
+ * @param[in] fd - File descriptor
+ */
+ CustomFd(int fd) : fd(fd)
+ {
+ }
+
+ ~CustomFd()
+ {
+ if (fd >= 0)
+ {
+ close(fd);
+ }
+ }
+
+ int operator()() const
+ {
+ return fd;
+ }
+
+ private:
+ /** @brief File descriptor */
+ int fd = -1;
+};
+
+/** @class Watch
+ *
+ * @brief Adds inotify watch on PNOR symlinks file to monitor for changes in
+ * "running" PNOR version
+ *
+ * The inotify watch is hooked up with sd-event, so that on call back,
+ * appropriate actions related to a change in the "running" PNOR version
+ * can be taken.
+ */
+class Watch
+{
+ public:
+ /** @brief ctor - hook inotify watch with sd-event
+ *
+ * @param[in] loop - sd-event object
+ * @param[in] functionalCallback - The callback function for updating
+ * the functional associations.
+ */
+ Watch(sd_event* loop,
+ std::function<void(const std::string&)> functionalCallback);
+
+ Watch(const Watch&) = delete;
+ Watch& operator=(const Watch&) = delete;
+ Watch(Watch&&) = delete;
+ Watch& operator=(Watch&&) = delete;
+
+ /** @brief dtor - remove inotify watch
+ */
+ ~Watch();
+
+ private:
+ /** @brief sd-event callback
+ *
+ * @param[in] s - event source, floating (unused) in our case
+ * @param[in] fd - inotify fd
+ * @param[in] revents - events that matched for fd
+ * @param[in] userdata - pointer to Watch object
+ * @returns 0 on success, -1 on fail
+ */
+ static int callback(sd_event_source* s, int fd, uint32_t revents,
+ void* userdata);
+
+ /** initialize an inotify instance and returns file descriptor */
+ int inotifyInit();
+
+ /** @brief PNOR symlink file watch descriptor */
+ int wd = -1;
+
+ /** @brief event source */
+ EventSourcePtr eventSource;
+
+ /** @brief The callback function for updating the
+ functional associations. */
+ std::function<void(std::string&)> functionalCallback;
+
+ /** @brief inotify file descriptor */
+ CustomFd fd;
+};
+
+} // namespace updater
+} // namespace software
+} // namespace openpower