summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Mills <gmills@us.ibm.com>2017-09-18 09:22:36 -0500
committerBrad Bishop <bradleyb@fuzziesquirrel.com>2017-09-29 03:58:25 +0000
commit6bd6d7bbc8d66c2ba74ab20821ef751046243f42 (patch)
tree14324f3540749f5456c71585e167b84712c0acef
parent234a07e856d3d03fe474a13d335df4d32e316ce6 (diff)
downloadopenpower-pnor-code-mgmt-6bd6d7bbc8d66c2ba74ab20821ef751046243f42.tar.gz
openpower-pnor-code-mgmt-6bd6d7bbc8d66c2ba74ab20821ef751046243f42.zip
Call updateFunctionalAssociation on symlink change
Call updateFunctionalAssociation, to change the functional association to the new "running" PNOR image, on a symlink change. The symlink change occurs on chassis poweron. Look at the RO symlink, /var/lib/phosphor-software-manager/pnor/ro, for a symlink change. Change-Id: I2c673635af55da1c642e6d96ab6e12951b3a4fd3 Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
-rwxr-xr-xMakefile.am1
-rwxr-xr-xitem_updater_main.cpp43
-rw-r--r--watch.cpp133
-rw-r--r--watch.hpp123
4 files changed, 295 insertions, 5 deletions
diff --git a/Makefile.am b/Makefile.am
index d9880fba7..0b94db409 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,6 +9,7 @@ openpower_update_manager_SOURCES = \
activation.cpp \
version.cpp \
serialize.cpp \
+ watch.cpp \
item_updater.cpp \
item_updater_main.cpp
diff --git a/item_updater_main.cpp b/item_updater_main.cpp
index c6f7dbad2..0933505ae 100755
--- a/item_updater_main.cpp
+++ b/item_updater_main.cpp
@@ -1,23 +1,56 @@
#include <sdbusplus/bus.hpp>
#include <sdbusplus/server/manager.hpp>
+#include <system_error>
#include "config.h"
#include "item_updater.hpp"
+#include <phosphor-logging/log.hpp>
+#include "watch.hpp"
int main(int argc, char* argv[])
{
+ using namespace openpower::software::updater;
+ using namespace phosphor::logging;
auto bus = sdbusplus::bus::new_default();
+ sd_event* loop = nullptr;
+ auto rc = sd_event_default(&loop);
+ if (rc < 0)
+ {
+ log<level::ERR>("Error occurred during the sd_event_default",
+ entry("RC=%d", rc));
+ return -1;
+ }
+
// Add sdbusplus ObjectManager.
sdbusplus::server::manager::manager objManager(bus, SOFTWARE_OBJPATH);
- openpower::software::updater::ItemUpdater updater(bus, SOFTWARE_OBJPATH);
+ ItemUpdater updater(bus, SOFTWARE_OBJPATH);
bus.request_name(BUSNAME_UPDATER);
-
- while (true)
+ try
{
- bus.process_discard();
- bus.wait();
+ openpower::software::updater::Watch watch(
+ loop,
+ std::bind(std::mem_fn(
+ &ItemUpdater::updateFunctionalAssociation),
+ &updater,
+ std::placeholders::_1));
+ bus.attach_event(loop, SD_EVENT_PRIORITY_NORMAL);
+ auto rc = sd_event_loop(loop);
+ if (rc < 0)
+ {
+ log<level::ERR>("Error occurred during the sd_event_loop",
+ entry("RC=%d", rc));
+ return -1;
+ }
}
+ catch (const std::system_error& e)
+ {
+ log<level::ERR>(e.what());
+ return -1;
+ }
+
+ sd_event_unref(loop);
+
return 0;
}
diff --git a/watch.cpp b/watch.cpp
new file mode 100644
index 000000000..da06bbc1e
--- /dev/null
+++ b/watch.cpp
@@ -0,0 +1,133 @@
+#include <stdexcept>
+#include <cstddef>
+#include <cstring>
+#include <string>
+#include <sys/inotify.h>
+#include <unistd.h>
+#include <experimental/filesystem>
+#include <phosphor-logging/log.hpp>
+#include "config.h"
+#include "watch.hpp"
+
+namespace openpower
+{
+namespace software
+{
+namespace updater
+{
+
+using namespace phosphor::logging;
+namespace fs = std::experimental::filesystem;
+
+Watch::Watch(sd_event* loop,
+ std::function<void(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 target = fs::canonical(path).string();
+
+ // Get the image <id> from the symlink target
+ // for example /media/ro-2a1022fe
+ static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
+ auto id = target.substr(PNOR_RO_PREFIX_LEN);
+ auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
+
+ static_cast<Watch*>(userdata)->functionalCallback(objPath);
+ }
+ 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/watch.hpp b/watch.hpp
new file mode 100644
index 000000000..bdea792c0
--- /dev/null
+++ b/watch.hpp
@@ -0,0 +1,123 @@
+#pragma once
+
+#include <systemd/sd-event.h>
+#include <unistd.h>
+
+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(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
OpenPOWER on IntegriCloud