diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/diskio.c | 6 | ||||
-rw-r--r-- | src/job.c | 18 | ||||
-rw-r--r-- | src/net.c | 87 | ||||
-rw-r--r-- | src/process.c | 162 | ||||
-rw-r--r-- | src/triplet.c | 104 | ||||
-rw-r--r-- | src/verify.c | 175 | ||||
-rw-r--r-- | src/vtab.c | 18 | ||||
-rw-r--r-- | src/watcher.c | 243 | ||||
-rw-r--r-- | src/wydawca.c | 14 | ||||
-rw-r--r-- | src/wydawca.h | 49 |
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 @@ -1,72 +1,78 @@ # This file is part of Wydawca # Copyright (C) 2007, 2009-2011 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, 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\ job.c\ lock.c\ meta.c\ net.c\ pidfile.c\ process.c\ pushd.c\ sql.c\ sql.h\ 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) LDADD=../grecs/src/libgrecs.a @SQLLIB@ @GPGMELIB@ @MAILUTILS_LIBS@ INCLUDES = -I$(top_srcdir)/grecs/src/ @MAILUTILS_INCLUDES@ AM_CPPFLAGS= \ -DSYSCONFDIR=\"$(sysconfdir)\"\ -DLOCALSTATEDIR=\"$(localstatedir)\"\ -DDEFAULT_VERSION_INCLUDE_DIR=\"$(incdir)\"\ -DDEFAULT_INCLUDE_DIR=\"$(pkgdatadir)/include\"\ -DDEFAULT_PREPROCESSOR="$(DEFAULT_PREPROCESSOR)" diff --git a/src/diskio.c b/src/diskio.c index bab5cb8..751d684 100644 --- a/src/diskio.c +++ b/src/diskio.c @@ -390,48 +390,54 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file, } if (!dry_run_mode && unlink (dst_file) && errno != ENOENT) { logmsg (LOG_ERR, _("canot unlink file `%s': %s"), dst_file, strerror (errno)); return 1; } return 0; } 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); if (!dst_dir) return 1; dst_file = concat_dir (dst_dir, trp->file[file_id].name, NULL); if (debug_level) logmsg (LOG_DEBUG, _("installing %s to %s"), trp->file[file_id].name, dst_dir); if (access (dst_file, F_OK) == 0) { if (replace_allowed_p (trp)) @@ -4,106 +4,116 @@ This program 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. This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ #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) { wakeup = 0; if (interval) alarm (interval); } struct job * job_locate (const struct spool *spool, uid_t uid) { struct job *p; for (p = queue; p; p = p->next) if (p->spool == spool && p->uid == uid) break; return p; } 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; } int job_start (struct job *job) { pid_t pid; if (jobmax && jobcnt == jobmax) { logmsg (LOG_NOTICE, "maximum number of processes active"); return 1; } if (debug_level) @@ -170,49 +180,49 @@ job_remove (struct job *job) void job_insert (struct job *job, struct job *elt) { struct job *p; job->prev = elt; if (!elt) { if (queue) queue->prev = job; job->next = queue; 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) { job = grecs_zalloc (sizeof (*job)); job->spool = spool; job->uid = uid; job->pid = -1; time (&job->timestamp); job_insert (job, NULL); } job->state |= STATE_QUEUED; job_start (job); } @@ -1,52 +1,49 @@ /* wydawca - automatic release submission daemon Copyright (C) 2007, 2009-2011 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" 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; if (stat (s_un->sun_path, &st)) { if (errno != ENOENT) { logmsg (LOG_CRIT, _("%s: cannot stat socket: %s"), s_un->sun_path, strerror (errno)); exit (errno == EACCES ? EX_NOPERM : EX_OSERR); } } else { /* FIXME: Check permissions? */ @@ -78,49 +75,49 @@ open_listener () close (fd); exit (EX_OSERR); } return fd; } void trim_crlf (char *s) { size_t len = strlen (s); if (len > 0 && s[len-1] == '\n') { 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)) fprintf (out, "+ OK, all spools\r\n"); else { fprintf (out, "- Unknown service name\r\n"); free (buf); return; } } else if (spool->url) fprintf (out, "+ OK, URL %s\r\n", spool->url); else fprintf (out, "+ OK, spool %s\r\n", spool->tag); @@ -153,92 +150,120 @@ handle_connection (FILE *in, FILE *out) logmsg (LOG_ERR, "no such user: %s", buf); free (buf); } int reconfigure; static int terminate; RETSIGTYPE sig_hup (int sig) { reconfigure = 1; terminate = 1; } 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 @@ -3,48 +3,62 @@ 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" 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) { if (spool->aliases && grecs_list_locate (spool->aliases, (char*) name)) return 1; return 0; } struct spool * wydawca_find_spool (const char *name) { struct spool_list *sp; for (sp = spool_list; sp; sp = sp->next) { @@ -101,186 +115,226 @@ parse_file_name (const char *name, struct file_info *finfo) enum file_type type; } suftab[] = { { SUF_SIG, SUF_SIG_LEN, file_signature }, { SUF_DIR, SUF_DIR_LEN, file_directive }, { "", 0, file_dist } }; int i; unsigned len = strlen (name); for (i = 0; i < sizeof suftab / sizeof suftab[0]; i++) { if (len >= suftab[i].len && 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)); return; } dir = opendir ("."); 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 @@ -11,49 +11,49 @@ 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 <time.h> static struct grecs_symtab *triplet_table; 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); for (i = 0; i < FILE_TYPE_COUNT; i++) { if (tp->file[i].name) free (tp->file[i].name); } free (tp->directive); free (tp->blurb); free (tp->tmp); txtacc_free (tp->acc); /* Free uploader list */ @@ -77,112 +77,134 @@ triplet_strdup (struct file_triplet *tp, const char *str) } /* Register a file in the triplet table */ void register_file (struct file_info *finfo, const struct spool *spool) { struct file_triplet key, *ret; int install = 1; if (!triplet_table) { triplet_table = grecs_symtab_create (sizeof (struct file_triplet), 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++) { if (trp->file[i].name && (now - trp->file[i].sb.st_mtime) > ttl) { if (debug_level) logmsg (LOG_DEBUG, _("file %s expired"), trp->file[i].name); return 1; } } return 0; } 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; } } } return triplet_incomplete; } /* Unlink all parts of the triplet TRP */ static void remove_triplet (struct file_triplet *trp) { int i; @@ -191,100 +213,168 @@ remove_triplet (struct file_triplet *trp) { if (trp->file[i].name) { logmsg (LOG_NOTICE, _("removing %s"), trp->file[i].name); if (!dry_run_mode && unlink (trp->file[i].name)) logmsg (LOG_ERR, _("cannot remove %s: %s"), trp->file[i].name, strerror (errno)); } } } /* Process a single triplet from the table */ 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); /* ignore unless expired (see below); */ UPDATE_STATS (STAT_INCOMPLETE_TRIPLETS); break; case triplet_bad: UPDATE_STATS (STAT_BAD_TRIPLETS); remove_triplet (trp); return 0; } 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_ |