aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Wydawca. If not, see <http://www.gnu.org/licenses/>.
sbin_PROGRAMS=wydawca
+
+if COND_INOTIFY
+ WATCHER_C=watcher.c
+endif
+
wydawca_SOURCES=\
backup.c\
builtin.c\
builtin.h\
cmdline.h\
config.c\
@@ -45,13 +50,14 @@ wydawca_SOURCES=\
mail.h\
mail.c\
vtab.c\
null.c\
timer.c\
txtacc.c\
- report.c
+ report.c\
+ $(WATCHER_C)
BUILT_SOURCES=cmdline.h
EXTRA_DIST=cmdline.opt pp-setup update-2.0.awk
SUFFIXES=.opt .c .h
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)
if (directive_get_value (trp, "replace", &val))
return 1;
return strcmp (val, "true") == 0;
}
+const char *
+dir_get_path (struct spool *sp)
+{
+ return sp->source_dir;
+}
+
/* Move the part FILE_ID of the triplet TRP between the directories in
TRP->SPOOL. TRP->RELATIVE_DIR gives relative directory (i.e. the
directory part of the file name) for backup purposes.
Do nothing if dry_run_mode is set. */
int
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 @@
#define STATE_ACTIVE 0x04
struct job
{
struct job *next, *prev;
int state;
- const struct spool *spool;
+ struct spool *spool;
uid_t uid;
pid_t pid;
time_t timestamp;
int exit_status;
};
struct job *queue;
size_t jobmax;
size_t jobcnt;
-static struct spool fake_spool = { "all spools" };
+struct spool fake_spool = { "all spools" },
+ inotify_spool = { "inotify" } ;
static int wakeup;
RETSIGTYPE
queue_signal (int sig)
{
@@ -73,19 +74,28 @@ job_active_count ()
for (job = queue; job; job = job->next)
if (job->state & STATE_ACTIVE)
count++;
return count;
}
+static int
+procspool (struct spool *spool, void *data)
+{
+ spool_commit_triplets (spool);
+ return 0;
+}
+
int
wydawca_scanner (struct job *job)
{
int rc;
initstats();
timer_start ("wydawca");
- if (job->spool == &fake_spool)
+ if (job->spool == &inotify_spool)
+ rc = for_each_spool (procspool, NULL);
+ else if (job->spool == &fake_spool)
rc = scan_all_spools (1, &job->uid);
else
{
spool_create_timers ();
rc = scan_spool (job->spool, 1, &job->uid);
}
@@ -188,13 +198,13 @@ job_insert (struct job *job, struct job *elt)
if (p)
p->prev = job;
}
void
-schedule_job (const struct spool *spool, uid_t uid)
+schedule_job (struct spool *spool, uid_t uid)
{
struct job *job;
if (!spool)
spool = &fake_spool;
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 @@
static int
open_listener ()
{
int fd;
if (listen_sockaddr.sa == NULL)
- {
- logmsg (LOG_CRIT, _("listener address is not configured"));
- exit (EX_CONFIG);
- }
+ return -1;
fd = socket (listen_sockaddr.sa->sa_family, SOCK_STREAM, 0);
if (fd == -1)
{
logmsg (LOG_CRIT, _("cannot create socket: %s"),
strerror(errno));
@@ -96,13 +93,13 @@ trim_crlf (char *s)
void
handle_connection (FILE *in, FILE *out)
{
char *buf = NULL;
size_t buflen = 0;
- const struct spool *spool;
+ struct spool *spool;
char *p;
struct passwd *pw;
if (grecs_getline (&buf, &buflen, in) <= 0)
return;
trim_crlf (buf);
@@ -171,74 +168,102 @@ sig_term (int sig)
}
void
wydawca_listener ()
{
int ctlfd = open_listener ();
+ int wfd = watcher_init ();
+ int maxfd = 0;
+
+ if (ctlfd != -1)
+ maxfd = ctlfd;
+
+ if (wfd != -1 && wfd > maxfd)
+ maxfd = wfd;
+ if (maxfd == 0)
+ {
+ logmsg (LOG_CRIT,
+ _("listener address is not configured and inotify is not available"));
+ exit (EX_CONFIG);
+ }
+
job_init ();
signal (SIGHUP, sig_hup);
signal (SIGTERM, sig_term);
signal (SIGQUIT, sig_term);
signal (SIGINT, sig_term);
while (!terminate)
{
- int fd;
- FILE *in, *out;
int rc;
fd_set rset;
struct timeval to, *pto;
- union {
- struct sockaddr sa;
- struct sockaddr_in s_in;
- struct sockaddr_un s_un;
- } addr;
- socklen_t len;
job_queue_runner ();
FD_ZERO (&rset);
- FD_SET (ctlfd, &rset);
+ if (ctlfd != -1)
+ FD_SET (ctlfd, &rset);
+ if (wfd != -1)
+ FD_SET (wfd, &rset);
if (wakeup_interval)
{
to.tv_sec = wakeup_interval;
to.tv_usec = 0;
*pto = to;
}
else
pto = NULL;
- rc = select (ctlfd + 1, &rset, NULL, NULL, pto);
+ rc = select (maxfd + 1, &rset, NULL, NULL, pto);
if (rc == 0)
continue;
else if (rc < 0)
{
if (errno == EINTR)
continue;
logmsg (LOG_ERR, "select: %s", strerror (errno));
break;
}
- len = sizeof (addr);
- fd = accept (ctlfd, (struct sockaddr*) &addr, &len);
- if (fd == -1)
- continue;
- /* FIXME: Use Mailutils ACLs? */
-#ifdef WITH_LIBWRAP
- if (!tcpwrap_access(fd))
+ if (wfd != -1 && FD_ISSET (wfd, &rset))
{
- close(fd);
- continue;
+ watcher_run (wfd);
}
+
+ if (ctlfd != -1 && FD_ISSET (ctlfd, &rset))
+ {
+ int fd;
+ FILE *in, *out;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in s_in;
+ struct sockaddr_un s_un;
+ } addr;
+ socklen_t len;
+
+ len = sizeof (addr);
+ fd = accept (ctlfd, (struct sockaddr*) &addr, &len);
+ if (fd == -1)
+ continue;
+ /* FIXME: Use Mailutils ACLs? */
+#ifdef WITH_LIBWRAP
+ if (!tcpwrap_access(fd))
+ {
+ close(fd);
+ continue;
+ }
#endif
- in = fdopen (fd, "r");
- setlinebuf (in);
- out = fdopen (fd, "w");
- setlinebuf (out);
- handle_connection (in, out);
- fclose (in);
- fclose (out);
+ in = fdopen (fd, "r");
+ setlinebuf (in);
+ out = fdopen (fd, "w");
+ setlinebuf (out);
+ handle_connection (in, out);
+ fclose (in);
+ fclose (out);
+ }
}
}
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
struct spool_list *next;
struct spool spool;
};
static struct spool_list *spool_list;
+int
+for_each_spool (int (*fun) (struct spool *, void *), void *data)
+{
+ struct spool_list *sp;
+
+ for (sp = spool_list; sp; sp = sp->next)
+ {
+ int rc = fun (&sp->spool, data);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
void
register_spool (struct spool *spool)
{
struct spool_list *sp = grecs_malloc (sizeof *sp);
sp->spool = *spool;
sp->next = spool_list;
@@ -119,28 +133,92 @@ parse_file_name (const char *name, struct file_info *finfo)
return;
}
}
abort (); /* should not happen */
}
-int
+void
+file_info_cleanup (struct file_info *finfo)
+{
+ free (finfo->name);
+ memset (finfo, 0, sizeof (*finfo));
+}
+
+static int
match_uid_p (uid_t uid, int uc, uid_t *uv)
{
int i;
if (!uv)
return 1;
for (i = 0; i < uc; i++)
if (uv[i] == uid)
return 1;
return 0;
}
+int
+spool_cwd_add_new_file (const struct spool *spool, const char *name,
+ int uc, uid_t *uv)
+{
+ struct stat st;
+ struct file_info finfo;
+
+ if (stat (name, &st))
+ {
+ logmsg (LOG_ERR, _("cannot stat file %s/%s: %s"),
+ spool->source_dir, name, strerror (errno));
+ return -1;
+ }
+
+ if (!S_ISREG (st.st_mode))
+ {
+ logmsg (LOG_NOTICE, _("not a regular file: %s/%s"),
+ spool->source_dir, name);
+ return -1;
+ }
+
+ if (!match_uid_p (st.st_uid, uc, uv))
+ {
+ if (debug_level)
+ logmsg (LOG_DEBUG, _("ignoring file: %s/%s"),
+ spool->source_dir, name);
+ return -1;
+ }
+
+ finfo.sb = st;
+ parse_file_name (name, &finfo);
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, _("found file %s: %s, stem: %.*s"), name,
+ file_type_str (finfo.type), finfo.root_len, finfo.name);
+
+ register_file (&finfo, spool);
+ return 0;
+}
+
+int
+spool_add_new_file (const struct spool *spool, const char *name,
+ int uc, uid_t *uv)
+{
+ if (debug_level)
+ logmsg (LOG_DEBUG, "%s -> %s, adding %s", spool->source_dir,
+ mu_url_to_string (spool->dest_url), name);
+
+ if (chdir (spool->source_dir))
+ {
+ logmsg (LOG_ERR, _("cannot chdir to %s: %s"), spool->source_dir,
+ strerror (errno));
+ return -1;
+ }
+ return spool_cwd_add_new_file (spool, name, uc, uv);
+}
+
/* Scan upload directory from the DPAIR and register all files found
there, forming triplets when possible */
void
-scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv)
+scan_spool_unlocked (struct spool *spool, int uc, uid_t *uv)
{
DIR *dir;
struct dirent *ent;
if (debug_level)
logmsg (LOG_DEBUG, "%s -> %s", spool->source_dir,
@@ -163,73 +241,28 @@ scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv)
timer_start ("spool");
/* FIXME: prefix spool tag with something */
timer_start (spool->tag);
while ((ent = readdir (dir)))
{
- struct stat st;
- struct file_info finfo;
-
if (strcmp (ent->d_name, ".") == 0 || strcmp (ent->d_name, "..") == 0)
continue;
-
- if (stat (ent->d_name, &st))
- {
- logmsg (LOG_ERR, _("cannot stat file %s/%s: %s"),
- spool->source_dir, ent->d_name,
- strerror (errno));
- continue;
- }
-
- if (!S_ISREG (st.st_mode))
- {
- logmsg (LOG_NOTICE, _("not a regular file: %s/%s"),
- spool->source_dir, ent->d_name);
- continue;
- }
-
- if (!match_uid_p (st.st_uid, uc, uv))
- {
- if (debug_level)
- logmsg (LOG_DEBUG, _("ignoring file: %s/%s"),
- spool->source_dir, ent->d_name);
- continue;
- }
-
- finfo.sb = st;
- parse_file_name (ent->d_name, &finfo);
-
- if (debug_level)
- logmsg (LOG_DEBUG, _("found file %s: %s, stem: %.*s"), ent->d_name,
- file_type_str (finfo.type), finfo.root_len, finfo.name);
-
- register_file (&finfo, spool);
+ spool_cwd_add_new_file (spool, ent->d_name, uc, uv);
}
closedir (dir);
if (count_collected_triplets () > 0)
- {
- int i;
-
- for (i = 0; i < dictionary_count; i++)
- {
- if (dictionary_init (spool->dictionary[i]))
- {
- logmsg (LOG_ERR, _("failed to initialize dictionary %d"), i);
- return;
- }
- }
- enumerate_triplets (spool);
- }
+ spool_commit_triplets (spool);
+
timer_stop (spool->tag);
timer_stop ("spool");
}
int
-scan_spool (const struct spool *spool, int uc, uid_t *uv)
+scan_spool (struct spool *spool, int uc, uid_t *uv)
{
char *lockfile = wydawca_lockname (spool->tag);
int rc = wydawca_lock (lockfile);
switch (rc)
{
case LOCK_OK:
@@ -246,18 +279,39 @@ scan_spool (const struct spool *spool, int uc, uid_t *uv)
break;
}
free (lockfile);
return rc;
}
-static void
-close_dictionaries (struct spool *spool)
+int
+spool_open_dictionaries (struct spool *spool)
+{
+ if (!spool->dict_inited)
+ {
+ int i;
+
+ for (i = 0; i < dictionary_count; i++)
+ {
+ if (dictionary_init (spool->dictionary[i]))
+ {
+ logmsg (LOG_ERR, _("failed to initialize dictionary %d"), i);
+ return -1;
+ }
+ }
+ spool->dict_inited = 1;
+ }
+ return 0;
+}
+
+void
+spool_close_dictionaries (struct spool *spool)
{
int i;
for (i = 0; i < NITEMS (spool->dictionary); i++)
dictionary_done (spool->dictionary[i]);
+ spool->dict_inited = 0;
}
/* Scan all configured update directories */
int
scan_all_spools (int uidc, uid_t *uidv)
{
@@ -268,13 +322,13 @@ scan_all_spools (int uidc, uid_t *uidv)
for (sp = spool_list; sp; sp = sp->next)
if (enabled_spool_p (&sp->spool))
if (scan_spool (&sp->spool, uidc, uidv))
rc++;
for (sp = spool_list; sp; sp = sp->next)
- close_dictionaries (&sp->spool);
+ spool_close_dictionaries (&sp->spool);
timer_stop ("wydawca");
return rc;
}
void
spool_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)
/* Compare two strings for equality. */
static int
hash_triplet_compare (void const *data1, void const *data2)
{
struct file_triplet const *t1 = data1;
struct file_triplet const *t2 = data2;
- return strcmp (t1->name, t2->name);
+ return t1->spool == t2->spool && strcmp (t1->name, t2->name);
}
/* Reclaim memory storage associated with a table entry */
void
hash_triplet_free (void *data)
{
@@ -95,12 +95,13 @@ register_file (struct file_info *finfo, const struct spool *spool)
grecs_alloc_die ();
}
key.name = grecs_malloc (finfo->root_len + 1);
memcpy (key.name, finfo->name, finfo->root_len);
key.name[finfo->root_len] = 0;
+ key.spool = spool;
ret = grecs_symtab_lookup_or_install (triplet_table, &key, &install);
if (!ret)
grecs_alloc_die ();
free (key.name);
if (install)
@@ -108,12 +109,34 @@ register_file (struct file_info *finfo, const struct spool *spool)
ret->spool = spool;
ret->acc = txtacc_create ();
}
ret->file[finfo->type] = *finfo;
}
+struct file_triplet *
+triplet_lookup (struct spool *spool, const char *name)
+{
+ struct file_triplet key, *ret;
+ struct file_info finfo;
+
+ if (!triplet_table)
+ return NULL;
+
+ parse_file_name (name, &finfo);
+
+ key.name = grecs_malloc (finfo.root_len + 1);
+ memcpy (key.name, finfo.name, finfo.root_len);
+ key.name[finfo.root_len] = 0;
+ key.spool = spool;
+
+ ret = grecs_symtab_lookup_or_install (triplet_table, &key, NULL);
+ file_info_cleanup (&finfo);
+
+ return ret;
+}
+
/* Return true if any part of the triplet TRP was modified more than
TTL seconds ago */
static int
triplet_expired_p (struct file_triplet *trp, time_t ttl)
{
int i;
@@ -144,27 +167,26 @@ enum triplet_state
triplet_incomplete, /* Incomplete triplet: some files are missing */
triplet_bad, /* Bad triplet. Should be removed immediately. */
};
static enum triplet_state
-check_triplet_state (struct file_triplet *trp)
+check_triplet_state (struct file_triplet *trp, int noauth)
{
if (trp->file[file_directive].name)
{
- if (verify_directive_file (trp))
+ if (verify_directive_file (trp, noauth))
return triplet_bad;
if (trp->file[file_dist].name == 0
&& trp->file[file_signature].name == 0)
{
if (directive_get_value (trp, "filename", NULL))
return triplet_directive;
}
- else if (trp->file[file_dist].name
- && trp->file[file_signature].name)
+ else if (trp->file[file_dist].name && trp->file[file_signature].name)
{
if (trp->file[file_dist].sb.st_uid ==
trp->file[file_signature].sb.st_uid
&& trp->file[file_dist].sb.st_uid ==
trp->file[file_directive].sb.st_uid)
return triplet_complete;
@@ -209,13 +231,13 @@ triplet_processor (void *data, void *proc_data)
logmsg (LOG_DEBUG, "FILE %s, DIST=%s, SIG=%s, DIRECTIVE=%s",
trp->name,
SP (trp->file[file_dist].name),
SP (trp->file[file_signature].name),
SP (trp->file[file_directive].name));
- switch (check_triplet_state (trp))
+ switch (check_triplet_state (trp, 0))
{
case triplet_directive:
case triplet_complete:
if (debug_level)
logmsg (LOG_DEBUG, _("processing triplet `%s'"), trp->name);
if (process_directives (trp))
@@ -243,17 +265,19 @@ triplet_processor (void *data, void *proc_data)
return 0;
}
/* Process all triplets from the table according to the SPOOL */
void
-enumerate_triplets (const struct spool *spool)
+spool_commit_triplets (struct spool *spool)
{
if (debug_level)
logmsg (LOG_DEBUG, _("processing spool %s (%s)"),
spool->tag, mu_url_to_string (spool->dest_url));
+ if (spool_open_dictionaries (spool))
+ return;
if (triplet_table)
{
grecs_symtab_enumerate (triplet_table, triplet_processor, NULL);
grecs_symtab_clear (triplet_table);
}
}
@@ -261,12 +285,78 @@ enumerate_triplets (const struct spool *spool)
size_t
count_collected_triplets ()
{
return triplet_table ? grecs_symtab_count_entries (triplet_table) : 0;
}
+static int
+triplet_counter (void *data, void *proc_data)
+{
+ struct file_triplet *trp = data;
+ size_t *cp = proc_data;
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "FILE %s, DIST=%s, SIG=%s, DIRECTIVE=%s",
+ trp->name,
+ SP (trp->file[file_dist].name),
+ SP (trp->file[file_signature].name),
+ SP (trp->file[file_directive].name));
+
+ switch (check_triplet_state (trp, 1))
+ {
+ case triplet_directive:
+ case triplet_complete:
+ case triplet_bad:
+ ++*cp;
+ case triplet_incomplete:
+ return 0;
+ }
+
+ if (triplet_expired_p (trp, trp->spool->file_sweep_time))
+ ++*cp;//FIXME
+
+ return 0;
+}
+
+size_t
+count_processable_triplets ()
+{
+ size_t count = 0;
+ if (triplet_table)
+ grecs_symtab_enumerate (triplet_table, triplet_counter, &count);
+ return count;
+}
+
+void
+triplet_remove_file (struct spool *spool, const char *name)
+{
+ struct file_triplet *tp = triplet_lookup (spool, name);
+ int i, n = 0;
+
+ if (!tp)
+ return;
+
+ for (i = 0; i < FILE_TYPE_COUNT; i++)
+ {
+ if (!tp->file[i].name)
+ /* nothing */;
+ else if (strcmp (tp->file[i].name, name) == 0)
+ file_info_cleanup (&tp->file[i]);
+ else
+ n++;
+ }
+
+ if (!n)
+ {
+ if (debug_level > 0)
+ logmsg (LOG_DEBUG, "deleting empty triplet (%s/%s)",
+ spool->source_dir, name);
+ grecs_symtab_remove (triplet_table, tp);
+ }
+}
+
static const char *
expand_project_base (struct metadef *def, void *data)
{
struct file_triplet *trp = data;
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)
if (list->fpr && strcmp (list->fpr, fpr) == 0)
break;
return list;
}
int
-verify_directive_file (struct file_triplet *trp)
+verify_directive_file (struct file_triplet *trp, int noath)
{
char *command;
int rc;
void *md;
size_t nrows, ncols, i;
struct uploader_info *head, *tail;
@@ -217,111 +217,114 @@ verify_directive_file (struct file_triplet *trp)
if (!trp->file[file_directive].name)
return 1;
if (fill_project_name (trp))
return 1;
-
- md = dictionary_open (dict);
- if (!md)
- return 1;
-
- command = triplet_expand_dictionary_query (dict, md, trp);
-
- rc = dictionary_lookup (dict, md, command);
- free (command);
- if (rc)
- {
- logmsg (LOG_ERR, _("cannot get uploaders for %s"), trp->name);
- dictionary_close (dict, md);
- return 1;
- }
-
- nrows = dictionary_num_rows (dict);
- if (nrows == 0)
- {
- logmsg (LOG_ERR, _("found no uploaders for %s"), trp->name);
- dictionary_close (dict, md);
- return 1;
- }
- ncols = dictionary_num_cols (dict);
- if (ncols < 4)
+ if (!noath)
{
- logmsg (LOG_ERR,
- _("project-uploader dictionary error: too few columns (%lu)"),
- (unsigned long) ncols);
- dictionary_close (dict, md);
- return 1;
- }
+ md = dictionary_open (dict);
+ if (!md)
+ return 1;
- head = tail = NULL;
- for (i = 0; i < nrows; i++)
- {
- const char *p;
- struct uploader_info info, *ptr;
+ command = triplet_expand_dictionary_query (dict, md, trp);
- memset (&info, 0, sizeof (info));
- p = dictionary_result (dict, md, i, 0);
- if (p)
- info.name = triplet_strdup (trp, p);
- p = dictionary_result (dict, md, i, 1);
- if (p)
- info.realname = triplet_strdup (trp, p);
- p = dictionary_result (dict, md, i, 2);
- if (p)
- info.email = triplet_strdup (trp, p);
- p = dictionary_result (dict, md, i, 3);
- if (p)
- info.gpg_key = triplet_strdup (trp, p);
+ rc = dictionary_lookup (dict, md, command);
+ free (command);
+ if (rc)
+ {
+ logmsg (LOG_ERR, _("cannot get uploaders for %s"), trp->name);
+ dictionary_close (dict, md);
+ return 1;
+ }
- if (debug_level > 3)
+ nrows = dictionary_num_rows (dict);
+ if (nrows == 0)
{
- logmsg (LOG_DEBUG, _("name: %s"), SP (info.name));
- logmsg (LOG_DEBUG, _("realname: %s"), SP (info.realname));
- logmsg (LOG_DEBUG, _("gpg-key: %s"), SP (info.gpg_key));
- logmsg (LOG_DEBUG, _("email: %s"), SP (info.email));
+ logmsg (LOG_ERR, _("found no uploaders for %s"), trp->name);
+ dictionary_close (dict, md);
+ return 1;
}
- if (!info.name || !info.realname || !info.gpg_key || !info.email)
+ ncols = dictionary_num_cols (dict);
+ if (ncols < 4)
{
logmsg (LOG_ERR,
- _("project-uploader dictionary error: malformed row %lu"),
- (unsigned long) i);
- /* FIXME: Memory not reclaimed */
- continue;
+ _("project-uploader dictionary error: too few columns (%lu)"),
+ (unsigned long) ncols);
+ dictionary_close (dict, md);
+ return 1;
}
-
- ptr = new_uploader_info (&info);
- if (tail)
- tail->next = ptr;
- else
- head = ptr;
- tail = ptr;
- }
+
+ head = tail = NULL;
+ for (i = 0; i < nrows; i++)
+ {
+ const char *p;
+ struct uploader_info info, *ptr;
- dictionary_close (dict, md);
-
- if (!head)
- {
- logmsg (LOG_ERR, _("no valid uploaders found for %s"), trp->name);
- return 1;
- }
-
- trp->uploader_list = head;
- trp->uploader = NULL;
+ memset (&info, 0, sizeof (info));
+ p = dictionary_result (dict, md, i, 0);
+ if (p)
+ info.name = triplet_strdup (trp, p);
+ p = dictionary_result (dict, md, i, 1);
+ if (p)
+ info.realname = triplet_strdup (trp, p);
+ p = dictionary_result (dict, md, i, 2);
+ if (p)
+ info.email = triplet_strdup (trp, p);
+ p = dictionary_result (dict, md, i, 3);
+ if (p)
+ info.gpg_key = triplet_strdup (trp, p);
+
+ if (debug_level > 3)
+ {
+ logmsg (LOG_DEBUG, _("name: %s"), SP (info.name));
+ logmsg (LOG_DEBUG, _("realname: %s"), SP (info.realname));
+ logmsg (LOG_DEBUG, _("gpg-key: %s"), SP (info.gpg_key));
+ logmsg (LOG_DEBUG, _("email: %s"), SP (info.email));
+ }
+
+ if (!info.name || !info.realname || !info.gpg_key || !info.email)
+ {
+ logmsg (LOG_ERR,
+ _("project-uploader dictionary error: malformed row %lu"),
+ (unsigned long) i);
+ /* FIXME: Memory not reclaimed */
+ continue;
+ }
+
+ ptr = new_uploader_info (&info);
+ if (tail)
+ tail->next = ptr;
+ else
+ head = ptr;
+ tail = ptr;
+ }
+
+ dictionary_close (dict, md);
- if (verify_directive_signature (trp))
- {
- /*FIXME: Update stats */
- logmsg (LOG_ERR, _("invalid signature for %s"),
- trp->name ? trp->name : "[unknown]");
- return 1;
+ if (!head)
+ {
+ logmsg (LOG_ERR, _("no valid uploaders found for %s"), trp->name);
+ return 1;
+ }
+
+ trp->uploader_list = head;
+ trp->uploader = NULL;
+
+ if (verify_directive_signature (trp))
+ {
+ /*FIXME: Update stats */
+ logmsg (LOG_ERR, _("invalid signature for %s"),
+ trp->name ? trp->name : "[unknown]");
+ return 1;
+ }
+ else if (debug_level)
+ logmsg (LOG_DEBUG, _("%s: directive file signature OK"), trp->name);
}
- else if (debug_level)
- logmsg (LOG_DEBUG, _("%s: directive file signature OK"), trp->name);
if (debug_level > 1)
{
int i;
for (i = 0; trp->directive[i]; i++)
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
char *scheme;
struct virt_tab vtab;
};
static struct virt_tab_reg reg[] = {
{ "file",
- { dir_test_url, dir_move_file, dir_archive_file, dir_symlink_file,
- dir_rmsymlink_file } },
+ { dir_get_path, dir_test_url, dir_move_file, dir_archive_file,
+ dir_symlink_file, dir_rmsymlink_file } },
{ "dir",
- { dir_test_url, dir_move_file, dir_archive_file, dir_symlink_file,
- dir_rmsymlink_file } },
+ { dir_get_path, dir_test_url, dir_move_file, dir_archive_file,
+ dir_symlink_file, dir_rmsymlink_file } },
{ "null",
- { NULL, null_move_file, null_archive_file, null_symlink_file,
+ { NULL, NULL, null_move_file, null_archive_file, null_symlink_file,
null_rmsymlink_file } },
{ NULL }
};
int
url_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)
return 0;
}
return 1;
}
+const char *
+get_path (struct spool *sp)
+{
+ if (!sp->vtab.get_path)
+ return NULL;
+ return sp->vtab.get_path (sp);
+}
+
int
move_file (struct file_triplet *trp, enum file_type file_id)
{
int rc = trp->spool->vtab.move_file (trp, file_id);
report_add ("Move %s to %s: %s", trp->file[file_id].name, trp->relative_dir,
rc == 0 ? "OK" : "FAILED");
diff --git a/src/watcher.c b/src/watcher.c
new file mode 100644
index 0000000..f8761ee
--- /dev/null
+++ b/src/watcher.c
@@ -0,0 +1,243 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2007, 2009-2012 Sergey Poznyakoff
+
+ Wydawca is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ Wydawca is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with wydawca. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "wydawca.h"
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+
+/* A directory watcher is described by the following structure */
+struct dirwatcher
+{
+ struct dirwatcher *next, *prev;
+ struct dirwatcher *parent; /* Points to the parent watcher.
+ NULL for top-level watchers */
+ struct spool *spool;
+ int wd; /* Watch descriptor */
+};
+
+static struct dirwatcher *dirwatcher_list;
+
+struct dirwatcher *
+dirwatcher_unlink(struct dirwatcher **root, struct dirwatcher *p)
+{
+ if (p->prev)
+ p->prev->next = p->next;
+ else
+ *root = p->next;
+ if (p->next)
+ p->next->prev = p->prev;
+ p->next = p->prev = NULL;
+ return p;
+}
+
+struct dirwatcher *
+dirwatcher_pop(struct dirwatcher **pp)
+{
+ if (*pp)
+ return dirwatcher_unlink(pp, *pp);
+ return NULL;
+}
+
+static void
+dirwatcher_push(struct dirwatcher **pp, struct dirwatcher *p)
+{
+ p->prev = NULL;
+ p->next = *pp;
+ if (*pp)
+ (*pp)->prev = p;
+ *pp = p;
+}
+
+/* Find a watcher with the given descriptor */
+static struct dirwatcher *
+dirwatcher_find_wd (int wd)
+{
+ struct dirwatcher *dwp;
+
+ for (dwp = dirwatcher_list; dwp; dwp = dwp->next)
+ if (dwp->wd == wd)
+ break;
+ return dwp;
+}
+
+static int
+create_watcher (struct spool *sp, void *data)
+{
+ int ifd = *(int*)data;
+ struct dirwatcher *dwp;
+ int wd;
+ const char *path = get_path (sp);
+
+ if (!sp)
+ return 0;
+
+ if (debug_level > 1)
+ logmsg (LOG_DEBUG, "creating watcher %s", path);
+ dwp = malloc (sizeof(*dwp));
+ if (!dwp)
+ {
+ logmsg (LOG_ERR, "not enough memory");
+ return 1;
+ }
+ dwp->spool = sp;
+ dwp->parent = NULL;
+
+ wd = inotify_add_watch (ifd, path, IN_DELETE|IN_CREATE|IN_CLOSE_WRITE|
+ IN_MOVED_FROM|IN_MOVED_TO);
+ if (wd == -1)
+ {
+ logmsg