summaryrefslogtreecommitdiffabout
path: root/src
Unidiff
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am8
-rw-r--r--src/diskio.c6
-rw-r--r--src/job.c18
-rw-r--r--src/net.c87
-rw-r--r--src/process.c162
-rw-r--r--src/triplet.c104
-rw-r--r--src/verify.c175
-rw-r--r--src/vtab.c18
-rw-r--r--src/watcher.c243
-rw-r--r--src/wydawca.c14
-rw-r--r--src/wydawca.h49
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
@@ -12,12 +12,17 @@
12# GNU General Public License for more details. 12# GNU General Public License for more details.
13# 13#
14# You should have received a copy of the GNU General Public License 14# You should have received a copy of the GNU General Public License
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
17sbin_PROGRAMS=wydawca 17sbin_PROGRAMS=wydawca
18
19if COND_INOTIFY
20 WATCHER_C=watcher.c
21endif
22
18wydawca_SOURCES=\ 23wydawca_SOURCES=\
19 backup.c\ 24 backup.c\
20 builtin.c\ 25 builtin.c\
21 builtin.h\ 26 builtin.h\
22 cmdline.h\ 27 cmdline.h\
23 config.c\ 28 config.c\
@@ -45,13 +50,14 @@ wydawca_SOURCES=\
45 mail.h\ 50 mail.h\
46 mail.c\ 51 mail.c\
47 vtab.c\ 52 vtab.c\
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
53BUILT_SOURCES=cmdline.h 59BUILT_SOURCES=cmdline.h
54EXTRA_DIST=cmdline.opt pp-setup update-2.0.awk 60EXTRA_DIST=cmdline.opt pp-setup update-2.0.awk
55 61
56SUFFIXES=.opt .c .h 62SUFFIXES=.opt .c .h
57 63
diff --git a/src/diskio.c b/src/diskio.c
index bab5cb8..751d684 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -408,12 +408,18 @@ replace_allowed_p (struct file_triplet *trp)
408 408
409 if (directive_get_value (trp, "replace", &val)) 409 if (directive_get_value (trp, "replace", &val))
410 return 1; 410 return 1;
411 return strcmp (val, "true") == 0; 411 return strcmp (val, "true") == 0;
412} 412}
413 413
414const char *
415dir_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.
417 423
418 Do nothing if dry_run_mode is set. */ 424 Do nothing if dry_run_mode is set. */
419int 425int
diff --git a/src/job.c b/src/job.c
index 4a97f88..3fae432 100644
--- a/src/job.c
+++ b/src/job.c
@@ -22,24 +22,25 @@
22#define STATE_ACTIVE 0x04 22#define STATE_ACTIVE 0x04
23 23
24struct job 24struct 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;
32 int exit_status; 32 int exit_status;
33}; 33};
34 34
35struct job *queue; 35struct job *queue;
36size_t jobmax; 36size_t jobmax;
37size_t jobcnt; 37size_t jobcnt;
38 38
39static struct spool fake_spool = { "all spools" }; 39struct spool fake_spool = { "all spools" },
40 inotify_spool = { "inotify" } ;
40 41
41static int wakeup; 42static int wakeup;
42 43
43RETSIGTYPE 44RETSIGTYPE
44queue_signal (int sig) 45queue_signal (int sig)
45{ 46{
@@ -73,19 +74,28 @@ job_active_count ()
73 for (job = queue; job; job = job->next) 74 for (job = queue; job; job = job->next)
74 if (job->state & STATE_ACTIVE) 75 if (job->state & STATE_ACTIVE)
75 count++; 76 count++;
76 return count; 77 return count;
77} 78}
78 79
80static int
81procspool (struct spool *spool, void *data)
82{
83 spool_commit_triplets (spool);
84 return 0;
85}
86
79int 87int
80wydawca_scanner (struct job *job) 88wydawca_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 {
89 spool_create_timers (); 99 spool_create_timers ();
90 rc = scan_spool (job->spool, 1, &job->uid); 100 rc = scan_spool (job->spool, 1, &job->uid);
91 } 101 }
@@ -188,13 +198,13 @@ job_insert (struct job *job, struct job *elt)
188 198
189 if (p) 199 if (p)
190 p->prev = job; 200 p->prev = job;
191} 201}
192 202
193void 203void
194schedule_job (const struct spool *spool, uid_t uid) 204schedule_job (struct spool *spool, uid_t uid)
195{ 205{
196 struct job *job; 206 struct job *job;
197 207
198 if (!spool) 208 if (!spool)
199 spool = &fake_spool; 209 spool = &fake_spool;
200 210
diff --git a/src/net.c b/src/net.c
index 4857fa2..3157fe8 100644
--- a/src/net.c
+++ b/src/net.c
@@ -19,16 +19,13 @@
19static int 19static int
20open_listener () 20open_listener ()
21{ 21{
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)
32 { 29 {
33 logmsg (LOG_CRIT, _("cannot create socket: %s"), 30 logmsg (LOG_CRIT, _("cannot create socket: %s"),
34 strerror(errno)); 31 strerror(errno));
@@ -96,13 +93,13 @@ trim_crlf (char *s)
96 93
97void 94void
98handle_connection (FILE *in, FILE *out) 95handle_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
106 if (grecs_getline (&buf, &buflen, in) <= 0) 103 if (grecs_getline (&buf, &buflen, in) <= 0)
107 return; 104 return;
108 trim_crlf (buf); 105 trim_crlf (buf);
@@ -171,74 +168,102 @@ sig_term (int sig)
171} 168}
172 169
173void 170void
174wydawca_listener () 171wydawca_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);
181 signal (SIGQUIT, sig_term); 193 signal (SIGQUIT, sig_term);
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 {
203 to.tv_sec = wakeup_interval; 210 to.tv_sec = wakeup_interval;
204 to.tv_usec = 0; 211 to.tv_usec = 0;
205 *pto = to; 212 *pto = to;
206 } 213 }
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)
214 { 221 {
215 if (errno == EINTR) 222 if (errno == EINTR)
216 continue; 223 continue;
217 logmsg (LOG_ERR, "select: %s", strerror (errno)); 224 logmsg (LOG_ERR, "select: %s", strerror (errno));
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
244 269
diff --git a/src/process.c b/src/process.c
index c5eb321..ec64589 100644
--- a/src/process.c
+++ b/src/process.c
@@ -21,12 +21,26 @@ struct spool_list
21 struct spool_list *next; 21 struct spool_list *next;
22 struct spool spool; 22 struct spool spool;
23}; 23};
24 24
25static struct spool_list *spool_list; 25static struct spool_list *spool_list;
26 26
27int
28for_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
27void 41void
28register_spool (struct spool *spool) 42register_spool (struct spool *spool)
29{ 43{
30 struct spool_list *sp = grecs_malloc (sizeof *sp); 44 struct spool_list *sp = grecs_malloc (sizeof *sp);
31 sp->spool = *spool; 45 sp->spool = *spool;
32 sp->next = spool_list; 46 sp->next = spool_list;
@@ -119,28 +133,92 @@ parse_file_name (const char *name, struct file_info *finfo)
119 return; 133 return;
120 } 134 }
121 } 135 }
122 abort (); /* should not happen */ 136 abort (); /* should not happen */
123} 137}
124 138
125int 139void
140file_info_cleanup (struct file_info *finfo)
141{
142 free (finfo->name);
143 memset (finfo, 0, sizeof (*finfo));
144}
145
146static int
126match_uid_p (uid_t uid, int uc, uid_t *uv) 147match_uid_p (uid_t uid, int uc, uid_t *uv)
127{ 148{
128 int i; 149 int i;
129 if (!uv) 150 if (!uv)
130 return 1; 151 return 1;
131 for (i = 0; i < uc; i++) 152 for (i = 0; i < uc; i++)
132 if (uv[i] == uid) 153 if (uv[i] == uid)
133 return 1; 154 return 1;
134 return 0; 155 return 0;
135} 156}
136 157
158int
159spool_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
198int
199spool_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 */
139void 217void
140scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv) 218scan_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;
144 222
145 if (debug_level) 223 if (debug_level)
146 logmsg (LOG_DEBUG, "%s -> %s", spool->source_dir, 224 logmsg (LOG_DEBUG, "%s -> %s", spool->source_dir,
@@ -163,73 +241,28 @@ scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv)
163 241
164 timer_start ("spool"); 242 timer_start ("spool");
165 /* FIXME: prefix spool tag with something */ 243 /* FIXME: prefix spool tag with something */
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
228int 261int
229scan_spool (const struct spool *spool, int uc, uid_t *uv) 262scan_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);
233 switch (rc) 266 switch (rc)
234 { 267 {
235 case LOCK_OK: 268 case LOCK_OK:
@@ -246,18 +279,39 @@ scan_spool (const struct spool *spool, int uc, uid_t *uv)
246 break; 279 break;
247 } 280 }
248 free (lockfile); 281 free (lockfile);
249 return rc; 282 return rc;
250} 283}
251 284
252static void 285int
253close_dictionaries (struct spool *spool) 286spool_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
305void
306spool_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 */
261int 315int
262scan_all_spools (int uidc, uid_t *uidv) 316scan_all_spools (int uidc, uid_t *uidv)
263{ 317{
@@ -268,13 +322,13 @@ scan_all_spools (int uidc, uid_t *uidv)
268 for (sp = spool_list; sp; sp = sp->next) 322 for (sp = spool_list; sp; sp = sp->next)
269 if (enabled_spool_p (&sp->spool)) 323 if (enabled_spool_p (&sp->spool))
270 if (scan_spool (&sp->spool, uidc, uidv)) 324 if (scan_spool (&sp->spool, uidc, 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}
278 332
279void 333void
280spool_create_timers () 334spool_create_timers ()
diff --git a/src/triplet.c b/src/triplet.c
index 79ca8c2..05b7536 100644
--- a/src/triplet.c
+++ b/src/triplet.c
@@ -29,13 +29,13 @@ hash_triplet_hasher (void *data, unsigned long n_buckets)
29/* Compare two strings for equality. */ 29/* Compare two strings for equality. */
30static int 30static int
31hash_triplet_compare (void const *data1, void const *data2) 31hash_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 */
39void 39void
40hash_triplet_free (void *data) 40hash_triplet_free (void *data)
41{ 41{
@@ -95,12 +95,13 @@ register_file (struct file_info *finfo, const struct spool *spool)
95 grecs_alloc_die (); 95 grecs_alloc_die ();
96 } 96 }
97 97
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)
104 grecs_alloc_die (); 105 grecs_alloc_die ();
105 free (key.name); 106 free (key.name);
106 if (install) 107 if (install)
@@ -108,12 +109,34 @@ register_file (struct file_info *finfo, const struct spool *spool)
108 ret->spool = spool; 109 ret->spool = spool;
109 ret->acc = txtacc_create (); 110 ret->acc = txtacc_create ();
110 } 111 }
111 ret->file[finfo->type] = *finfo; 112 ret->file[finfo->type] = *finfo;
112} 113}
113 114
115struct file_triplet *
116triplet_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 */
116static int 139static int
117triplet_expired_p (struct file_triplet *trp, time_t ttl) 140triplet_expired_p (struct file_triplet *trp, time_t ttl)
118{ 141{
119 int i; 142 int i;
@@ -144,27 +167,26 @@ enum triplet_state
144 triplet_incomplete, /* Incomplete triplet: some files are missing */ 167 triplet_incomplete, /* Incomplete triplet: some files are missing */
145 triplet_bad, /* Bad triplet. Should be removed immediately. */ 168 triplet_bad, /* Bad triplet. Should be removed immediately. */
146 }; 169 };
147 170
148 171
149static enum triplet_state 172static enum triplet_state
150check_triplet_state (struct file_triplet *trp) 173check_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
158 && trp->file[file_signature].name == 0) 181 && trp->file[file_signature].name == 0)
159 { 182 {
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
168 && trp->file[file_dist].sb.st_uid == 190 && trp->file[file_dist].sb.st_uid ==
169 trp->file[file_directive].sb.st_uid) 191 trp->file[file_directive].sb.st_uid)
170 return triplet_complete; 192 return triplet_complete;
@@ -209,13 +231,13 @@ triplet_processor (void *data, void *proc_data)
209 logmsg (LOG_DEBUG, "FILE %s, DIST=%s, SIG=%s, DIRECTIVE=%s", 231 logmsg (LOG_DEBUG, "FILE %s, DIST=%s, SIG=%s, DIRECTIVE=%s",
210 trp->name, 232 trp->name,
211 SP (trp->file[file_dist].name), 233 SP (trp->file[file_dist].name),
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:
219 if (debug_level) 241 if (debug_level)
220 logmsg (LOG_DEBUG, _("processing triplet `%s'"), trp->name); 242 logmsg (LOG_DEBUG, _("processing triplet `%s'"), trp->name);
221 if (process_directives (trp)) 243 if (process_directives (trp))
@@ -243,17 +265,19 @@ triplet_processor (void *data, void *proc_data)
243 265
244 return 0; 266 return 0;
245} 267}
246 268
247/* Process all triplets from the table according to the SPOOL */ 269/* Process all triplets from the table according to the SPOOL */
248void 270void
249enumerate_triplets (const struct spool *spool) 271spool_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);
257 grecs_symtab_clear (triplet_table); 281 grecs_symtab_clear (triplet_table);
258 } 282 }
259} 283}
@@ -261,12 +285,78 @@ enumerate_triplets (const struct spool *spool)
261size_t 285size_t
262count_collected_triplets () 286count_collected_triplets ()
263{ 287{
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
291static int
292triplet_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
320size_t
321count_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
329void
330triplet_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
268static const char * 358static const char *
269expand_project_base (struct metadef *def, void *data) 359expand_project_base (struct metadef *def, void *data)
270{ 360{
271 struct file_triplet *trp = data; 361 struct file_triplet *trp = data;
272 return trp->project; 362 return trp->project;
diff --git a/src/verify.c b/src/verify.c
index 1409889..4a108bc 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -199,13 +199,13 @@ uploader_find_frp (struct uploader_info *list, const char *fpr)
199 if (list->fpr && strcmp (list->fpr, fpr) == 0) 199 if (list->fpr && strcmp (list->fpr, fpr) == 0)
200 break; 200 break;
201 return list; 201 return list;
202} 202}
203 203
204int 204int
205verify_directive_file (struct file_triplet *trp) 205verify_directive_file (struct file_triplet *trp, int noath)
206{ 206{
207 char *command; 207 char *command;
208 int rc; 208 int rc;
209 void *md; 209 void *md;
210 size_t nrows, ncols, i; 210 size_t nrows, ncols, i;
211 struct uploader_info *head, *tail; 211 struct uploader_info *head, *tail;
@@ -217,111 +217,114 @@ verify_directive_file (struct file_triplet *trp)
217 217
218 if (!trp->file[file_directive].name) 218 if (!trp->file[file_directive].name)
219 return 1; 219 return 1;
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 {
325 int i; 328 int i;
326 for (i = 0; trp->directive[i]; i++) 329 for (i = 0; trp->directive[i]; i++)
327 logmsg (LOG_DEBUG, "directive[%d] = %s", i, trp->directive[i]); 330 logmsg (LOG_DEBUG, "directive[%d] = %s", i, trp->directive[i]);
diff --git a/src/vtab.c b/src/vtab.c
index 2f8a85e..cec6fc0 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -21,19 +21,19 @@ struct virt_tab_reg
21 char *scheme; 21 char *scheme;
22 struct virt_tab vtab; 22 struct virt_tab vtab;
23}; 23};
24 24
25static struct virt_tab_reg reg[] = { 25static 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};
37 37
38int 38int
39url_to_vtab (mu_url_t url, struct virt_tab *vtab) 39url_to_vtab (mu_url_t url, struct virt_tab *vtab)
@@ -50,12 +50,20 @@ url_to_vtab (mu_url_t url, struct virt_tab *vtab)
50 return 0; 50 return 0;
51 } 51 }
52 return 1; 52 return 1;
53} 53}
54 54
55 55
56const char *
57get_path (struct spool *sp)
58{
59 if (!sp->vtab.get_path)
60 return NULL;
61 return sp->vtab.get_path (sp);
62}
63
56int 64int
57move_file (struct file_triplet *trp, enum file_type file_id) 65move_file (struct file_triplet *trp, enum file_type file_id)
58{ 66{
59 int rc = trp->spool->vtab.move_file (trp, file_id); 67 int rc = trp->spool->vtab.move_file (trp, file_id);
60 report_add ("Move %s to %s: %s", trp->file[file_id].name, trp->relative_dir, 68 report_add ("Move %s to %s: %s", trp->file[file_id].name, trp->relative_dir,
61 rc == 0 ? "OK" : "FAILED"); 69 rc == 0 ? "OK" : "FAILED");
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 */
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 }
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
@@ -325,19 +325,33 @@ wydawca_daemon ()
325 remove_pidfile (); 325 remove_pidfile ();
326} 326}
327 327
328 328
329#include "cmdline.h" 329#include "cmdline.h"
330 330
331void
332version_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
331int 344int
332main (int argc, char **argv) 345main (int argc, char **argv)
333{ 346{
334 struct grecs_node *tree; 347 struct grecs_node *tree;
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 ();
341 355
342 x_argv = argv; 356 x_argv = argv;
343 parse_options (argc, argv); 357 parse_options (argc, argv);
diff --git a/src/wydawca.h b/src/wydawca.h
index 5de1f3e..722fc9b 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -202,12 +202,13 @@ struct file_triplet
202#define TRIPLET_GID(t) ((t)->file[file_directive].sb.st_gid) 202#define TRIPLET_GID(t) ((t)->file[file_directive].sb.st_gid)
203 203
204 204
205 205
206struct virt_tab 206struct 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);
211 int (*symlink_file) (struct file_triplet *trp, 212 int (*symlink_file) (struct file_triplet *trp,
212 const char *wanted_src, 213 const char *wanted_src,
213 const char *wanted_dst); 214 const char *wanted_dst);
@@ -226,12 +227,13 @@ struct spool
226 const char *dest_dir; /* Directory part of the above */ 227 const char *dest_dir; /* Directory part of the above */
227 struct virt_tab vtab; /* Virtual method table */ 228 struct virt_tab vtab; /* Virtual method table */
228 229
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;
235}; 237};
236 238
237#define ASGN_SPOOL(spool, trp, faction) \ 239#define ASGN_SPOOL(spool, trp, faction) \
@@ -369,12 +371,15 @@ extern char *wydawca_gpg_homedir;
369extern char *default_check_script; 371extern char *default_check_script;
370extern char *temp_homedir; 372extern char *temp_homedir;
371 373
372extern unsigned min_directive_version; 374extern unsigned min_directive_version;
373extern unsigned max_directive_version; 375extern unsigned max_directive_version;
374 376
377extern struct spool fake_spool;
378extern struct spool inotify_spool;
379
375 #define UPDATE_STATS(what) \ 380 #define UPDATE_STATS(what) \
376 do \ 381 do \
377 { \ 382 { \
378 if (what >= MAX_STAT) abort(); \ 383 if (what >= MAX_STAT) abort(); \
379 wydawca_stat[what]++; \ 384 wydawca_stat[what]++; \
380 } \ 385 } \
@@ -406,25 +411,37 @@ enum exec_result
406 }; 411 };
407 412
408enum exec_result wydawca_exec (int argc, const char **argv, int *retcode); 413enum 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 */
412int scan_spool (const struct spool *spool, int uc, uid_t *uv); 417int scan_spool (struct spool *spool, int uc, uid_t *uv);
413int scan_all_spools (int, uid_t *); 418int scan_all_spools (int, uid_t *);
414void spool_create_timers (void); 419void spool_create_timers (void);
415 420
421int spool_add_new_file (const struct spool *spool, const char *name,
422 int uc, uid_t *uv);
423int spool_cwd_add_new_file (const struct spool *spool, const char *name,
424 int uc, uid_t *uv);
425int spool_open_dictionaries (struct spool *spool);
426void spool_close_dictionaries (struct spool *spool);
427
428int for_each_spool (int (*fun) (struct spool *, void *), void *data);
416void register_spool (struct spool *spool); 429void register_spool (struct spool *spool);
417struct spool *wydawca_find_spool (const char *name); 430struct spool *wydawca_find_spool (const char *name);
418void register_file (struct file_info *finfo, const struct spool *spool); 431void register_file (struct file_info *finfo, const struct spool *spool);
419void enumerate_triplets (const struct spool *); 432void spool_commit_triplets (struct spool *);
420size_t count_collected_triplets (void); 433size_t count_collected_triplets (void);
434size_t count_processable_triplets (void);
435
421char *triplet_expand_param (const char *tmpl, struct file_triplet *trp); 436char *triplet_expand_param (const char *tmpl, struct file_triplet *trp);
422char *triplet_expand_dictionary_query (struct dictionary *dict, void *handle, 437char *triplet_expand_dictionary_query (struct dictionary *dict, void *handle,
423 struct file_triplet *trp); 438 struct file_triplet *trp);
424 439
440void triplet_remove_file (struct spool *spool, const char *name);
441
425/* General-purpose dictionary support */ 442/* General-purpose dictionary support */
426struct dictionary *dictionary_new (enum dictionary_id id, 443struct dictionary *dictionary_new (enum dictionary_id id,
427 enum dictionary_type type); 444 enum dictionary_type type);
428int dictionary_init (struct dictionary *dict); 445int dictionary_init (struct dictionary *dict);
429int dictionary_done (struct dictionary *dict); 446int dictionary_done (struct dictionary *dict);
430void *dictionary_open (struct dictionary *dict); 447void *dictionary_open (struct dictionary *dict);
@@ -439,13 +456,13 @@ int dictionary_quote_string (struct dictionary *dict, void *handle,
439 const char *input, char **poutput, size_t *psize); 456 const char *input, char **poutput, size_t *psize);
440 457
441unsigned dictionary_num_rows (struct dictionary *dict); 458unsigned dictionary_num_rows (struct dictionary *dict);
442unsigned dictionary_num_cols (struct dictionary *dict); 459unsigned dictionary_num_cols (struct dictionary *dict);
443 460
444/* Verification functions */ 461/* Verification functions */
445int verify_directive_file (struct file_triplet *trp); 462int verify_directive_file (struct file_triplet *trp, int noath);
446int verify_directive_signature (struct file_triplet *trp); 463int verify_directive_signature (struct file_triplet *trp);
447int verify_detached_signature (struct file_triplet *trp); 464int verify_detached_signature (struct file_triplet *trp);
448int fill_project_name (struct file_triplet *trp); 465int fill_project_name (struct file_triplet *trp);
449struct uploader_info *uploader_find_frp (struct uploader_info *list, 466struct uploader_info *uploader_find_frp (struct uploader_info *list,
450 const char *frp); 467 const char *frp);
451 468
@@ -482,27 +499,25 @@ int assert_string_arg (grecs_locus_t *, enum grecs_callback_command,
482 const grecs_value_t *); 499 const grecs_value_t *);
483 500
484 501
485/* vtab.c */ 502/* vtab.c */
486int url_to_vtab (mu_url_t url, struct virt_tab *vtab); 503int url_to_vtab (mu_url_t url, struct virt_tab *vtab);
487 504
488int 505const 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);
490int 507 int archive_file (struct file_triplet *trp, const char *file_name);
491 archive_file (struct file_triplet *trp, const char *file_name); 508int symlink_file (struct file_triplet *trp,
492int 509 const char *wanted_src, const char *wanted_dst);
493symlink_file (struct file_triplet *trp, 510int rmsymlink_file (struct file_triplet *trp, const char *file_name);
494 const char *wanted_src, const char *wanted_dst);
495int
496rmsymlink_file (struct file_triplet *trp, const char *file_name);
497 511
498 512
499/* diskio.c */ 513/* diskio.c */
500char *concat_dir (const char *base, const char *name, size_t *pbaselen); 514char *concat_dir (const char *base, const char *name, size_t *pbaselen);
501int copy_file (const char *file, const char *dst_file); 515int copy_file (const char *file, const char *dst_file);
502 516
517const char *dir_get_path (struct spool *sp);
503int dir_test_url (mu_url_t url, grecs_locus_t *locus); 518int dir_test_url (mu_url_t url, grecs_locus_t *locus);
504int dir_move_file (struct file_triplet *trp, enum file_type file_id); 519int dir_move_file (struct file_triplet *trp, enum file_type file_id);
505int dir_archive_file (struct file_triplet *trp, const char *reldir); 520int dir_archive_file (struct file_triplet *trp, const char *reldir);
506int dir_symlink_file (struct file_triplet *trp, 521int dir_symlink_file (struct file_triplet *trp,
507 const char *wanted_src, const char *wanted_dst); 522 const char *wanted_src, const char *wanted_dst);
508int dir_rmsymlink_file (struct file_triplet *trp, const char *file_name); 523int dir_rmsymlink_file (struct file_triplet *trp, const char *file_name);
@@ -535,13 +550,13 @@ void report_init (void);
535void report_add (const char *fmt, ...); 550void report_add (const char *fmt, ...);
536void report_finish (void); 551void report_finish (void);
537extern char *report_string; 552extern char *report_string;
538 553
539 554
540/* job.c */ 555/* job.c */
541void schedule_job (const struct spool *spool, uid_t uid); 556void schedule_job (struct spool *spool, uid_t uid);
542void job_init (void); 557void job_init (void);
543void job_queue_runner (void); 558void job_queue_runner (void);
544 559
545 560
546/* profile.c */ 561/* profile.c */
547void check_pidfile (void); 562void check_pidfile (void);
@@ -585,6 +600,14 @@ void txtacc_grow (struct txtacc *acc, const char *buf, size_t size);
585 { \ 600 { \
586 char __ch = c; \ 601 char __ch = c; \
587 txtacc_grow (acc, &__ch, 1); \ 602 txtacc_grow (acc, &__ch, 1); \
588 } \ 603 } \
589 while (0) 604 while (0)
590char *txtacc_finish (struct txtacc *acc, int steal); 605char *txtacc_finish (struct txtacc *acc, int steal);
606
607#ifdef WITH_INOTIFY
608int watcher_init (void);
609int watcher_run (int);
610#else
611# define watcher_init() -1
612# define watcher_run(c)
613#endif

Return to:

Send suggestions and report system problems to the System administrator.