/* wydawca - automatic release submission daemon Copyright (C) 2007, 2009, 2010 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 . */ #include "wydawca.h" struct spool_list { struct spool_list *next; struct spool spool; }; static struct spool_list *spool_list; void register_spool (struct spool *spool) { struct spool_list *sp = xmalloc (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 && gl_list_search (spool->aliases, 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) { if (strcmp (sp->spool.tag, name) == 0 || spool_check_alias (&sp->spool, name)) return &sp->spool; } return NULL; } /* 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 = xstrdup (name); finfo->type = suftab[i].type; finfo->root_len = len - suftab[i].len; return; } } abort (); /* should not happen */ } 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; } /* 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) { 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); } 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); } timer_stop (spool->tag); timer_stop ("spool"); } int scan_spool (const 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 i; for (i = 0; i < NITEMS (spool->dictionary); i++) dictionary_done (spool->dictionary[i]); } /* 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); 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); }