summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--configure.ac32
-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
12 files changed, 712 insertions, 204 deletions
diff --git a/configure.ac b/configure.ac
index a503cc7..2683b9b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,8 @@
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
17AC_PREREQ(2.63) 17AC_PREREQ(2.63)
18AC_INIT([wydawca], 2.1.90, [bug-wydawca@gnu.org.ua]) 18AC_INIT([wydawca], 2.1.90, [bug-wydawca@gnu.org.ua], [wydawca],
19 [http://www.gnu.org.ua/software/wydawca])
19AC_CONFIG_SRCDIR([src/wydawca.c]) 20AC_CONFIG_SRCDIR([src/wydawca.c])
20AC_CONFIG_AUX_DIR([build-aux]) 21AC_CONFIG_AUX_DIR([build-aux])
21AC_CONFIG_HEADER([config.h]) 22AC_CONFIG_HEADER([config.h])
@@ -33,7 +34,7 @@ AC_PROG_RANLIB
33# Checks for header files. 34# Checks for header files.
34AC_HEADER_STDC 35AC_HEADER_STDC
35AC_HEADER_SYS_WAIT 36AC_HEADER_SYS_WAIT
36AC_CHECK_HEADERS([stdlib.h string.h sys/file.h unistd.h]) 37AC_CHECK_HEADERS([stdlib.h string.h sys/file.h unistd.h sys/inotify.h])
37 38
38# Checks for typedefs, structures, and compiler characteristics. 39# Checks for typedefs, structures, and compiler characteristics.
39AC_C_CONST 40AC_C_CONST
@@ -50,7 +51,9 @@ AC_FUNC_MALLOC
50AC_FUNC_MEMCMP 51AC_FUNC_MEMCMP
51AC_FUNC_STAT 52AC_FUNC_STAT
52AC_FUNC_VPRINTF 53AC_FUNC_VPRINTF
53AC_CHECK_FUNCS([fchdir memset strchr strdup strerror strrchr setegid setregid setresgid setresuid seteuid setreuid vsyslog sysconf getdtablesize]) 54AC_CHECK_FUNCS([fchdir memset strchr strdup strerror strrchr setegid setregid\
55 setresgid setresuid seteuid setreuid vsyslog sysconf getdtablesize\
56 inotify_init])
54 57
55 # ********************** 58 # **********************
56# Mailutils 59# Mailutils
@@ -107,6 +110,29 @@ if test "$status_tcpwrap" = yes; then
107 AC_DEFINE_UNQUOTED([WITH_LIBWRAP],1,[Defined if compiling with libwrap]) 110 AC_DEFINE_UNQUOTED([WITH_LIBWRAP],1,[Defined if compiling with libwrap])
108fi 111fi
109 112
113 # **********************
114# TCP wrappers
115 # **********************
116AC_ARG_WITH(inotify,
117 AC_HELP_STRING([--with-inotify],
118 [compile with inotify(7) support (Linux-specific)]),
119 [status_inotify=${withval}],
120 [status_inotify=probe])
121if test $status_inotify != no; then
122 if test "$ac_cv_header_sys_inotify_h" = yes &&
123 test "$ac_cv_func_inotify_init" = yes; then
124 status_inotify=yes
125 elif test $status_inotify = probe; then
126 status_inotify=no
127 else
128 AC_MSG_FAILURE([Requested inotify(7) support is not available])
129 fi
130fi
131if test $status_inotify = yes; then
132 AC_DEFINE([WITH_INOTIFY],1,[Set to 1 if inotify(7) is to be used])
133fi
134AM_CONDITIONAL([COND_INOTIFY],[test $status_inotify = yes])
135
110# Grecs subsystem 136# Grecs subsystem
111GRECS_SETUP([grecs],[git2chg getopt tests]) 137GRECS_SETUP([grecs],[git2chg getopt tests])
112 138
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
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\
@@ -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
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
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
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.
diff --git a/src/job.c b/src/job.c
index 4a97f88..3fae432 100644
--- a/src/job.c
+++ b/src/job.c
@@ -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;
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
@@ -76,13 +77,22 @@ job_active_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 {
@@ -191,7 +201,7 @@ job_insert (struct job *job, struct job *elt)
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
diff --git a/src/net.c b/src/net.c
index 4857fa2..3157fe8 100644
--- a/src/net.c
+++ b/src/net.c
@@ -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
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);
@@ -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
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{
@@ -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
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;
@@ -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
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;
@@ -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
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);
@@ -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
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 */
@@ -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
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
@@ -147,11 +170,11 @@ enum triplet_state
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
@@ -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 */
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);
@@ -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
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)
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
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;
@@ -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 {
diff --git a/src/vtab.c b/src/vtab.c
index 2f8a85e..cec6fc0 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -24,13 +24,13 @@ struct virt_tab_reg
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};
@@ -53,6 +53,14 @@ url_to_vtab (mu_url_t url, struct virt_tab *vtab)
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{
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
@@ -328,6 +328,19 @@ wydawca_daemon ()
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{
@@ -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
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);
@@ -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;
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 { \
@@ -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 */
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);
@@ -442,7 +459,7 @@ unsigned 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);
@@ -485,21 +502,19 @@ int assert_string_arg (grecs_locus_t *, enum grecs_callback_command,
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);
@@ -538,7 +553,7 @@ extern 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
@@ -588,3 +603,11 @@ void txtacc_grow (struct txtacc *acc, const char *buf, size_t size);
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.