aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 @@
# along with wydawca. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ(2.63)
-AC_INIT([wydawca], 2.1.90, [bug-wydawca@gnu.org.ua])
+AC_INIT([wydawca], 2.1.90, [bug-wydawca@gnu.org.ua], [wydawca],
+ [http://www.gnu.org.ua/software/wydawca])
AC_CONFIG_SRCDIR([src/wydawca.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADER([config.h])
@@ -33,7 +34,7 @@ AC_PROG_RANLIB
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS([stdlib.h string.h sys/file.h unistd.h])
+AC_CHECK_HEADERS([stdlib.h string.h sys/file.h unistd.h sys/inotify.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -50,7 +51,9 @@ AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_STAT
AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([fchdir memset strchr strdup strerror strrchr setegid setregid setresgid setresuid seteuid setreuid vsyslog sysconf getdtablesize])
+AC_CHECK_FUNCS([fchdir memset strchr strdup strerror strrchr setegid setregid\
+ setresgid setresuid seteuid setreuid vsyslog sysconf getdtablesize\
+ inotify_init])
# **********************
# Mailutils
@@ -107,6 +110,29 @@ if test "$status_tcpwrap" = yes; then
AC_DEFINE_UNQUOTED([WITH_LIBWRAP],1,[Defined if compiling with libwrap])
fi
+# **********************
+# TCP wrappers
+# **********************
+AC_ARG_WITH(inotify,
+ AC_HELP_STRING([--with-inotify],
+ [compile with inotify(7) support (Linux-specific)]),
+ [status_inotify=${withval}],
+ [status_inotify=probe])
+if test $status_inotify != no; then
+ if test "$ac_cv_header_sys_inotify_h" = yes &&
+ test "$ac_cv_func_inotify_init" = yes; then
+ status_inotify=yes
+ elif test $status_inotify = probe; then
+ status_inotify=no
+ else
+ AC_MSG_FAILURE([Requested inotify(7) support is not available])
+ fi
+fi
+if test $status_inotify = yes; then
+ AC_DEFINE([WITH_INOTIFY],1,[Set to 1 if inotify(7) is to be used])
+fi
+AM_CONDITIONAL([COND_INOTIFY],[test $status_inotify = yes])
+
# Grecs subsystem
GRECS_SETUP([grecs],[git2chg getopt tests])
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 @@
# 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\
@@ -48,7 +53,8 @@ wydawca_SOURCES=\
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
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)
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.
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
{
struct job *next, *prev;
int state;
- const struct spool *spool;
+ struct spool *spool;
uid_t uid;
pid_t pid;
time_t timestamp;
@@ -36,7 +36,8 @@ 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;
@@ -76,13 +77,22 @@ job_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
{
@@ -191,7 +201,7 @@ job_insert (struct job *job, struct job *elt)
}
void
-schedule_job (const struct spool *spool, uid_t uid)
+schedule_job (struct spool *spool, uid_t uid)
{
struct job *job;
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 ()
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)
@@ -99,7 +96,7 @@ 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;
@@ -174,7 +171,22 @@ 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);
@@ -182,21 +194,16 @@ wydawca_listener ()
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)
{
@@ -207,7 +214,7 @@ wydawca_listener ()
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)
@@ -218,26 +225,44 @@ wydawca_listener ()
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
@@ -24,6 +24,20 @@ struct spool_list
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)
{
@@ -122,7 +136,14 @@ parse_file_name (const char *name, struct file_info *finfo)
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;
@@ -134,10 +155,67 @@ match_uid_p (uid_t uid, int uc, uid_t *uv)
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;
@@ -166,67 +244,22 @@ scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv)
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);
@@ -249,12 +282,33 @@ scan_spool (const struct spool *spool, int uc, uid_t *uv)
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 */
@@ -271,7 +325,7 @@ scan_all_spools (int uidc, uid_t *uidv)
rc++;
for (sp = spool_list; sp; sp = sp->next)
- close_dictionaries (&sp->spool);
+ spool_close_dictionaries (&sp->spool);
timer_stop ("wydawca");
return rc;
}
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)
{
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 */
@@ -98,6 +98,7 @@ register_file (struct file_info *finfo, const struct spool *spool)
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)
@@ -111,6 +112,28 @@ register_file (struct file_info *finfo, const struct spool *spool)
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
@@ -147,11 +170,11 @@ enum triplet_state
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
@@ -160,8 +183,7 @@ check_triplet_state (struct file_triplet *trp)
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
@@ -212,7 +234,7 @@ triplet_processor (void *data, void *proc_data)
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:
@@ -246,11 +268,13 @@ triplet_processor (void *data, void *proc_data)
/* 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);
@@ -264,6 +288,72 @@ 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)
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)
}
int
-verify_directive_file (struct file_triplet *trp)
+verify_directive_file (struct file_triplet *trp, int noath)
{
char *command;
int rc;
@@ -220,105 +220,108 @@ verify_directive_file (struct file_triplet *trp)
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)
{
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
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 }
};
@@ -53,6 +53,14 @@ url_to_vtab (mu_url_t url, struct virt_tab *vtab)
}
+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)
{
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 (LOG_ERR, "cannot set watch on %s: %s", path, strerror (errno));
+ free (dwp);
+ return 1;
+ }
+
+ dwp->wd = wd;
+ dirwatcher_push (&dirwatcher_list, dwp);
+ return 0;
+}
+
+int
+watcher_init ()
+{
+ int ifd, rc;
+
+ if (debug_level > 1)
+ logmsg (LOG_DEBUG, "setting up inotify");
+ ifd = inotify_init ();
+ if (ifd == -1)
+ {
+ logmsg (LOG_ERR, "inotify_init: %s", strerror (errno));
+ return -1;
+ }
+
+ rc = for_each_spool (create_watcher, &ifd);
+ if (rc)
+ exit (EX_OSERR);
+ if (!dirwatcher_list)
+ {
+ if (debug_level > 1)
+ logmsg (LOG_DEBUG, "inotify: nothing to watch");
+ close (ifd);
+ ifd = -1;
+ }
+ else if (debug_level > 1)
+ logmsg (LOG_DEBUG, "inotify initialized successfully");
+
+ return ifd;
+}
+
+static void
+process_event (struct inotify_event *ep)
+{
+ static struct dirwatcher *dwp;
+ dwp = dirwatcher_find_wd (ep->wd);
+
+ if (ep->mask & IN_IGNORED)
+ /* nothing */;
+ else if (ep->mask & IN_Q_OVERFLOW)
+ logmsg (LOG_NOTICE, "event queue overflow");
+ else if (ep->mask & IN_UNMOUNT)
+ /* FIXME: not sure if there's
+ anything to do. Perhaps we should
+ deregister the watched dirs that
+ were located under the mountpoint
+ */;
+ else if (!dwp)
+ {
+ if (ep->name)
+ logmsg (LOG_NOTICE, "unrecognized event %x for %s",
+ ep->mask, ep->name);
+ else
+ logmsg (LOG_NOTICE, "unrecognized event %x", ep->mask);
+ }
+ else if (ep->mask & IN_CREATE)
+ {
+ if (debug_level > 0)
+ logmsg (LOG_DEBUG, "%s/%s created", dwp->spool->source_dir, ep->name);
+ }
+ else if (ep->mask & (IN_DELETE|IN_MOVED_FROM))
+ {
+ if (debug_level > 0)
+ logmsg (LOG_DEBUG, "%s/%s %s", dwp->spool->source_dir, ep->name,
+ ep->mask & IN_DELETE ? "deleted" : "moved out");</