Krolyxon
Commit 9ac8fc6

Branches

Refs →

nsxivautoreload_inotify.c

135 lines · 3.5 KB · C

1/* Copyright 2017 Max Voit
2 *
3 * This file is part of sxiv.
4 *
5 * sxiv is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License,
8 * or (at your option) any later version.
9 *
10 * sxiv is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22#include <sys/inotify.h>
23#include <libgen.h>
24
25#include "util.h"
26#include "autoreload.h"
27
28CLEANUP void arl_cleanup(arl_t *arl)
29{
30 if (arl->fd != -1 && arl->wd != -1) {
31 if (inotify_rm_watch(arl->fd, arl->wd))
32 error(0, 0, "Failed to remove inotify watch.");
33 }
34}
35
36static void arl_setup_dir(arl_t *arl, const char *filepath)
37{
38 char *dntmp, *dn;
39
40 if (arl->fd == -1) {
41 error(0, 0, "Uninitialized, could not add inotify watch on directory.");
42 return;
43 }
44
45 /* get dirname */
46 dntmp = (char*) strdup(filepath);
47 dn = (char*) dirname(dntmp);
48
49 /* this is not one-shot as other stuff may be created too
50 * note: we won't handle deletion of the directory itself,
51 * this is a design decision
52 */
53 arl->wd = inotify_add_watch(arl->fd, dn, IN_CREATE);
54 if (arl->wd == -1)
55 error(0, 0, "Failed to add inotify watch on directory '%s'.", dn);
56 else
57 arl->watching_dir = true;
58
59 free(dntmp);
60}
61
62bool arl_handle(arl_t *arl, const char *filepath)
63{
64 bool reload = false;
65 char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
66 char *ptr;
67 const struct inotify_event *event;
68
69 ssize_t len = read(arl->fd, buf, sizeof(buf));
70
71 if (len == -1) {
72 error(0, 0, "Failed to read inotify events.");
73 return false;
74 }
75 for (ptr = buf; ptr < buf + len; ptr += sizeof(*event) + event->len) {
76 event = (const struct inotify_event*) ptr;
77
78 /* events from watching the file itself */
79 if (event->mask & IN_CLOSE_WRITE) {
80 reload = true;
81 }
82 if (event->mask & IN_DELETE_SELF)
83 arl_setup_dir(arl, filepath);
84
85 /* events from watching the file's directory */
86 if (event->mask & IN_CREATE) {
87 char *fntmp = strdup(filepath);
88 char *fn = basename(fntmp);
89
90 if (STREQ(event->name, fn)) {
91 /* this is the file we're looking for */
92
93 /* cleanup, this has not been one-shot */
94 if (arl->watching_dir) {
95 if (inotify_rm_watch(arl->fd, arl->wd))
96 error(0, 0, "Failed to remove inotify watch.");
97 arl->watching_dir = false;
98 }
99 reload = true;
100 }
101 free(fntmp);
102 }
103 }
104 return reload;
105}
106
107void arl_init(arl_t *arl)
108{
109 /* this needs to be done only once */
110 arl->fd = inotify_init();
111 arl->watching_dir = false;
112 if (arl->fd == -1)
113 error(0, 0, "Could not initialize inotify.");
114}
115
116void arl_setup(arl_t *arl, const char *filepath)
117{
118 if (arl->fd == -1) {
119 error(0, 0, "Uninitialized, could not add inotify watch.");
120 return;
121 }
122
123 /* may have switched from a deleted to another image */
124 if (arl->watching_dir) {
125 if (inotify_rm_watch(arl->fd, arl->wd))
126 error(0, 0, "Failed to remove inotify watch.");
127 arl->watching_dir = false;
128 }
129
130 arl->wd = inotify_add_watch(arl->fd, filepath,
131 IN_ONESHOT | IN_CLOSE_WRITE | IN_DELETE_SELF);
132 if (arl->wd == -1)
133 error(0, 0, "Failed to add inotify watch on file '%s'.", filepath);
134}
135