blob: 9921bbd3074c27e79517024a54b8eba32f176130 [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 {
32 log<level::ERR>("ERROR No Image Dir",
33 entry("IMAGEDIR=%s", IMG_UPLOAD_DIR));
34 throw std::runtime_error(
35 "No Image Dir, IMAGEDIR=" + std::string{IMG_UPLOAD_DIR});
36 }
37
Deepak Kodihalli059e2332017-04-12 06:40:53 -050038 fd = inotify_init1(IN_NONBLOCK);
39 if (-1 == fd)
40 {
41 // Store a copy of errno, because the string creation below will
42 // invalidate errno due to one more system calls.
43 auto error = errno;
44 throw std::runtime_error(
45 "inotify_init1 failed, errno="s + std::strerror(error));
46 }
47
Gunnar Mills368cfcb2017-04-27 16:13:17 -050048 wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050049 if (-1 == wd)
50 {
51 auto error = errno;
52 close(fd);
53 throw std::runtime_error(
54 "inotify_add_watch failed, errno="s + std::strerror(error));
55 }
56
57 auto rc = sd_event_add_io(loop,
58 nullptr,
59 fd,
60 EPOLLIN,
61 callback,
62 this);
63 if (0 > rc)
64 {
65 throw std::runtime_error(
66 "failed to add to event loop, rc="s + std::strerror(-rc));
67 }
68}
69
70Watch::~Watch()
71{
72 if ((-1 != fd) && (-1 != wd))
73 {
74 inotify_rm_watch(fd, wd);
75 close(fd);
76 }
77}
78
79int Watch::callback(sd_event_source* s,
80 int fd,
81 uint32_t revents,
82 void* userdata)
83{
84 if (!(revents & EPOLLIN))
85 {
86 return 0;
87 }
88
89 constexpr auto maxBytes = 1024;
90 uint8_t buffer[maxBytes];
91 auto bytes = read(fd, buffer, maxBytes);
92 if (0 > bytes)
93 {
94 auto error = errno;
95 throw std::runtime_error(
96 "failed to read inotify event, errno="s + std::strerror(error));
97 }
98
99 auto offset = 0;
100 while (offset < bytes)
101 {
102 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
Gunnar Mills368cfcb2017-04-27 16:13:17 -0500103 if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500104 {
Gunnar Mills3027bba2017-04-27 15:49:03 -0500105 auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
106 auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -0500107 if (rc < 0)
108 {
109 log<level::ERR>("Error processing image",
Gunnar Mills3027bba2017-04-27 15:49:03 -0500110 entry("IMAGE=%s", tarballPath));
Gunnar Millse91d3212017-04-19 15:42:47 -0500111 }
112
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500113 }
114
115 offset += offsetof(inotify_event, name) + event->len;
116 }
117
118 return 0;
119}
120
121} // namespace manager
122} // namespace software
123} // namespace phosphor