diff options
Diffstat (limited to 'src/spool.c')
-rw-r--r-- | src/spool.c | 279 |
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); + } +} + + + |