blob: 2ad8c4c88f7c440a446207f5992fd2405423e538 [file] [log] [blame]
Deepak Kodihalli059e2332017-04-12 06:40:53 -05001#include <stdexcept>
2#include <cstddef>
3#include <cstring>
4#include <string>
5#include <sys/inotify.h>
6#include <unistd.h>
Gunnar Mills4e48fd52017-04-28 09:53:02 -05007#include <experimental/filesystem>
Deepak Kodihalli059e2332017-04-12 06:40:53 -05008#include <phosphor-logging/log.hpp>
9#include "config.h"
10#include "watch.hpp"
Gunnar Millse91d3212017-04-19 15:42:47 -050011#include "image_manager.hpp"
Deepak Kodihalli059e2332017-04-12 06:40:53 -050012
13namespace phosphor
14{
15namespace software
16{
17namespace manager
18{
19
Gunnar Millse91d3212017-04-19 15:42:47 -050020using namespace phosphor::logging;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050021using namespace std::string_literals;
Gunnar Mills4e48fd52017-04-28 09:53:02 -050022namespace fs = std::experimental::filesystem;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050023
Adriana Kobylak2285fe02018-02-27 15:36:59 -060024Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
25 imageCallback(imageCallback)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050026{
Gunnar Mills4e48fd52017-04-28 09:53:02 -050027 // Check if IMAGE DIR exists.
28 fs::path imgDirPath(IMG_UPLOAD_DIR);
29 if (!fs::is_directory(imgDirPath))
30 {
Gunnar Mills7e1abfc2017-11-09 15:43:50 -060031 fs::create_directories(imgDirPath);
Gunnar Mills4e48fd52017-04-28 09:53:02 -050032 }
33
Deepak Kodihalli059e2332017-04-12 06:40:53 -050034 fd = inotify_init1(IN_NONBLOCK);
35 if (-1 == fd)
36 {
37 // Store a copy of errno, because the string creation below will
38 // invalidate errno due to one more system calls.
39 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060040 throw std::runtime_error("inotify_init1 failed, errno="s +
41 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050042 }
43
Gunnar Mills368cfcb2017-04-27 16:13:17 -050044 wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050045 if (-1 == wd)
46 {
47 auto error = errno;
48 close(fd);
Adriana Kobylak2285fe02018-02-27 15:36:59 -060049 throw std::runtime_error("inotify_add_watch failed, errno="s +
50 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050051 }
52
Adriana Kobylak2285fe02018-02-27 15:36:59 -060053 auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050054 if (0 > rc)
55 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -060056 throw std::runtime_error("failed to add to event loop, rc="s +
57 std::strerror(-rc));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050058 }
59}
60
61Watch::~Watch()
62{
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070063 if (-1 != fd)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050064 {
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070065 if (-1 != wd)
66 {
67 inotify_rm_watch(fd, wd);
68 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -050069 close(fd);
70 }
71}
72
Adriana Kobylak2285fe02018-02-27 15:36:59 -060073int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
Deepak Kodihalli059e2332017-04-12 06:40:53 -050074 void* userdata)
75{
76 if (!(revents & EPOLLIN))
77 {
78 return 0;
79 }
80
81 constexpr auto maxBytes = 1024;
82 uint8_t buffer[maxBytes];
83 auto bytes = read(fd, buffer, maxBytes);
84 if (0 > bytes)
85 {
86 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060087 throw std::runtime_error("failed to read inotify event, errno="s +
88 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050089 }
90
91 auto offset = 0;
92 while (offset < bytes)
93 {
94 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
Gunnar Mills368cfcb2017-04-27 16:13:17 -050095 if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
Deepak Kodihalli059e2332017-04-12 06:40:53 -050096 {
Gunnar Mills3027bba2017-04-27 15:49:03 -050097 auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
98 auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -050099 if (rc < 0)
100 {
101 log<level::ERR>("Error processing image",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600102 entry("IMAGE=%s", tarballPath.c_str()));
Gunnar Millse91d3212017-04-19 15:42:47 -0500103 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500104 }
105
106 offset += offsetof(inotify_event, name) + event->len;
107 }
108
109 return 0;
110}
111
112} // namespace manager
113} // namespace software
114} // namespace phosphor