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
@@ -6,60 +6,63 @@
# the Free Software Foundation; either version 3, 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/>.
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])
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-xz std-options silent-rules])
# Enable silent rules by default:
AM_SILENT_RULES([yes])
# Checks for programs.
AC_PROG_CC
AC_PROG_RANLIB
# Checks for libraries.
# 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
AC_TYPE_SIGNAL
AC_TYPE_UID_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_STDBOOL
AC_SYS_LARGEFILE
# Checks for library functions.
AC_FUNC_FORK
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
# **********************
AM_GNU_MAILUTILS(2.0, [mailer], [:])
# **********************
# MySQL
# **********************
AC_SUBST(SQLLIB)
@@ -98,24 +101,47 @@ AC_ARG_WITH(tcp-wrappers,
if test "$status_tcpwrap" = yes; then
AC_CHECK_LIB(nsl, main)
AC_CHECK_LIB(wrap, main,, [status_tcpwrap=no])
if test "$status_tcpwrap" = yes; then
AC_CHECK_HEADERS(tcpd.h,,[status_tcpwrap=no])
fi
fi
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])
AH_BOTTOM([
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
# define __attribute__(x)
#endif
#ifndef GSC_PRINTFLIKE
# define GSC_PRINTFLIKE(fmt,narg) __attribute__ ((__format__ (__printf__, fmt, narg)))
#endif
])
diff --git a/src/Makefile.am b/src/Makefile.am
index 73182c4..828d573 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,24 +6,29 @@
# the Free Software Foundation; either version 3, 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/>.
sbin_PROGRAMS=wydawca
+
+if COND_INOTIFY
+ WATCHER_C=watcher.c
+endif
+
wydawca_SOURCES=\
backup.c\
builtin.c\
builtin.h\
cmdline.h\
config.c\
dictionary.c\
directive.c\
diskio.c\
exec.c\
gpg.c\
interval.c\
@@ -39,25 +44,26 @@ wydawca_SOURCES=\
tcpwrap.c\
triplet.c\
userprivs.c\
verify.c\
wydawca.c\
wydawca.h\
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
.opt.h:
$(AM_V_GEN)m4 -s $(top_srcdir)/@GRECS_SUBDIR@/build-aux/getopt.m4 $< > $@
incdir=$(pkgdatadir)/$(VERSION)/include
inc_DATA = $(PP_SETUP_FILE)
diff --git a/src/diskio.c b/src/diskio.c
index bab5cb8..751d684 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -402,24 +402,30 @@ static int
replace_allowed_p (struct file_triplet *trp)
{
const char *val;
if (trp->version < 102)
return 1;
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
dir_move_file (struct file_triplet *trp, enum file_type file_id)
{
char *dst_file;
int rc = 0;
const struct spool *spool = trp->spool;
char *dst_dir = create_directory (spool->dest_dir, trp->relative_dir);
diff --git a/src/job.c b/src/job.c
index 4a97f88..3fae432 100644
--- a/src/job.c
+++ b/src/job.c
@@ -16,36 +16,37 @@
#include "wydawca.h"
#include "mail.h"
#define STATE_FINISHED 0x01
#define STATE_QUEUED 0x02
#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)
{
wakeup = 1;
signal (sig, queue_signal);
}
void
set_timer (time_t interval)
@@ -67,31 +68,40 @@ job_locate (const struct spool *spool, uid_t uid)
size_t
job_active_count ()
{
struct job *job;
size_t count = 0;
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);
}
timer_stop ("wydawca");
logstats ();
mail_finish ();
return rc;
}
@@ -182,25 +192,25 @@ job_insert (struct job *job, struct job *elt)
queue = job;
return;
}
p = elt->next;
elt->next = job;
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;
if (debug_level)
logmsg (LOG_DEBUG, _("scheduling job: %s, %lu"),
spool->tag, (unsigned long)uid);
job = job_locate (spool, uid);
if (!job)
diff --git a/src/net.c b/src/net.c
index 4857fa2..3157fe8 100644
--- a/src/net.c
+++ b/src/net.c
@@ -13,28 +13,25 @@
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"
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));
exit (EX_OSERR);
}
if (listen_sockaddr.sa->sa_family == AF_UNIX)
{
struct stat st;
struct sockaddr_un *s_un = (struct sockaddr_un *) listen_sockaddr.sa;
@@ -90,25 +87,25 @@ trim_crlf (char *s)
{
s[--len] = 0;
if (len > 0 && s[len-1] == '\r')
s[--len] = 0;
}
}
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);
if (debug_level)
logmsg (LOG_DEBUG, "recv: %s", buf);
spool = wydawca_find_spool (buf);
if (!spool)
{
if (all_spool_aliases && grecs_list_locate (all_spool_aliases, buf))
@@ -165,80 +162,108 @@ sig_hup (int sig)
}
RETSIGTYPE
sig_term (int sig)
{
terminate = 1;
}
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
@@ -15,24 +15,38 @@
with wydawca. If not, see <http://www.gnu.org/licenses/>. */
#include "wydawca.h"
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;
spool_list = sp;
}
static int
spool_check_alias (struct spool *spool, const char *name)
{
@@ -113,40 +127,104 @@ parse_file_name (const char *name, struct file_info *finfo)
&& memcmp (name + len - suftab[i].len,
suftab[i].suf, suftab[i].len) == 0)
{
finfo->name = grecs_strdup (name);
finfo->type = suftab[i].type;
finfo->root_len = len - suftab[i].len;
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,
mu_url_to_string (spool->dest_url));
if (chdir (spool->source_dir))
{
logmsg (LOG_ERR, _("cannot chdir to %s: %s"), spool->source_dir,
strerror (errno));
@@ -157,130 +235,106 @@ scan_spool_unlocked (const struct spool *spool, int uc, uid_t *uv)
if (!dir)
{
logmsg (LOG_ERR, _("cannot open directory %s: %s"), spool->source_dir,
strerror (errno));
return;
}
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:
scan_spool_unlocked (spool, uc, uv);
wydawca_unlock (lockfile);
break;
case LOCK_FAILURE:
logmsg (LOG_ERR, _("cannot lock spool %s"), spool->tag);
break;
case LOCK_RETRY:
logmsg (LOG_WARNING, _("timed out while looking spool %s"), spool->tag);
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)
{
struct spool_list *sp;
int rc = 0;
timer_start ("wydawca");
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 ()
{
struct spool_list *sp;
for (sp = spool_list; sp; sp = sp->next)
timer_start (sp->spool.tag);
}
diff --git a/src/triplet.c b/src/triplet.c
index 79ca8c2..05b7536 100644
--- a/src/triplet.c
+++ b/src/triplet.c
@@ -23,25 +23,25 @@ static unsigned
hash_triplet_hasher (void *data, unsigned long n_buckets)
{
struct file_triplet const *t = data;
return grecs_hash_string (t->name, 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)
{
int i;
struct file_triplet *tp = data;
struct uploader_info *up;
free (tp->name);
@@ -89,37 +89,60 @@ register_file (struct file_info *finfo, const struct spool *spool)
hash_triplet_hasher,
hash_triplet_compare,
NULL,
NULL,
hash_triplet_free);
if (!triplet_table)
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)
{
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;
time_t now = time (NULL);
if (ttl == 0)
return 0;
for (i = 0; i < FILE_TYPE_COUNT; i++)
@@ -138,39 +161,38 @@ triplet_expired_p (struct file_triplet *trp, time_t ttl)
enum triplet_state
{
triplet_directive, /* Short triplet: only a directive is present,
but nothing more is required */
triplet_complete, /* A complete triplet: all three files are present
and have the same owner */
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;
else
{
if (debug_level)
logmsg (LOG_DEBUG, _("%s: invalid triplet: UIDs differ"),
trp->name);
return triplet_bad;
@@ -203,25 +225,25 @@ remove_triplet (struct file_triplet *trp)
static int
triplet_processor (void *data, void *proc_data)
{
struct file_triplet *trp = 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))
+ 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))
remove_triplet (trp);
return 0;
case triplet_incomplete:
if (debug_level)
logmsg (LOG_DEBUG, _("%s: incomplete triplet"), trp->name);
@@ -237,42 +259,110 @@ triplet_processor (void *data, void *proc_data)
if (triplet_expired_p (trp, trp->spool->file_sweep_time))
{
UPDATE_STATS (STAT_EXPIRED_TRIPLETS);
remove_triplet (trp);
}
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);
}
}
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;
}
static const char *
expand_tag (struct metadef *def, void *data)
{
struct file_triplet *trp = data;
diff --git a/src/verify.c b/src/verify.c
index 1409889..4a108bc 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -193,141 +193,144 @@ new_uploader_info (struct uploader_info *src)
}
struct uploader_info *
uploader_find_frp (struct uploader_info *list, const char *fpr)
{
for (; list; list = list->next)
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;
const struct spool *spool;
struct dictionary *dict;
ASGN_SPOOL (spool, trp, return 1);
dict = spool->dictionary[project_uploader_dict];
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)