aboutsummaryrefslogtreecommitdiff
path: root/src/watcher.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2012-12-22 21:39:23 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2012-12-22 21:54:43 +0200
commit67a64a6a7809c183516740696e15ab88f82d7ef0 (patch)
treeb58f30a8cee98bac7c9f4bc8236c86eefdadb4ef /src/watcher.c
parent2c28190e77ce38b6437a2be8337680f77f58d37a (diff)
downloadwydawca-67a64a6a7809c183516740696e15ab88f82d7ef0.tar.gz
wydawca-67a64a6a7809c183516740696e15ab88f82d7ef0.tar.bz2
Implement inotify support.
* configure.ac: New option --with-inotify. Bye default, use inotify if it is present. * src/watcher.c: New file. Implements inotify watcher. * src/Makefile.am [COND_INOTIFY] (wydawca_SOURCES): Add watcher.c * src/diskio.c (dir_get_path): New function. * src/job.c (job) <spool>: Remove const qualifier. All uses changed. (inotify_spool): New pseudo-spool. (fake_spool): Remove static qualifier. (wydawca_scanner): Support for inotify spools. * src/net.c (open_listener): Don't exit if the listener address is not set. (wydawca_listener): Listen on the listener socket and on the inotify descriptor. If none is set, bail out. * src/process.c (for_each_spool) (file_info_cleanup) (spool_cwd_add_new_file,spool_add_new_file): New functions. (scan_spool_unlocked): Use spool_cwd_add_new_file. Don't initialize dictionaries here: it will be done in spool_commit_triplets. (spool_open_dictionaries): New function. (close_dictionaries): Rename to spool_close_dictionaries. Clear dict_inited. * src/triplet.c (hash_triplet_compare): Compare spools as well. (register_file): Likewise. (triplet_lookup): New function. (check_triplet_state): New argument: noauth. All uses updated. (enumerate_triplets): Rename to spool_commit_triplets. Call spool_open_dictionaries. (count_processable_triplets,triplet_remove_file): New functions. * src/verify.c (verify_directive_file): New argument: noauth. All uses updated. * src/vtab.c (reg): Initialize get_path member. (get_path): New function. * src/wydawca.c (main): Set print_version_hook. * src/wydawca.h (virt_tab) <get_path>: New method. (spool) <dict_inited>: New member. (fake_spool, inotify_spool): New externs. (spool_add_new_file, spool_cwd_add_new_file) (spool_open_dictionaries, spool_close_dictionaries) (for_each_spool, count_processable_triplets) (triplet_remove_file, get_path): New protos. (enumerate_triplets): Rename to spool_commit_triplets. (verify_directive_file): Take two arguments.
Diffstat (limited to 'src/watcher.c')
-rw-r--r--src/watcher.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/src/watcher.c b/src/watcher.c
new file mode 100644
index 0000000..f8761ee
--- /dev/null
+++ b/src/watcher.c
@@ -0,0 +1,243 @@
1/* wydawca - automatic release submission daemon
2 Copyright (C) 2007, 2009-2012 Sergey Poznyakoff
3
4 Wydawca is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 Wydawca is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with wydawca. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "wydawca.h"
18#include <sys/inotify.h>
19#include <sys/ioctl.h>
20
21/* A directory watcher is described by the following structure */
22struct dirwatcher
23{
24 struct dirwatcher *next, *prev;
25 struct dirwatcher *parent; /* Points to the parent watcher.
26 NULL for top-level watchers */
27 struct spool *spool;
28 int wd; /* Watch descriptor */
29};
30
31static struct dirwatcher *dirwatcher_list;
32
33struct dirwatcher *
34dirwatcher_unlink(struct dirwatcher **root, struct dirwatcher *p)
35{
36 if (p->prev)
37 p->prev->next = p->next;
38 else
39 *root = p->next;
40 if (p->next)
41 p->next->prev = p->prev;
42 p->next = p->prev = NULL;
43 return p;
44}
45
46struct dirwatcher *
47dirwatcher_pop(struct dirwatcher **pp)
48{
49 if (*pp)
50 return dirwatcher_unlink(pp, *pp);
51 return NULL;
52}
53
54static void
55dirwatcher_push(struct dirwatcher **pp, struct dirwatcher *p)
56{
57 p->prev = NULL;
58 p->next = *pp;
59 if (*pp)
60 (*pp)->prev = p;
61 *pp = p;
62}
63
64/* Find a watcher with the given descriptor */
65static struct dirwatcher *
66dirwatcher_find_wd (int wd)
67{
68 struct dirwatcher *dwp;
69
70 for (dwp = dirwatcher_list; dwp; dwp = dwp->next)
71 if (dwp->wd == wd)
72 break;
73 return dwp;
74}
75
76static int
77create_watcher (struct spool *sp, void *data)
78{
79 int ifd = *(int*)data;
80 struct dirwatcher *dwp;
81 int wd;
82 const char *path = get_path (sp);
83
84 if (!sp)
85 return 0;
86
87 if (debug_level > 1)
88 logmsg (LOG_DEBUG, "creating watcher %s", path);
89 dwp = malloc (sizeof(*dwp));
90 if (!dwp)
91 {
92 logmsg (LOG_ERR, "not enough memory");
93 return 1;
94 }
95 dwp->spool = sp;
96 dwp->parent = NULL;
97
98 wd = inotify_add_watch (ifd, path, IN_DELETE|IN_CREATE|IN_CLOSE_WRITE|
99 IN_MOVED_FROM|IN_MOVED_TO);
100 if (wd == -1)
101 {
102 logmsg (LOG_ERR, "cannot set watch on %s: %s", path, strerror (errno));
103 free (dwp);
104 return 1;
105 }
106
107 dwp->wd = wd;
108 dirwatcher_push (&dirwatcher_list, dwp);
109 return 0;
110}
111
112int
113watcher_init ()
114{
115 int ifd, rc;
116
117 if (debug_level > 1)
118 logmsg (LOG_DEBUG, "setting up inotify");
119 ifd = inotify_init ();
120 if (ifd == -1)
121 {
122 logmsg (LOG_ERR, "inotify_init: %s", strerror (errno));
123 return -1;
124 }
125
126 rc = for_each_spool (create_watcher, &ifd);
127 if (rc)
128 exit (EX_OSERR);
129 if (!dirwatcher_list)
130 {
131 if (debug_level > 1)
132 logmsg (LOG_DEBUG, "inotify: nothing to watch");
133 close (ifd);
134 ifd = -1;
135 }
136 else if (debug_level > 1)
137 logmsg (LOG_DEBUG, "inotify initialized successfully");
138
139 return ifd;
140}
141
142static void
143process_event (struct inotify_event *ep)
144{
145 static struct dirwatcher *dwp;
146 dwp = dirwatcher_find_wd (ep->wd);
147
148 if (ep->mask & IN_IGNORED)
149 /* nothing */;
150 else if (ep->mask & IN_Q_OVERFLOW)
151 logmsg (LOG_NOTICE, "event queue overflow");
152 else if (ep->mask & IN_UNMOUNT)
153 /* FIXME: not sure if there's
154 anything to do. Perhaps we should
155 deregister the watched dirs that
156 were located under the mountpoint
157 */;
158 else if (!dwp)
159 {
160 if (ep->name)
161 logmsg (LOG_NOTICE, "unrecognized event %x for %s",
162 ep->mask, ep->name);
163 else
164 logmsg (LOG_NOTICE, "unrecognized event %x", ep->mask);
165 }
166 else if (ep->mask & IN_CREATE)
167 {
168 if (debug_level > 0)
169 logmsg (LOG_DEBUG, "%s/%s created", dwp->spool->source_dir, ep->name);
170 }
171 else if (ep->mask & (IN_DELETE|IN_MOVED_FROM))
172 {
173 if (debug_level > 0)
174 logmsg (LOG_DEBUG, "%s/%s %s", dwp->spool->source_dir, ep->name,
175 ep->mask & IN_DELETE ? "deleted" : "moved out");
176 triplet_remove_file (dwp->spool, ep->name);
177 }
178 else if (ep->mask & (IN_CLOSE_WRITE|IN_MOVED_TO))
179 {
180 if (debug_level > 0)
181 logmsg (LOG_DEBUG, "%s/%s written", dwp->spool->source_dir, ep->name);
182 if (spool_add_new_file (dwp->spool, ep->name, 0, NULL) == 0 &&
183 count_processable_triplets ())
184 schedule_job (&inotify_spool, getuid ());
185 }
186 else
187 logmsg (LOG_NOTICE, "%s/%s: unexpected event %x",
188 dwp->spool->source_dir, ep->name, ep->mask);
189}
190
191static char buffer[4096];
192static int offset;
193
194int
195watcher_run (int ifd)
196{
197 int n;
198 int rdbytes;
199
200 if (ioctl (ifd, FIONREAD, &n))
201 {
202 logmsg (LOG_ERR, "ioctl: %s", strerror (errno));
203 return -1;
204 }
205 if (offset + n > sizeof buffer)
206 n = sizeof buffer - offset;
207 if (n)
208 {
209 rdbytes = read (ifd, buffer + offset, n);
210 if (rdbytes == -1)
211 {
212 if (errno == EINTR)
213 {
214 //FIXME logmsg (LOG_NOTICE, "got signal %d", signo);
215 return 0;
216 }
217
218 logmsg (LOG_NOTICE, "read failed: %s", strerror (errno));
219 return -1;
220 }
221 }
222 offset += n;
223
224 for (n = 0; offset - n >= sizeof (struct inotify_event); )
225 {
226 struct inotify_event *ep;
227 size_t size;
228
229 ep = (struct inotify_event *) (buffer + n);
230 size = sizeof(*ep) + ep->len;
231 if (offset - n < size)
232 break;
233
234 process_event (ep);
235
236 n += size;
237 }