aboutsummaryrefslogtreecommitdiff
path: root/src/spool.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/spool.c')
-rw-r--r--src/spool.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/src/spool.c b/src/spool.c
new file mode 100644
index 0000000..39ddc7b
--- /dev/null
+++ b/src/spool.c
@@ -0,0 +1,279 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2007, 2009-2013, 2017, 2019-2020 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 STAILQ_HEAD(,spool) spool_list = STAILQ_HEAD_INITIALIZER(spool_list);
+size_t spool_count;
+
+int
+for_each_spool(int (*fun) (struct spool *, void *), void *data)
+{
+ struct spool *sp;
+
+ STAILQ_FOREACH(sp, &spool_list, link) {
+ int rc = fun(sp, data);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+void
+register_spool(struct spool *spool)
+{
+ spool->timer_id = spool_count++ + MY_TIMER_SPOOL_FIRST;
+ STAILQ_INSERT_TAIL(&spool_list, spool, link);
+}
+
+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 *sp;
+
+ STAILQ_FOREACH(sp, &spool_list, link) {
+ if (strcmp(sp->tag, name) == 0 || spool_check_alias(sp, name))
+ break;
+ }
+ return sp;
+}
+
+/* Return true if NAME is a directory. If stat fails, return the error
+ code in EC */
+int
+test_dir(const char *name, int *ec)
+{
+ struct stat st;
+
+ *ec = 0;
+ if (stat(name, &st)) {
+ *ec = errno;
+ return 1;
+ }
+ return S_ISDIR(st.st_mode) == 0;
+}
+
+/* Return a textual representation of a file TYPE */
+const char *
+file_type_str(enum file_type type)
+{
+ switch (type) {
+ case file_dist:
+ return "distributive";
+
+ case file_signature:
+ return "detached signature";
+
+ case file_directive:
+ return "signed upload directive";
+ }
+ return "UNKNOWN";
+}
+
+/* Parse file NAME: determine its type and root name and store this
+ information in FINFO */
+void
+parse_file_name(const char *name, struct file_info *finfo)
+{
+ static struct suffix {
+ const char *suf;
+ unsigned len;
+ 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 */
+}
+
+void
+file_info_cleanup(struct file_info *finfo)
+{
+ free(finfo->name);
+ memset(finfo, 0, sizeof(*finfo));
+}
+
+struct wy_triplet *
+spool_add_new_file(struct spool *spool, const char *name)
+{
+ struct stat st;
+ struct file_info finfo;
+
+ if (fstatat(spool->source_fd, name, &st, 0)) {
+ wy_log(LOG_ERR, _("cannot stat file %s/%s: %s"),
+ spool->source_dir, name, strerror(errno));
+ return NULL;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ wy_log(LOG_NOTICE, _("not a regular file: %s/%s"),
+ spool->source_dir, name);
+ return NULL;
+ }
+
+ finfo.sb = st;
+ parse_file_name(name, &finfo);
+
+ wy_debug(1, (_("found file %s: %s, stem: %.*s"), name,
+ file_type_str(finfo.type), finfo.root_len, finfo.name));
+
+ return register_file(&finfo, spool);
+}
+
+/* Scan upload directory from SPOOL and register all files found
+ there, forming triplets when possible */
+int
+scan_spool(struct spool *spool)
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ if (!enabled_spool_p(spool))
+ return -1;
+
+ wy_debug(1, ("%s -> %s", spool->source_dir,
+ wy_url_printable(spool->dest_url)));
+
+ dir = opendir(spool->source_dir);
+ if (!dir) {
+ wy_log(LOG_ERR, _("cannot open directory %s: %s"),
+ spool->source_dir, strerror(errno));
+ return -1;
+ }
+
+ timer_start(WY_TIMER_SPOOL);
+ timer_start(spool->timer_id);
+ while ((ent = readdir(dir))) {
+ if (strcmp(ent->d_name, ".") == 0 ||
+ strcmp(ent->d_name, "..") == 0)
+ continue;
+ triplet_enqueue(spool_add_new_file(spool, ent->d_name));
+ }
+
+ closedir(dir);
+
+ timer_stop(spool->timer_id);
+ timer_stop(WY_TIMER_SPOOL);
+ return 0;
+}
+
+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])) {
+ wy_log(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;
+}
+
+void
+dictionaries_close(void)
+{
+ struct spool *sp;
+ STAILQ_FOREACH(sp, &spool_list, link)
+ spool_close_dictionaries(sp);
+}
+
+/* Scan all configured update directories */
+void
+scan_all_spools(void)
+{
+ struct spool *sp;
+ STAILQ_FOREACH(sp, &spool_list, link)
+ scan_spool(sp);
+}
+
+int
+spool_timer_id(char *name)
+{
+ struct spool *sp;
+ STAILQ_FOREACH(sp, &spool_list, link) {
+ if (strcmp(sp->tag, name) == 0)
+ return sp->timer_id;
+ }
+ return -1;
+}
+
+void
+notify(const NOTIFYQ *nq, struct wy_triplet *t, enum wy_event e)
+{
+ struct notification *n;
+ NOTIFYQ_FOREACH(n, nq) {
+ if (n->ev == e) {
+ if (n->modname)
+ module_notify(n->modname, n->modcfg, e, t);
+ }
+ }
+}
+
+void
+notify_finish(void)
+{
+ notify(&default_notification, NULL, wy_ev_finish);
+}
+
+void
+spool_notify_flush(struct spool *spool)
+{
+ struct notification *n;
+ NOTIFYQ_FOREACH(n, &spool->notification_queue) {
+ if (n->modcfg)
+ module_flush(n->modname, n->modcfg);
+ }
+}
+
+
+

Return to:

Send suggestions and report system problems to the System administrator.