blob: c3aa7e9401160b6bd8ec8c7e4cb8bd5b7301ebf0 [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
Gunnar Mills3027bba2017-04-27 15:49:03 -050024Watch::Watch(sd_event* loop,
25 std::function<int(std::string&)> imageCallback) : imageCallback(
26 imageCallback)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050027{
Gunnar Mills4e48fd52017-04-28 09:53:02 -050028 // Check if IMAGE DIR exists.
29 fs::path imgDirPath(IMG_UPLOAD_DIR);
30 if (!fs::is_directory(imgDirPath))
31 {
Gunnar Mills7e1abfc2017-11-09 15:43:50 -060032 fs::create_directories(imgDirPath);
Gunnar Mills4e48fd52017-04-28 09:53:02 -050033 }
34
Deepak Kodihalli059e2332017-04-12 06:40:53 -050035 fd = inotify_init1(IN_NONBLOCK);
36 if (-1 == fd)
37 {
38 // Store a copy of errno, because the string creation below will
39 // invalidate errno due to one more system calls.
40 auto error = errno;
41 throw std::runtime_error(
42 "inotify_init1 failed, errno="s + std::strerror(error));
43 }
44
Gunnar Mills368cfcb2017-04-27 16:13:17 -050045 wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050046 if (-1 == wd)
47 {
48 auto error = errno;
49 close(fd);
50 throw std::runtime_error(
51 "inotify_add_watch failed, errno="s + std::strerror(error));
52 }
53
54 auto rc = sd_event_add_io(loop,
55 nullptr,
56 fd,
57 EPOLLIN,
58 callback,
59 this);
60 if (0 > rc)
61 {
62 throw std::runtime_error(
63 "failed to add to event loop, rc="s + std::strerror(-rc));
64 }
65}
66
67Watch::~Watch()
68{
69 if ((-1 != fd) && (-1 != wd))
70 {
71 inotify_rm_watch(fd, wd);
72 close(fd);
73 }
74}
75
76int Watch::callback(sd_event_source* s,
77 int fd,
78 uint32_t revents,
79 void* userdata)
80{
81 if (!(revents & EPOLLIN))
82 {
83 return 0;
84 }
85
86 constexpr auto maxBytes = 1024;
87 uint8_t buffer[maxBytes];
88 auto bytes = read(fd, buffer, maxBytes);
89 if (0 > bytes)
90 {
91 auto error = errno;
92 throw std::runtime_error(
93 "failed to read inotify event, errno="s + std::strerror(error));
94 }
95
96 auto offset = 0;
97 while (offset < bytes)
98 {
99 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
Gunnar Mills368cfcb2017-04-27 16:13:17 -0500100 if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500101 {
Gunnar Mills3027bba2017-04-27 15:49:03 -0500102 auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
103 auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -0500104 if (rc < 0)
105 {
106 log<level::ERR>("Error processing image",
Gunnar Mills3027bba2017-04-27 15:49:03 -0500107 entry("IMAGE=%s", tarballPath));
Gunnar Millse91d3212017-04-19 15:42:47 -0500108 }
109
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500110 }
111
112 offset += offsetof(inotify_event, name) + event->len;
113 }
114
115 return 0;
116}
117
118} // namespace manager
119} // namespace software
120} // namespace phosphor