-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/diskio.c | 6 | ||||
-rw-r--r-- | src/job.c | 18 | ||||
-rw-r--r-- | src/net.c | 87 | ||||
-rw-r--r-- | src/process.c | 162 | ||||
-rw-r--r-- | src/triplet.c | 104 | ||||
-rw-r--r-- | src/verify.c | 175 | ||||
-rw-r--r-- | src/vtab.c | 18 | ||||
-rw-r--r-- | src/watcher.c | 243 | ||||
-rw-r--r-- | src/wydawca.c | 14 | ||||
-rw-r--r-- | src/wydawca.h | 49 |
11 files changed, 683 insertions, 201 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 73182c4..828d573 100644 --- a/src/Makefile.am +++ b/src/Makefile.am | |||
@@ -15,6 +15,11 @@ | |||
15 | # along with Wydawca. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with Wydawca. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | ||
17 | sbin_PROGRAMS=wydawca | 17 | sbin_PROGRAMS=wydawca |
18 | |||
19 | if COND_INOTIFY | ||
20 | WATCHER_C=watcher.c | ||
21 | endif | ||
22 | |||
18 | wydawca_SOURCES=\ | 23 | wydawca_SOURCES=\ |
19 | backup.c\ | 24 | backup.c\ |
20 | builtin.c\ | 25 | builtin.c\ |
@@ -48,7 +53,8 @@ wydawca_SOURCES=\ | |||
48 | null.c\ | 53 | null.c\ |
49 | timer.c\ | 54 | timer.c\ |
50 | txtacc.c\ | 55 | txtacc.c\ |
51 | report.c | 56 | report.c\ |
57 | $(WATCHER_C) | ||
52 | 58 | ||
53 | BUILT_SOURCES=cmdline.h | 59 | BUILT_SOURCES=cmdline.h |
54 | EXTRA_DIST=cmdline.opt pp-setup update-2.0.awk | 60 | EXTRA_DIST=cmdline.opt pp-setup update-2.0.awk |
diff --git a/src/diskio.c b/src/diskio.c index bab5cb8..751d684 100644 --- a/src/diskio.c +++ b/src/diskio.c | |||
@@ -411,6 +411,12 @@ replace_allowed_p (struct file_triplet *trp) | |||
411 | return strcmp (val, "true") == 0; | 411 | return strcmp (val, "true") == 0; |
412 | } | 412 | } |
413 | 413 | ||
414 | const char * | ||
415 | dir_get_path (struct spool *sp) | ||
416 | { | ||
417 | return sp->source_dir; | ||
418 | } | ||
419 | |||
414 | /* Move the part FILE_ID of the triplet TRP between the directories in | 420 | /* Move the part FILE_ID of the triplet TRP between the directories in |
415 | TRP->SPOOL. TRP->RELATIVE_DIR gives relative directory (i.e. the | 421 | TRP->SPOOL. TRP->RELATIVE_DIR gives relative directory (i.e. the |
416 | directory part of the file name) for backup purposes. | 422 | directory part of the file name) for backup purposes. |
@@ -25,7 +25,7 @@ struct job | |||
25 | { | 25 | { |
26 | struct job *next, *prev; | 26 | struct job *next, *prev; |
27 | int state; | 27 | int state; |
28 | const struct spool *spool; | 28 | struct spool *spool; |
29 | uid_t uid; | 29 | uid_t uid; |
30 | pid_t pid; | 30 | pid_t pid; |
31 | time_t timestamp; | 31 | time_t timestamp; |
@@ -36,7 +36,8 @@ struct job *queue; | |||
36 | size_t jobmax; | 36 | size_t jobmax; |
37 | size_t jobcnt; | 37 | size_t jobcnt; |
38 | 38 | ||
39 | static struct spool fake_spool = { "all spools" }; | 39 | struct spool fake_spool = { "all spools" }, |
40 | inotify_spool = { "inotify" } ; | ||
40 | 41 | ||
41 | static int wakeup; | 42 | static int wakeup; |
42 | 43 | ||
@@ -76,13 +77,22 @@ job_active_count () | |||
76 | return count; | 77 | return count; |
77 | } | 78 | } |
78 | 79 | ||
80 | static int | ||
81 | procspool (struct spool *spool, void *data) | ||
82 | { | ||
83 | spool_commit_triplets (spool); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
79 | int | 87 | int |
80 | wydawca_scanner (struct job *job) | 88 | wydawca_scanner (struct job *job) |
81 | { | 89 | { |
82 | int rc; | 90 | int rc; |
83 | initstats(); | 91 | initstats(); |
84 | timer_start ("wydawca"); | 92 | timer_start ("wydawca"); |
85 | if (job->spool == &fake_spool) | 93 | if (job->spool == &inotify_spool) |
94 | rc = for_each_spool (procspool, NULL); | ||
95 | else if (job->spool == &fake_spool) | ||
86 | rc = scan_all_spools (1, &job->uid); | 96 | rc = scan_all_spools (1, &job->uid); |
87 | else | 97 | else |
88 | { | 98 | { |
@@ -191,7 +201,7 @@ job_insert (struct job *job, struct job *elt) | |||
191 | } | 201 | } |
192 | 202 | ||
193 | void | 203 | void |
194 | schedule_job (const struct spool *spool, uid_t uid) | 204 | schedule_job (struct spool *spool, uid_t uid) |
195 | { | 205 | { |
196 | struct job *job; | 206 | struct job *job; |
197 | 207 | ||
@@ -22,10 +22,7 @@ open_listener () | |||
22 | int fd; | 22 | int fd; |
23 | 23 | ||
24 | if (listen_sockaddr.sa == NULL) | 24 | if (listen_sockaddr.sa == NULL) |
25 | { | 25 | return -1; |
26 | logmsg (LOG_CRIT, _("listener address is not configured")); | ||
27 | exit (EX_CONFIG); | ||
28 | } | ||
29 | 26 | ||
30 | fd = socket (listen_sockaddr.sa->sa_family, SOCK_STREAM, 0); | 27 | fd = socket (listen_sockaddr.sa->sa_family, SOCK_STREAM, 0); |
31 | if (fd == -1) | 28 | if (fd == -1) |
@@ -99,7 +96,7 @@ handle_connection (FILE *in, FILE *out) | |||
99 | { | 96 | { |
100 | char *buf = NULL; | 97 | char *buf = NULL; |
101 | size_t buflen = 0; | 98 | size_t buflen = 0; |
102 | const struct spool *spool; | 99 | struct spool *spool; |
103 | char *p; | 100 | char *p; |
104 | struct passwd *pw; | 101 | struct passwd *pw; |
105 | 102 | ||
@@ -174,7 +171,22 @@ void | |||
174 | wydawca_listener () | 171 | wydawca_listener () |
175 | { | 172 | { |
176 | int ctlfd = open_listener (); | 173 | int ctlfd = open_listener (); |
174 | int wfd = watcher_init (); | ||
175 | int maxfd = 0; | ||
176 | |||
177 | if (ctlfd != -1) | ||
178 | maxfd = ctlfd; | ||
179 | |||
180 | if (wfd != -1 && wfd > maxfd) | ||
181 | maxfd = wfd; | ||
177 | 182 | ||
183 | if (maxfd == 0) | ||
184 | { | ||
185 | logmsg (LOG_CRIT, | ||
186 | _("listener address is not configured and inotify is not available")); | ||
187 | exit (EX_CONFIG); | ||
188 | } | ||
189 | |||
178 | job_init (); | 190 | job_init (); |
179 | signal (SIGHUP, sig_hup); | 191 | signal (SIGHUP, sig_hup); |
180 | signal (SIGTERM, sig_term); | 192 | signal (SIGTERM, sig_term); |
@@ -182,21 +194,16 @@ wydawca_listener () | |||
182 | signal (SIGINT, sig_term); | 194 | signal (SIGINT, sig_term); |
183 | while (!terminate) | 195 | while (!terminate) |
184 | { | 196 | { |
185 | int fd; | ||
186 | FILE *in, *out; | ||
187 | int rc; | 197 | int rc; |
188 | fd_set rset; | 198 | fd_set rset; |
189 | struct timeval to, *pto; | 199 | struct timeval to, *pto; |
190 | union { | ||
191 | struct sockaddr sa; | ||
192 | struct sockaddr_in s_in; | ||
193 | struct sockaddr_un s_un; | ||
194 | } addr; | ||
195 | socklen_t len; | ||
196 | 200 | ||
197 | job_queue_runner (); | 201 | job_queue_runner (); |
198 | FD_ZERO (&rset); | 202 | FD_ZERO (&rset); |
199 | FD_SET (ctlfd, &rset); | 203 | if (ctlfd != -1) |
204 | FD_SET (ctlfd, &rset); | ||
205 | if (wfd != -1) | ||
206 | FD_SET (wfd, &rset); | ||
200 | 207 | ||
201 | if (wakeup_interval) | 208 | if (wakeup_interval) |
202 | { | 209 | { |
@@ -207,7 +214,7 @@ wydawca_listener () | |||
207 | else | 214 | else |
208 | pto = NULL; | 215 | pto = NULL; |
209 | 216 | ||
210 | rc = select (ctlfd + 1, &rset, NULL, NULL, pto); | 217 | rc = select (maxfd + 1, &rset, NULL, NULL, pto); |
211 | if (rc == 0) | 218 | if (rc == 0) |
212 | continue; | 219 | continue; |
213 | else if (rc < 0) | 220 | else if (rc < 0) |
@@ -218,26 +225,44 @@ wydawca_listener () | |||
218 | break; | 225 | break; |
219 | } | 226 | } |
220 | 227 | ||
221 | len = sizeof (addr); | 228 | if (wfd != -1 && FD_ISSET (wfd, &rset)) |
222 | fd = accept (ctlfd, (struct sockaddr*) &addr, &len); | ||
223 | if (fd == -1) | ||
224 | continue; | ||
225 | /* FIXME: Use Mailutils ACLs? */ | ||
226 | #ifdef WITH_LIBWRAP | ||
227 | if (!tcpwrap_access(fd)) | ||
228 | { | 229 | { |
229 | close(fd); | 230 | watcher_run (wfd); |
230 | continue; | ||
231 | } | 231 | } |
232 | |||
233 | if (ctlfd != -1 && FD_ISSET (ctlfd, &rset)) | ||
234 | { | ||
235 | int fd; | ||
236 | FILE *in, *out; | ||
237 | union | ||
238 | { | ||
239 | struct sockaddr sa; | ||
240 | struct sockaddr_in s_in; | ||
241 | struct sockaddr_un s_un; | ||
242 | } addr; | ||
243 | socklen_t len; | ||
244 | |||
245 | len = sizeof (addr); | ||
246 | fd = accept (ctlfd, (struct sockaddr*) &addr, &len); | ||
247 | if (fd == -1) | ||
248 | continue; | ||
249 | /* FIXME: Use Mailutils ACLs? */ | ||
250 | #ifdef WITH_LIBWRAP | ||
251 | if (!tcpwrap_access(fd)) | ||
252 | { | ||
253 | close(fd); | ||
254 | continue; | ||
255 | } | ||
232 | #endif | 256 | #endif |
233 | 257 | ||
234 | in = fdopen (fd, "r"); | 258 | in = fdopen (fd, "r"); |
235 | setlinebuf (in); | 259 | setlinebuf (in); |
236 | out = fdopen (fd, "w"); | 260 | out = fdopen (fd, "w"); |
237 | setlinebuf (out); | 261 | setlinebuf (out); |
238 | handle_connection (in, out); | 262 | handle_connection (in, out); |
239 | fclose (in); | 263 | fclose (in); |
240 | fclose (out); | 264 | fclose (out); |
265 | } | ||
241 | } | 266 | } |
242 | } | 267 | } |
243 | 268 | ||
diff --git a/src/process.c b/src/process.c index c5eb321..ec64589 100644 --- a/src/process.c +++ b/src/process.c | |||
@@ -24,6 +24,20 @@ struct spool_list | |||
24 | 24 | ||
25 | static struct spool_list *spool_list; | 25 | static struct spool_list *spool_list; |
26 | 26 | ||
27 | int | ||
28 | for_each_spool (int (*fun) (struct spool *, void *), void *data) | ||
29 | { | ||
30 | struct spool_list *sp; | ||
31 | |||
32 | for (sp = spool_list; sp; sp = sp->next) | ||
33 | { | ||
34 | int rc = fun (&sp->spool, data); | ||
35 | if (rc) | ||
36 | return rc; | ||
37 | } | ||
38 | return 0; | ||
39 | } | ||
40 | |||
27 | void | 41 | void |
28 | register_spool (struct spool *spool) | 42 | register_spool (struct spool *spool) |
29 | { | 43 | { |
@@ -122,7 +136,14 @@ parse_file_name (const char *name, struct file_info *finfo) | |||
122 | abort (); /* should not happen */ | 136 | abort (); /* should not happen */ |
123 | } | 137 | } |
124 | 138 | ||
125 | int | 139 | void |
140 | file_info_cleanup (struct file_info *finfo) | ||
141 | { | ||
142 | free (finfo->name); | ||
143 | memset (finfo, 0, sizeof (*finfo)); | ||
144 | } | ||
145 | |||
146 | static int | ||
126 | match_uid_p (uid_t uid, int uc, uid_t *uv) | 147 | match_uid_p (uid_t uid, int uc, uid_t *uv) |
127 | { | 148 | { |
128 | int i; | 149 | int i; |
@@ -134,10 +155,67 @@ match_uid_p (uid_t uid, int uc, uid_t *uv) | |||
134 | return 0; | 155 | return 0; |
135 | } | 156 | } |
136 | 157 | ||
158 | int | ||
159 | spool_cwd_add_new_file (const struct spool *spool, const char *name, | ||
160 | int uc, uid_t *uv) | ||
161 | { | ||
162 | struct stat st; | ||
163 | struct file_info finfo; | ||
164 | |||
165 | if (stat (name, &st)) | ||
166 | { | ||
167 | logmsg (LOG_ERR, _("cannot stat file %s/%s: %s"), | ||
168 | spool->source_dir, name, strerror (errno)); | ||
169 | return -1; | ||
170 | } | ||
171 | |||
172 | if (!S_ISREG (st.st_mode)) | ||
173 | { | ||
174 | logmsg (LOG_NOTICE, _("not a regular file: %s/%s"), | ||
175 | spool->source_dir, name); | ||
176 | return -1; | ||
177 | } | ||
178 | |||
179 | if (!match_uid_p (st.st_uid, uc, uv)) | ||
180 | { | ||
181 | if (debug_level) | ||
182 | logmsg (LOG_DEBUG, _("ignoring file: %s/%s"), | ||
183 | spool->source_dir, name); | ||
184 | return -1; | ||
185 | } | ||
186 | |||
187 | finfo.sb = st; | ||
188 | parse_file_name (name, &finfo); | ||
189 | |||
190 | if (debug_level) | ||
191 | logmsg (LOG_DEBUG, _("found file %s: %s, stem: %.*s"), name, | ||
192 | file_type_str (finfo.type), finfo.root_len, finfo.name); | ||
193 | |||
194 | register_file (&finfo, spool); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | int | ||
199 | spool_add_new_file (const struct spool *spool, const char *name, | ||
200 | int uc, uid_t *uv) | ||
201 | { | ||
202 | if (debug_level) | ||
203 | logmsg (LOG_DEBUG, "%s -> %s, adding %s", spool->source_dir, | ||
204 | mu_url_to_string (spool->dest_url), name); | ||
205 | |||
206 | if (chdir (spool->source_dir)) | ||
207 | { | ||
208 | logmsg (LOG_ERR, _("cannot chdir to %s: %s"), spool->source_dir, | ||
209 | strerror (errno)); | ||
210 | return -1; | ||
211 | } | ||
212 | return spool_cwd_add_new_file (spool, name, uc, uv); | ||
213 | } | ||
214 | |||
137 | /* Scan upload directory from the DPAIR and register all files found | 215 | /* Scan upload directory from the DPAIR and register all files found |
138 | there, forming triplets when possible */ | 216 | there, forming triplets when possible */ |
139 | void | 217 | void |
140 | scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv) | 218 | scan_spool_unlocked (struct spool *spool, int uc, uid_t *uv) |
141 | { | 219 | { |
142 | DIR *dir; | 220 | DIR *dir; |
143 | struct dirent *ent; | 221 | struct dirent *ent; |
@@ -166,67 +244,22 @@ scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv) | |||
166 | timer_start (spool->tag); | 244 | timer_start (spool->tag); |
167 | while ((ent = readdir (dir))) | 245 | while ((ent = readdir (dir))) |
168 | { | 246 | { |
169 | struct stat st; | ||
170 | struct file_info finfo; | ||
171 | |||
172 | if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) | 247 | if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0) |
173 | continue; | 248 | continue; |
174 | 249 | spool_cwd_add_new_file (spool, ent->d_name, uc, uv); | |
175 | if (stat (ent->d_name, &st)) | ||
176 | { | ||
177 | logmsg (LOG_ERR, _("cannot stat file %s/%s: %s"), | ||
178 | spool->source_dir, ent->d_name, | ||
179 | strerror (errno)); | ||
180 | continue; | ||
181 | } | ||
182 | |||
183 | if (!S_ISREG (st.st_mode)) | ||
184 | { | ||
185 | logmsg (LOG_NOTICE, _("not a regular file: %s/%s"), | ||
186 | spool->source_dir, ent->d_name); | ||
187 | continue; | ||
188 | } | ||
189 | |||
190 | if (!match_uid_p (st.st_uid, uc, uv)) | ||
191 | { | ||
192 | if (debug_level) | ||
193 | logmsg (LOG_DEBUG, _("ignoring file: %s/%s"), | ||
194 | spool->source_dir, ent->d_name); | ||
195 | continue; | ||
196 | } | ||
197 | |||
198 | finfo.sb = st; | ||
199 | parse_file_name (ent->d_name, &finfo); | ||
200 | |||
201 | if (debug_level) | ||
202 | logmsg (LOG_DEBUG, _("found file %s: %s, stem: %.*s"), ent->d_name, | ||
203 | file_type_str (finfo.type), finfo.root_len, finfo.name); | ||
204 | |||
205 | register_file (&finfo, spool); | ||
206 | } | 250 | } |
207 | 251 | ||
208 | closedir (dir); | 252 | closedir (dir); |
209 | 253 | ||
210 | if (count_collected_triplets () > 0) | 254 | if (count_collected_triplets () > 0) |
211 | { | 255 | spool_commit_triplets (spool); |
212 | int i; | 256 | |
213 | |||
214 | for (i = 0; i < dictionary_count; i++) | ||
215 | { | ||
216 | if (dictionary_init (spool->dictionary[i])) | ||
217 | { | ||
218 | logmsg (LOG_ERR, _("failed to initialize dictionary %d"), i); | ||
219 | return; | ||
220 | } | ||
221 | } | ||
222 | enumerate_triplets (spool); | ||
223 | } | ||
224 | timer_stop (spool->tag); | 257 | timer_stop (spool->tag); |
225 | timer_stop ("spool"); | 258 | timer_stop ("spool"); |
226 | } | 259 | } |
227 | 260 | ||
228 | int | 261 | int |
229 | scan_spool (const struct spool *spool, int uc, uid_t *uv) | 262 | scan_spool (struct spool *spool, int uc, uid_t *uv) |
230 | { | 263 | { |
231 | char *lockfile = wydawca_lockname (spool->tag); | 264 | char *lockfile = wydawca_lockname (spool->tag); |
232 | int rc = wydawca_lock (lockfile); | 265 | int rc = wydawca_lock (lockfile); |
@@ -249,12 +282,33 @@ scan_spool (const struct spool *spool, int uc, uid_t *uv) | |||
249 | return rc; | 282 | return rc; |
250 | } | 283 | } |
251 | 284 | ||
252 | static void | 285 | int |
253 | close_dictionaries (struct spool *spool) | 286 | spool_open_dictionaries (struct spool *spool) |
287 | { | ||
288 | if (!spool->dict_inited) | ||
289 | { | ||
290 | int i; | ||
291 | |||
292 | for (i = 0; i < dictionary_count; i++) | ||
293 | { | ||
294 | if (dictionary_init (spool->dictionary[i])) | ||
295 | { | ||
296 | logmsg (LOG_ERR, _("failed to initialize dictionary %d"), i); | ||
297 | return -1; | ||
298 | } | ||
299 | } | ||
300 | spool->dict_inited = 1; | ||
301 | } | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | void | ||
306 | spool_close_dictionaries (struct spool *spool) | ||
254 | { | 307 | { |
255 | int i; | 308 | int i; |
256 | for (i = 0; i < NITEMS (spool->dictionary); i++) | 309 | for (i = 0; i < NITEMS (spool->dictionary); i++) |
257 | dictionary_done (spool->dictionary[i]); | 310 | dictionary_done (spool->dictionary[i]); |
311 | spool->dict_inited = 0; | ||
258 | } | 312 | } |
259 | 313 | ||
260 | /* Scan all configured update directories */ | 314 | /* Scan all configured update directories */ |
@@ -271,7 +325,7 @@ scan_all_spools (int uidc, uid_t *uidv) | |||
271 | rc++; | 325 | rc++; |
272 | 326 | ||
273 | for (sp = spool_list; sp; sp = sp->next) | 327 | for (sp = spool_list; sp; sp = sp->next) |
274 | close_dictionaries (&sp->spool); | 328 | spool_close_dictionaries (&sp->spool); |
275 | timer_stop ("wydawca"); | 329 | timer_stop ("wydawca"); |
276 | return rc; | 330 | return rc; |
277 | } | 331 | } |
diff --git a/src/triplet.c b/src/triplet.c index 79ca8c2..05b7536 100644 --- a/src/triplet.c +++ b/src/triplet.c | |||
@@ -32,7 +32,7 @@ hash_triplet_compare (void const *data1, void const *data2) | |||
32 | { | 32 | { |
33 | struct file_triplet const *t1 = data1; | 33 | struct file_triplet const *t1 = data1; |
34 | struct file_triplet const *t2 = data2; | 34 | struct file_triplet const *t2 = data2; |
35 | return strcmp (t1->name, t2->name); | 35 | return t1->spool == t2->spool && strcmp (t1->name, t2->name); |
36 | } | 36 | } |
37 | 37 | ||
38 | /* Reclaim memory storage associated with a table entry */ | 38 | /* Reclaim memory storage associated with a table entry */ |
@@ -98,6 +98,7 @@ register_file (struct file_info *finfo, const struct spool *spool) | |||
98 | key.name = grecs_malloc (finfo->root_len + 1); | 98 | key.name = grecs_malloc (finfo->root_len + 1); |
99 | memcpy (key.name, finfo->name, finfo->root_len); | 99 | memcpy (key.name, finfo->name, finfo->root_len); |
100 | key.name[finfo->root_len] = 0; | 100 | key.name[finfo->root_len] = 0; |
101 | key.spool = spool; | ||
101 | 102 | ||
102 | ret = grecs_symtab_lookup_or_install (triplet_table, &key, &install); | 103 | ret = grecs_symtab_lookup_or_install (triplet_table, &key, &install); |
103 | if (!ret) | 104 | if (!ret) |
@@ -111,6 +112,28 @@ register_file (struct file_info *finfo, const struct spool *spool) | |||
111 | ret->file[finfo->type] = *finfo; | 112 | ret->file[finfo->type] = *finfo; |
112 | } | 113 | } |
113 | 114 | ||
115 | struct file_triplet * | ||
116 | triplet_lookup (struct spool *spool, const char *name) | ||
117 | { | ||
118 | struct file_triplet key, *ret; | ||
119 | struct file_info finfo; | ||
120 | |||
121 | if (!triplet_table) | ||
122 | return NULL; | ||
123 | |||
124 | parse_file_name (name, &finfo); | ||
125 | |||
126 | key.name = grecs_malloc (finfo.root_len + 1); | ||
127 | memcpy (key.name, finfo.name, finfo.root_len); | ||
128 | key.name[finfo.root_len] = 0; | ||
129 | key.spool = spool; | ||
130 | |||
131 | ret = grecs_symtab_lookup_or_install (triplet_table, &key, NULL); | ||
132 | file_info_cleanup (&finfo); | ||
133 | |||
134 | return ret; | ||
135 | } | ||
136 | |||
114 | /* Return true if any part of the triplet TRP was modified more than | 137 | /* Return true if any part of the triplet TRP was modified more than |
115 | TTL seconds ago */ | 138 | TTL seconds ago */ |
116 | static int | 139 | static int |
@@ -147,11 +170,11 @@ enum triplet_state | |||
147 | 170 | ||
148 | 171 | ||
149 | static enum triplet_state | 172 | static enum triplet_state |
150 | check_triplet_state (struct file_triplet *trp) | 173 | check_triplet_state (struct file_triplet *trp, int noauth) |
151 | { | 174 | { |
152 | if (trp->file[file_directive].name) | 175 | if (trp->file[file_directive].name) |
153 | { | 176 | { |
154 | if (verify_directive_file (trp)) | 177 | if (verify_directive_file (trp, noauth)) |
155 | return triplet_bad; | 178 | return triplet_bad; |
156 | 179 | ||
157 | if (trp->file[file_dist].name == 0 | 180 | if (trp->file[file_dist].name == 0 |
@@ -160,8 +183,7 @@ check_triplet_state (struct file_triplet *trp) | |||
160 | if (directive_get_value (trp, "filename", NULL)) | 183 | if (directive_get_value (trp, "filename", NULL)) |
161 | return triplet_directive; | 184 | return triplet_directive; |
162 | } | 185 | } |
163 | else if (trp->file[file_dist].name | 186 | else if (trp->file[file_dist].name && trp->file[file_signature].name) |
164 | && trp->file[file_signature].name) | ||
165 | { | 187 | { |
166 | if (trp->file[file_dist].sb.st_uid == | 188 | if (trp->file[file_dist].sb.st_uid == |
167 | trp->file[file_signature].sb.st_uid | 189 | trp->file[file_signature].sb.st_uid |
@@ -212,7 +234,7 @@ triplet_processor (void *data, void *proc_data) | |||
212 | SP (trp->file[file_signature].name), | 234 | SP (trp->file[file_signature].name), |
213 | SP (trp->file[file_directive].name)); | 235 | SP (trp->file[file_directive].name)); |
214 | 236 | ||
215 | switch (check_triplet_state (trp)) | 237 | switch (check_triplet_state (trp, 0)) |
216 | { | 238 | { |
217 | case triplet_directive: | 239 | case triplet_directive: |
218 | case triplet_complete: | 240 | case triplet_complete: |
@@ -246,11 +268,13 @@ triplet_processor (void *data, void *proc_data) | |||
246 | 268 | ||
247 | /* Process all triplets from the table according to the SPOOL */ | 269 | /* Process all triplets from the table according to the SPOOL */ |
248 | void | 270 | void |
249 | enumerate_triplets (const struct spool *spool) | 271 | spool_commit_triplets (struct spool *spool) |
250 | { | 272 | { |
251 | if (debug_level) | 273 | if (debug_level) |
252 | logmsg (LOG_DEBUG, _("processing spool %s (%s)"), | 274 | logmsg (LOG_DEBUG, _("processing spool %s (%s)"), |
253 | spool->tag, mu_url_to_string (spool->dest_url)); | 275 | spool->tag, mu_url_to_string (spool->dest_url)); |
276 | if (spool_open_dictionaries (spool)) | ||
277 | return; | ||
254 | if (triplet_table) | 278 | if (triplet_table) |
255 | { | 279 | { |
256 | grecs_symtab_enumerate (triplet_table, triplet_processor, NULL); | 280 | grecs_symtab_enumerate (triplet_table, triplet_processor, NULL); |
@@ -264,6 +288,72 @@ count_collected_triplets () | |||
264 | return triplet_table ? grecs_symtab_count_entries (triplet_table) : 0; | 288 | return triplet_table ? grecs_symtab_count_entries (triplet_table) : 0; |
265 | } | 289 | } |
266 | 290 | ||
291 | static int | ||
292 | triplet_counter (void *data, void *proc_data) | ||
293 | { | ||
294 | struct file_triplet *trp = data; | ||
295 | size_t *cp = proc_data; | ||
296 | |||
297 | if (debug_level) | ||
298 | logmsg (LOG_DEBUG, "FILE %s, DIST=%s, SIG=%s, DIRECTIVE=%s", | ||
299 | trp->name, | ||
300 | SP (trp->file[file_dist].name), | ||
301 | SP (trp->file[file_signature].name), | ||
302 | SP (trp->file[file_directive].name)); | ||
303 | |||
304 | switch (check_triplet_state (trp, 1)) | ||
305 | { | ||
306 | case triplet_directive: | ||
307 | case triplet_complete: | ||
308 | case triplet_bad: | ||
309 | ++*cp; | ||
310 | case triplet_incomplete: | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | if (triplet_expired_p (trp, trp->spool->file_sweep_time)) | ||
315 | ++*cp;//FIXME | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | size_t | ||
321 | count_processable_triplets () | ||
322 | { | ||
323 | size_t count = 0; | ||
324 | if (triplet_table) | ||
325 | grecs_symtab_enumerate (triplet_table, triplet_counter, &count); | ||
326 | return count; | ||
327 | } | ||
328 | |||
329 | void | ||
330 | triplet_remove_file (struct spool *spool, const char *name) | ||
331 | { | ||
332 | struct file_triplet *tp = triplet_lookup (spool, name); | ||
333 | int i, n = 0; | ||
334 | |||
335 | if (!tp) | ||
336 | return; | ||
337 | |||
338 | for (i = 0; i < FILE_TYPE_COUNT; i++) | ||
339 | { | ||
340 | if (!tp->file[i].name) | ||
341 | /* nothing */; | ||
342 | else if (strcmp (tp->file[i].name, name) == 0) | ||
343 | file_info_cleanup (&tp->file[i]); | ||
344 | else | ||
345 | n++; | ||
346 | } | ||
347 | |||
348 | if (!n) | ||
349 | { | ||
350 | if (debug_level > 0) | ||
351 | logmsg (LOG_DEBUG, "deleting empty triplet (%s/%s)", | ||
352 | spool->source_dir, name); | ||
353 | grecs_symtab_remove (triplet_table, tp); | ||
354 | } | ||
355 | } | ||
356 | |||
267 | 357 | ||
268 | static const char * | 358 | static const char * |
269 | expand_project_base (struct metadef *def, void *data) | 359 | expand_project_base (struct metadef *def, void *data) |
diff --git a/src/verify.c b/src/verify.c index 1409889..4a108bc 100644 --- a/src/verify.c +++ b/src/verify.c | |||
@@ -202,7 +202,7 @@ uploader_find_frp (struct uploader_info *list, const char *fpr) | |||
202 | } | 202 | } |
203 | 203 | ||
204 | int | 204 | int |
205 | verify_directive_file (struct file_triplet *trp) | 205 | verify_directive_file (struct file_triplet *trp, int noath) |
206 | { | 206 | { |
207 | char *command; | 207 | char *command; |
208 | int rc; | 208 | int rc; |
@@ -220,105 +220,108 @@ verify_directive_file (struct file_triplet *trp) | |||
220 | 220 | ||
221 | if (fill_project_name (trp)) | 221 | if (fill_project_name (trp)) |
222 | return 1; | 222 | return 1; |
223 | |||
224 | md = dictionary_open (dict); | ||
225 | if (!md) | ||
226 | return 1; | ||
227 | |||
228 | command = triplet_expand_dictionary_query (dict, md, trp); | ||
229 | |||
230 | rc = dictionary_lookup (dict, md, command); | ||
231 | free (command); | ||
232 | if (rc) | ||
233 | { | ||
234 | logmsg (LOG_ERR, _("cannot get uploaders for %s"), trp->name); | ||
235 | dictionary_close (dict, md); | ||
236 | return 1; | ||
237 | } | ||
238 | |||
239 | nrows = dictionary_num_rows (dict); | ||
240 | if (nrows == 0) | ||
241 | { | ||
242 | logmsg (LOG_ERR, _("found no uploaders for %s"), trp->name); | ||
243 | dictionary_close (dict, md); | ||
244 | return 1; | ||
245 | } | ||
246 | 223 | ||
247 | ncols = dictionary_num_cols (dict); | 224 | if (!noath) |
248 | if (ncols < 4) | ||
249 | { | 225 | { |
250 | logmsg (LOG_ERR, | 226 | md = dictionary_open (dict); |
251 | _("project-uploader dictionary error: too few columns (%lu)"), | 227 | if (!md) |
252 | (unsigned long) ncols); | 228 | return 1; |
253 | dictionary_close (dict, md); | ||
254 | return 1; | ||
255 | } | ||
256 | 229 | ||
257 | head = tail = NULL; | 230 | command = triplet_expand_dictionary_query (dict, md, trp); |
258 | for (i = 0; i < nrows; i++) | ||
259 | { | ||
260 | const char *p; | ||
261 | struct uploader_info info, *ptr; | ||
262 | 231 | ||
263 | memset (&info, 0, sizeof (info)); | 232 | rc = dictionary_lookup (dict, md, command); |
264 | p = dictionary_result (dict, md, i, 0); | 233 | free (command); |
265 | if (p) | 234 | if (rc) |
266 | info.name = triplet_strdup (trp, p); | 235 | { |
267 | p = dictionary_result (dict, md, i, 1); | 236 | logmsg (LOG_ERR, _("cannot get uploaders for %s"), trp->name); |
268 | if (p) | 237 | dictionary_close (dict, md); |
269 | info.realname = triplet_strdup (trp, p); | 238 | return 1; |
270 | p = dictionary_result (dict, md, i, 2); | 239 | } |
271 | if (p) | ||
272 | info.email = triplet_strdup (trp, p); | ||
273 | p = dictionary_result (dict, md, i, 3); | ||
274 | if (p) | ||
275 | info.gpg_key = triplet_strdup (trp, p); | ||
276 | 240 | ||
277 | if (debug_level > 3) | 241 | nrows = dictionary_num_rows (dict); |
242 | if (nrows == 0) | ||
278 | { | 243 | { |
279 | logmsg (LOG_DEBUG, _("name: %s"), SP (info.name)); | 244 | logmsg (LOG_ERR, _("found no uploaders for %s"), trp->name); |
280 | logmsg (LOG_DEBUG, _("realname: %s"), SP (info.realname)); | 245 | dictionary_close (dict, md); |
281 | logmsg (LOG_DEBUG, _("gpg-key: %s"), SP (info.gpg_key)); | 246 | return 1; |
282 | logmsg (LOG_DEBUG, _("email: %s"), SP (info.email)); | ||
283 | } | 247 | } |
284 | 248 | ||
285 | if (!info.name || !info.realname || !info.gpg_key || !info.email) | 249 | ncols = dictionary_num_cols (dict); |
250 | if (ncols < 4) | ||
286 | { | 251 | { |
287 | logmsg (LOG_ERR, | 252 | logmsg (LOG_ERR, |
288 | _("project-uploader dictionary error: malformed row %lu"), | 253 | _("project-uploader dictionary error: too few columns (%lu)"), |
289 | (unsigned long) i); | 254 | (unsigned long) ncols); |
290 | /* FIXME: Memory not reclaimed */ | 255 | dictionary_close (dict, md); |
291 | continue; | 256 | return 1; |
292 | } | 257 | } |
293 | 258 | ||
294 | ptr = new_uploader_info (&info); | 259 | head = tail = NULL; |
295 | if (tail) | 260 | for (i = 0; i < nrows; i++) |
296 | tail->next = ptr; | 261 | { |
297 | else | 262 | const char *p; |
298 | head = ptr; | 263 | struct uploader_info info, *ptr; |
299 | tail = ptr; | ||
300 | } | ||
301 | 264 | ||
302 | dictionary_close (dict, md); | 265 | memset (&info, 0, sizeof (info)); |
303 | 266 | p = dictionary_result (dict, md, i, 0); | |
304 | if (!head) | 267 | if (p) |
305 | { | 268 | info.name = triplet_strdup (trp, p); |
306 | logmsg (LOG_ERR, _("no valid uploaders found for %s"), trp->name); | 269 | p = dictionary_result (dict, md, i, 1); |
307 | return 1; | 270 | if (p) |
308 | } | 271 | info.realname = triplet_strdup (trp, p); |
309 | 272 | p = dictionary_result (dict, md, i, 2); | |
310 | trp->uploader_list = head; | 273 | if (p) |
311 | trp->uploader = NULL; | 274 | info.email = triplet_strdup (trp, p); |
275 | p = dictionary_result (dict, md, i, 3); | ||
276 | if (p) | ||
277 | info.gpg_key = triplet_strdup (trp, p); | ||
278 | |||
279 | if (debug_level > 3) | ||
280 | { | ||
281 | logmsg (LOG_DEBUG, _("name: %s"), SP (info.name)); | ||
282 | logmsg (LOG_DEBUG, _("realname: %s"), SP (info.realname)); | ||
283 | logmsg (LOG_DEBUG, _("gpg-key: %s"), SP (info.gpg_key)); | ||
284 | logmsg (LOG_DEBUG, _("email: %s"), SP (info.email)); | ||
285 | } | ||
286 | |||
287 | if (!info.name || !info.realname || !info.gpg_key || !info.email) | ||
288 | { | ||
289 | logmsg (LOG_ERR, | ||
290 | _("project-uploader dictionary error: malformed row %lu"), | ||
291 | (unsigned long) i); | ||
292 | /* FIXME: Memory not reclaimed */ | ||
293 | continue; | ||
294 | } | ||
295 | |||
296 | ptr = new_uploader_info (&info); | ||
297 | if (tail) | ||
298 | tail->next = ptr; | ||
299 | else | ||
300 | head = ptr; | ||
301 | tail = ptr; | ||
302 | } | ||
303 | |||
304 | dictionary_close (dict, md); | ||
312 | 305 | ||
313 | if (verify_directive_signature (trp)) | 306 | if (!head) |
314 | { | 307 | { |
315 | /*FIXME: Update stats */ | 308 | logmsg (LOG_ERR, _("no valid uploaders found for %s"), trp->name); |
316 | logmsg (LOG_ERR, _("invalid signature for %s"), | 309 | return 1; |
317 | trp->name ? trp->name : "[unknown]"); | 310 | } |
318 | return 1; | 311 | |
312 | trp->uploader_list = head; | ||
313 | trp->uploader = NULL; | ||
314 | |||
315 | if (verify_directive_signature (trp)) | ||
316 | { | ||
317 | /*FIXME: Update stats */ | ||
318 | logmsg (LOG_ERR, _("invalid signature for %s"), | ||
319 | trp->name ? trp->name : "[unknown]"); | ||
320 | return 1; | ||
321 | } | ||
322 | else if (debug_level) | ||
323 | logmsg (LOG_DEBUG, _("%s: directive file signature OK"), trp->name); | ||
319 | } | 324 | } |
320 | else if (debug_level) | ||
321 | logmsg (LOG_DEBUG, _("%s: directive file signature OK"), trp->name); | ||
322 | 325 | ||
323 | if (debug_level > 1) | 326 | if (debug_level > 1) |
324 | { | 327 | { |
@@ -24,13 +24,13 @@ struct virt_tab_reg | |||
24 | 24 | ||
25 | static struct virt_tab_reg reg[] = { | 25 | static struct virt_tab_reg reg[] = { |
26 | { "file", | 26 | { "file", |
27 | { dir_test_url, dir_move_file, dir_archive_file, dir_symlink_file, | 27 | { dir_get_path, dir_test_url, dir_move_file, dir_archive_file, |
28 | dir_rmsymlink_file } }, | 28 | dir_symlink_file, dir_rmsymlink_file } }, |
29 | { "dir", | 29 | { "dir", |
30 | { dir_test_url, dir_move_file, dir_archive_file, dir_symlink_file, | 30 | { dir_get_path, dir_test_url, dir_move_file, dir_archive_file, |
31 | dir_rmsymlink_file } }, | 31 | dir_symlink_file, dir_rmsymlink_file } }, |
32 | { "null", | 32 | { "null", |
33 | { NULL, null_move_file, null_archive_file, null_symlink_file, | 33 | { NULL, NULL, null_move_file, null_archive_file, null_symlink_file, |
34 | null_rmsymlink_file } }, | 34 | null_rmsymlink_file } }, |
35 | { NULL } | 35 | { NULL } |
36 | }; | 36 | }; |
@@ -53,6 +53,14 @@ url_to_vtab (mu_url_t url, struct virt_tab *vtab) | |||
53 | } | 53 | } |
54 | 54 | ||
55 | 55 | ||
56 | const char * | ||
57 | get_path (struct spool *sp) | ||
58 | { | ||
59 | if (!sp->vtab.get_path) | ||
60 | return NULL; | ||
61 | return sp->vtab.get_path (sp); | ||
62 | } | ||
63 | |||
56 | int | 64 | int |
57 | move_file (struct file_triplet *trp, enum file_type file_id) | 65 | move_file (struct file_triplet *trp, enum file_type file_id) |
58 | { | 66 | { |
diff --git a/src/watcher.c b/src/watcher.c new file mode 100644 index 0000000..f8761ee --- a/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 */ | ||
22 | struct 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 | |||
31 | static struct dirwatcher *dirwatcher_list; | ||
32 | |||
33 | struct dirwatcher * | ||
34 | dirwatcher_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 | |||
46 | struct dirwatcher * | ||
47 | dirwatcher_pop(struct dirwatcher **pp) | ||
48 | { | ||
49 | if (*pp) | ||
50 | return dirwatcher_unlink(pp, *pp); | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static void | ||
55 | dirwatcher_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 */ | ||
65 | static struct dirwatcher * | ||
66 | dirwatcher_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 | |||
76 | static int | ||
77 | create_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 | |||
112 | int | ||
113 | watcher_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 | |||
142 | static void | ||
143 | process_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 | |||
191 | static char buffer[4096]; | ||
192 | static int offset; | ||
193 | |||
194 | int | ||
195 | watcher_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 | } | ||
238 | if (n > 0 && offset - n > 0) | ||
239 | memmove (buffer, buffer + n, offset - n); | ||
240 | offset -= n; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
diff --git a/src/wydawca.c b/src/wydawca.c index 69fb898..521d796 100644 --- a/src/wydawca.c +++ b/src/wydawca.c | |||
@@ -328,6 +328,19 @@ wydawca_daemon () | |||
328 | 328 | ||
329 | #include "cmdline.h" | 329 | #include "cmdline.h" |
330 | 330 | ||
331 | void | ||
332 | version_hook (FILE *stream) | ||
333 | { | ||
334 | printf ("Compiled with:"); | ||
335 | #ifdef WITH_LIBWRAP | ||
336 | printf (" libwrap"); | ||
337 | #endif | ||
338 | #ifdef WITH_INOTIFY | ||
339 | printf (" inotify"); | ||
340 | #endif | ||
341 | putchar ('\n'); | ||
342 | } | ||
343 | |||
331 | int | 344 | int |
332 | main (int argc, char **argv) | 345 | main (int argc, char **argv) |
333 | { | 346 | { |
@@ -335,6 +348,7 @@ main (int argc, char **argv) | |||
335 | const char *p; | 348 | const char *p; |
336 | 349 | ||
337 | program_name = argv[0]; | 350 | program_name = argv[0]; |
351 | print_version_hook = version_hook; | ||
338 | mu_register_all_mailer_formats (); | 352 | mu_register_all_mailer_formats (); |
339 | mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); | 353 | mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); |
340 | config_init (); | 354 | config_init (); |
diff --git a/src/wydawca.h b/src/wydawca.h index 5de1f3e..722fc9b 100644 --- a/src/wydawca.h +++ b/src/wydawca.h | |||
@@ -205,6 +205,7 @@ struct file_triplet | |||
205 | 205 | ||
206 | struct virt_tab | 206 | struct virt_tab |
207 | { | 207 | { |
208 | const char *(*get_path) (struct spool *sp); | ||
208 | int (*test_url) (mu_url_t url, grecs_locus_t *loc); | 209 | int (*test_url) (mu_url_t url, grecs_locus_t *loc); |
209 | int (*move_file) (struct file_triplet *trp, enum file_type file_id); | 210 | int (*move_file) (struct file_triplet *trp, enum file_type file_id); |
210 | int (*archive_file) (struct file_triplet *trp, const char *file_name); | 211 | int (*archive_file) (struct file_triplet *trp, const char *file_name); |
@@ -229,6 +230,7 @@ struct spool | |||
229 | time_t file_sweep_time; /* Remove invalid/unprocessed files | 230 | time_t file_sweep_time; /* Remove invalid/unprocessed files |
230 | after this amount of time */ | 231 | after this amount of time */ |
231 | struct dictionary *dictionary[dictionary_count]; | 232 | struct dictionary *dictionary[dictionary_count]; |
233 | int dict_inited; | ||
232 | struct archive_descr archive; /* Archivation data */ | 234 | struct archive_descr archive; /* Archivation data */ |
233 | struct notification *notification; | 235 | struct notification *notification; |
234 | char *check_script; | 236 | char *check_script; |
@@ -372,6 +374,9 @@ extern char *temp_homedir; | |||
372 | extern unsigned min_directive_version; | 374 | extern unsigned min_directive_version; |
373 | extern unsigned max_directive_version; | 375 | extern unsigned max_directive_version; |
374 | 376 | ||
377 | extern struct spool fake_spool; | ||
378 | extern struct spool inotify_spool; | ||
379 | |||
375 | #define UPDATE_STATS(what) \ | 380 | #define UPDATE_STATS(what) \ |
376 | do \ | 381 | do \ |
377 | { \ | 382 | { \ |
@@ -409,19 +414,31 @@ enum exec_result wydawca_exec (int argc, const char **argv, int *retcode); | |||
409 | 414 | ||
410 | 415 | ||
411 | /* Directory scanning and registering */ | 416 | /* Directory scanning and registering */ |
412 | int scan_spool (const struct spool *spool, int uc, uid_t *uv); | 417 | int scan_spool (struct spool *spool, int uc, uid_t *uv); |
413 | int scan_all_spools (int, uid_t *); | 418 | int scan_all_spools (int, uid_t *); |
414 | void spool_create_timers (void); | 419 | void spool_create_timers (void); |
415 | 420 | ||
421 | int spool_add_new_file (const struct spool *spool, const char *name, | ||
422 | int uc, uid_t *uv); | ||
423 | int spool_cwd_add_new_file (const struct spool *spool, const char *name, | ||
424 | int uc, uid_t *uv); | ||
425 | int spool_open_dictionaries (struct spool *spool); | ||
426 | void spool_close_dictionaries (struct spool *spool); | ||
427 | |||
428 | int for_each_spool (int (*fun) (struct spool *, void *), void *data); | ||
416 | void register_spool (struct spool *spool); | 429 | void register_spool (struct spool *spool); |
417 | struct spool *wydawca_find_spool (const char *name); | 430 | struct spool *wydawca_find_spool (const char *name); |
418 | void register_file (struct file_info *finfo, const struct spool *spool); | 431 | void register_file (struct file_info *finfo, const struct spool *spool); |
419 | void enumerate_triplets (const struct spool *); | 432 | void spool_commit_triplets (struct spool *); |
420 | size_t count_collected_triplets (void); | 433 | size_t count_collected_triplets (void); |
434 | size_t count_processable_triplets (void); | ||
435 | |||
421 | char *triplet_expand_param (const char *tmpl, struct file_triplet *trp); | 436 | char *triplet_expand_param (const char *tmpl, struct file_triplet *trp); |
422 | char *triplet_expand_dictionary_query (struct dictionary *dict, void *handle, | 437 | char *triplet_expand_dictionary_query (struct dictionary *dict, void *handle, |
423 | struct file_triplet *trp); | 438 | struct file_triplet *trp); |
424 | 439 | ||
440 | void triplet_remove_file (struct spool *spool, const char *name); | ||
441 | |||
425 | /* General-purpose dictionary support */ | 442 | /* General-purpose dictionary support */ |
426 | struct dictionary *dictionary_new (enum dictionary_id id, | 443 | struct dictionary *dictionary_new (enum dictionary_id id, |
427 | enum dictionary_type type); | 444 | enum dictionary_type type); |
@@ -442,7 +459,7 @@ unsigned dictionary_num_rows (struct dictionary *dict); | |||
442 | unsigned dictionary_num_cols (struct dictionary *dict); | 459 | unsigned dictionary_num_cols (struct dictionary *dict); |
443 | 460 | ||
444 | /* Verification functions */ | 461 | /* Verification functions */ |
445 | int verify_directive_file (struct file_triplet *trp); | 462 | int verify_directive_file (struct file_triplet *trp, int noath); |
446 | int verify_directive_signature (struct file_triplet *trp); | 463 | int verify_directive_signature (struct file_triplet *trp); |
447 | int verify_detached_signature (struct file_triplet *trp); | 464 | int verify_detached_signature (struct file_triplet *trp); |
448 | int fill_project_name (struct file_triplet *trp); | 465 | int fill_project_name (struct file_triplet *trp); |
@@ -485,21 +502,19 @@ int assert_string_arg (grecs_locus_t *, enum grecs_callback_command, | |||
485 | /* vtab.c */ | 502 | /* vtab.c */ |
486 | int url_to_vtab (mu_url_t url, struct virt_tab *vtab); | 503 | int url_to_vtab (mu_url_t url, struct virt_tab *vtab); |
487 | 504 | ||
488 | int | 505 | const char *get_path (struct spool *sp); |
489 | move_file (struct file_triplet *trp, enum file_type file_id); | 506 | int move_file (struct file_triplet *trp, enum file_type file_id); |
490 | int | 507 | int archive_file (struct file_triplet *trp, const char *file_name); |
491 | archive_file (struct file_triplet *trp, const char *file_name); | 508 | int symlink_file (struct file_triplet *trp, |
492 | int | 509 | const char *wanted_src, const char *wanted_dst); |
493 | symlink_file (struct file_triplet *trp, | 510 | int rmsymlink_file (struct file_triplet *trp, const char *file_name); |
494 | const char *wanted_src, const char *wanted_dst); | ||
495 | int | ||
496 | rmsymlink_file (struct file_triplet *trp, const char *file_name); | ||
497 | 511 | ||
498 | 512 | ||
499 | /* diskio.c */ | 513 | /* diskio.c */ |
500 | char *concat_dir (const char *base, const char *name, size_t *pbaselen); | 514 | char *concat_dir (const char *base, const char *name, size_t *pbaselen); |
501 | int copy_file (const char *file, const char *dst_file); | 515 | int copy_file (const char *file, const char *dst_file); |
502 | 516 | ||
517 | const char *dir_get_path (struct spool *sp); | ||
503 | int dir_test_url (mu_url_t url, grecs_locus_t *locus); | 518 | int dir_test_url (mu_url_t url, grecs_locus_t *locus); |
504 | int dir_move_file (struct file_triplet *trp, enum file_type file_id); | 519 | int dir_move_file (struct file_triplet *trp, enum file_type file_id); |
505 | int dir_archive_file (struct file_triplet *trp, const char *reldir); | 520 | int dir_archive_file (struct file_triplet *trp, const char *reldir); |
@@ -538,7 +553,7 @@ extern char *report_string; | |||
538 | 553 | ||
539 | 554 | ||
540 | /* job.c */ | 555 | /* job.c */ |
541 | void schedule_job (const struct spool *spool, uid_t uid); | 556 | void schedule_job (struct spool *spool, uid_t uid); |
542 | void job_init (void); | 557 | void job_init (void); |
543 | void job_queue_runner (void); | 558 | void job_queue_runner (void); |
544 | 559 | ||
@@ -588,3 +603,11 @@ void txtacc_grow (struct txtacc *acc, const char *buf, size_t size); | |||
588 | } \ | 603 | } \ |
589 | while (0) | 604 | while (0) |
590 | char *txtacc_finish (struct txtacc *acc, int steal); | 605 | char *txtacc_finish (struct txtacc *acc, int steal); |
606 | |||
607 | #ifdef WITH_INOTIFY | ||
608 | int watcher_init (void); | ||
609 | int watcher_run (int); | ||
610 | #else | ||
611 | # define watcher_init() -1 | ||
612 | # define watcher_run(c) | ||
613 | #endif | ||