From 059e23355e0563ed22661ec2a78ccdc563414a7d Mon Sep 17 00:00:00 2001 From: Deepak Kodihalli Date: Wed, 12 Apr 2017 06:40:53 -0500 Subject: image manager: add inotify watch Add an inotify watch to the known software image location. Hook the inotify fd with sd-event, so that on callback, version d-bus objects can be created based on the newly added software image. Resolves openbmc/openbmc#1444. Change-Id: I5c460f820c8d3a851b8ddc969f26d38870c36991 Signed-off-by: Deepak Kodihalli --- Makefile.am | 21 ++++++++-- configure.ac | 6 +++ image_manager_main.cpp | 25 ++++++++---- watch.cpp | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ watch.hpp | 60 ++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+), 10 deletions(-) create mode 100644 watch.cpp create mode 100644 watch.hpp diff --git a/Makefile.am b/Makefile.am index 1e863d7..e4be065 100755 --- a/Makefile.am +++ b/Makefile.am @@ -1,19 +1,34 @@ AM_DEFAULT_SOURCE_EXT = .cpp +# Build these headers, don't install them +noinst_HEADERS = \ + version_software_manager.hpp \ + download_manager.hpp \ + watch.hpp + sbin_PROGRAMS = \ phosphor-version-software-manager \ phosphor-download-manager phosphor_version_software_manager_SOURCES = \ version_software_manager.cpp \ - image_manager_main.cpp + image_manager_main.cpp \ + watch.cpp phosphor_download_manager_SOURCES = \ download_manager.cpp \ download_manager_main.cpp -generic_cxxflags = $(SYSTEMD_CFLAGS) $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) $(SDBUSPLUS_CFLAGS) -generic_ldflags = $(SYSTEMD_LIBS) $(PHOSPHOR_DBUS_INTERFACES_LIBS) $(SDBUSPLUS_LIBS) +generic_cxxflags = \ + $(SYSTEMD_CFLAGS) \ + $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ + $(SDBUSPLUS_CFLAGS) \ + $(PHOSPHOR_LOGGING_CFLAGS) +generic_ldflags = \ + $(SYSTEMD_LIBS) \ + $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ + $(SDBUSPLUS_LIBS) \ + $(PHOSPHOR_LOGGING_LIBS) phosphor_version_software_manager_CXXFLAGS = $(generic_cxxflags) phosphor_version_software_manager_LDFLAGS = $(generic_ldflags) diff --git a/configure.ac b/configure.ac index af227ae..1928422 100755 --- a/configure.ac +++ b/configure.ac @@ -16,6 +16,8 @@ PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces],,\ AC_MSG_ERROR(["Requires phosphor-dbus-interfaces package."])) PKG_CHECK_MODULES([SDBUSPLUS], [sdbusplus],, AC_MSG_ERROR(["Requires sdbusplus package."])) +PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging],,\ + AC_MSG_ERROR(["Requires phosphor-logging package."])) # Checks for library functions LT_INIT # Required for systemd linking @@ -37,6 +39,10 @@ AS_IF([test "x$DOWNLOAD_BUSNAME" == "x"], [DOWNLOAD_BUSNAME="xyz.openbmc_project.Software.Download"]) AC_DEFINE_UNQUOTED([DOWNLOAD_BUSNAME], ["$DOWNLOAD_BUSNAME"], [The DBus busname to own]) +AC_ARG_VAR(IMG_UPLOAD_DIR, [Directory where downloaded software images are placed]) +AS_IF([test "x$IMG_UPLOAD_DIR" == "x"], [IMG_UPLOAD_DIR="/tmp/images"]) +AC_DEFINE_UNQUOTED([IMG_UPLOAD_DIR], ["$IMG_UPLOAD_DIR"], [Directory where downloaded software images are placed]) + # Check for header files. AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd developement package required])]) AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])]) diff --git a/image_manager_main.cpp b/image_manager_main.cpp index bd41b63..66f31f6 100644 --- a/image_manager_main.cpp +++ b/image_manager_main.cpp @@ -1,27 +1,38 @@ -#include #include #include #include +#include #include "config.h" #include "version_software_manager.hpp" +#include "watch.hpp" int main(int argc, char* argv[]) { auto bus = sdbusplus::bus::new_default(); - // Add sdbusplus ObjectManager. + sd_event* loop = nullptr; + sd_event_default(&loop); + sdbusplus::server::manager::manager objManager(bus, SOFTWARE_OBJPATH); - phosphor::software::manager::Version manager(bus, SOFTWARE_OBJPATH); - bus.request_name(VERSION_BUSNAME); - while (true) + try { - bus.process_discard(); - bus.wait(); + phosphor::software::manager::Watch watch(loop); + bus.attach_event(loop, SD_EVENT_PRIORITY_NORMAL); + sd_event_loop(loop); } + catch (std::exception& e) + { + using namespace phosphor::logging; + log(e.what()); + return -1; + } + + sd_event_unref(loop); + return 0; } diff --git a/watch.cpp b/watch.cpp new file mode 100644 index 0000000..a520dd2 --- /dev/null +++ b/watch.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "watch.hpp" + +namespace phosphor +{ +namespace software +{ +namespace manager +{ + +using namespace std::string_literals; + +Watch::Watch(sd_event* loop) +{ + fd = inotify_init1(IN_NONBLOCK); + if (-1 == fd) + { + // Store a copy of errno, because the string creation below will + // invalidate errno due to one more system calls. + auto error = errno; + throw std::runtime_error( + "inotify_init1 failed, errno="s + std::strerror(error)); + } + + wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CREATE); + if (-1 == wd) + { + auto error = errno; + close(fd); + throw std::runtime_error( + "inotify_add_watch failed, errno="s + std::strerror(error)); + } + + auto rc = sd_event_add_io(loop, + nullptr, + fd, + EPOLLIN, + callback, + this); + if (0 > rc) + { + throw std::runtime_error( + "failed to add to event loop, rc="s + std::strerror(-rc)); + } +} + +Watch::~Watch() +{ + if ((-1 != fd) && (-1 != wd)) + { + inotify_rm_watch(fd, wd); + close(fd); + } +} + +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::runtime_error( + "failed to read inotify event, errno="s + std::strerror(error)); + } + + auto offset = 0; + while (offset < bytes) + { + auto event = reinterpret_cast(&buffer[offset]); + if ((event->mask & IN_CREATE) && !(event->mask & IN_ISDIR)) + { + // TODO: openbmc/openbmc#1352 - invoke method (which takes uploaded + // filepath) to construct software version d-bus objects. + // For now, log the image filename. + using namespace phosphor::logging; + log(event->name); + } + + offset += offsetof(inotify_event, name) + event->len; + } + + return 0; +} + +} // namespace manager +} // namespace software +} // namespace phosphor diff --git a/watch.hpp b/watch.hpp new file mode 100644 index 0000000..c125ef2 --- /dev/null +++ b/watch.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include + +namespace phosphor +{ +namespace software +{ +namespace manager +{ + +/** @class Watch + * + * @brief Adds inotify watch on software image upload directory + * + * The inotify watch is hooked up with sd-event, so that on call back, + * appropriate actions related to a software image upload can be taken. + */ +class Watch +{ + public: + /** @brief ctor - hook inotify watch with sd-event + * + * @param[in] loop - sd-event object + */ + Watch(sd_event* loop); + + Watch(const Watch&) = delete; + Watch& operator=(const Watch&) = delete; + Watch(Watch&&) = default; + Watch& operator=(Watch&&) = default; + + /** @brief dtor - remove inotify watch and close fd's + */ + ~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); + + /** @brief image upload directory watch descriptor */ + int wd = -1; + + /** @brief inotify file descriptor */ + int fd = -1; +}; + +} // namespace manager +} // namespace software +} // namespace phosphor -- cgit v1.2.1