/* wydawca - automatic release submission daemon Copyright (C) 2007, 2009-2013 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" char *program_name; uid_t wydawca_uid; gid_t wydawca_gid; size_t wydawca_supp_groupc; gid_t *wydawca_supp_groups; char *conffile = SYSCONFDIR "/wydawca.rc"; const char *wy_version = "wydawca (" PACKAGE_STRING ")"; int wy_debug_level; int wy_dry_run; int wy_log_to_stderr = -1; /* -1 means autodetect */ int wy_log_facility = LOG_LOCAL1; char *wy_syslog_tag = "wydawca"; int syslog_include_prio; /* syslog messages include priority */ unsigned long print_stats; /* Print final statistics output */ time_t file_sweep_time = 0; char *tar_command_name = "tar"; int archive_signatures = 1; /* Archive sig files by default */ int lint_mode = 0; int preprocess_only = 0; int cron_option = 0; int foreground_option = -1; int single_process_option = -1; int daemon_mode = 0; int foreground; int single_process; time_t wakeup_interval; struct grecs_list *all_spool_aliases; char *wy_gpg_homedir; char *default_check_script; struct grecs_sockaddr listen_sockaddr; unsigned wydawca_stat[MAX_STAT]; unsigned min_directive_version = MIN_DIRECTIVE_VERSION; unsigned max_directive_version = MAX_DIRECTIVE_VERSION; int inotify_enable = 1; void initstats() { memset(wydawca_stat, 0, sizeof wydawca_stat); } /* Logging */ void syslog_printer(int prio, const char *fmt, va_list ap) { if (syslog_include_prio) { static char *fmtbuf; static size_t fmtsize; const char *p = wy_pritostr(prio); size_t size = strlen(p) + 3 + strlen(fmt) + 1; if (size > fmtsize) { fmtsize = size; fmtbuf = grecs_realloc(fmtbuf, fmtsize); } sprintf(fmtbuf, "[%s] %s", p, fmt); fmt = fmtbuf; } #if HAVE_VSYSLOG vsyslog(prio, fmt, ap); #else char buf[128]; vsnprintf(buf, sizeof buf, fmt, ap); syslog(prio, "%s", buf); #endif } void stderr_printer(int prio, const char *fmt, va_list ap) { const char *p = wy_pritostr(prio); fprintf(stderr, "%s: ", program_name); if (p) fprintf(stderr, "[%s] ", p); vfprintf(stderr, fmt, ap); fputc('\n', stderr); } static void (*log_printer) (int prio, const char *fmt, va_list ap) = stderr_printer; void wy_log(int prio, char *fmt, ...) { va_list ap; switch (prio) { case LOG_EMERG: case LOG_ALERT: case LOG_CRIT: case LOG_ERR: UPDATE_STATS(STAT_ERRORS); break; case LOG_WARNING: UPDATE_STATS(STAT_WARNINGS); } va_start(ap, fmt); log_printer(prio, fmt, ap); va_end(ap); } void wy_dbg(char *fmt, ...) { va_list ap; va_start(ap, fmt); log_printer(LOG_DEBUG, fmt, ap); va_end(ap); } static char *stat_name[MAX_STAT] = { N_("errors"), N_("warnings"), N_("bad signatures"), N_("access violation attempts"), N_("complete triplets"), N_("incomplete triplets"), N_("bad triplets"), N_("expired triplets"), N_("triplet successes"), N_("files uploaded"), N_("files archived"), N_("symlinks created"), N_("symlinks removed"), N_("check failures"), }; static char *stat_kwname[MAX_STAT] = { "stat:errors", "stat:warnings", "stat:bad_signatures", "stat:access_violations", "stat:complete_triplets", "stat:incomplete_triplets", "stat:bad_triplets", "stat:expired_triplets", "stat:triplet_success", "stat:uploads", "stat:archives", "stat:symlinks", "stat:rmsymlinks", "stat:check-failures" }; int wy_stat_mask_p(unsigned long mask) { int i; for (i = 0; i < MAX_STAT; i++) if (wydawca_stat[i] != 0 && (mask && STAT_MASK(i))) return 1; return 0; } static const char * stat_expand(struct wy_metadef *def, void *data) { size_t size = 0; def->storage = NULL; if (grecs_asprintf(&def->storage, &size, "%u", wydawca_stat[(int)def->data])) grecs_alloc_die(); def->value = def->storage; return def->value; } struct wy_metadef * make_stat_expansion(size_t count) { int i; struct wy_metadef *def, *p; def = grecs_calloc(MAX_STAT + count + 1, sizeof(def[0])); p = def + count; for (i = 0; i < MAX_STAT; i++, p++) { p->kw = stat_kwname[i]; p->value = NULL; p->storage = NULL; p->expand = stat_expand; p->data = (void *)i; } p->kw = NULL; return def; } void logstats() { int i; if (wy_stat_mask_p(print_stats)) { for (i = 0; i < MAX_STAT; i++) if (print_stats & STAT_MASK(i)) wy_log(LOG_INFO, "%s: %u", gettext(stat_name[i]), wydawca_stat[i]); } notify_stats(); } void grecs_print_diag(grecs_locus_t *locus, int err, int errcode, const char *msg) { char *locstr = NULL; if (locus) { size_t size = 0; if (locus->beg.col == 0) grecs_asprintf(&locstr, &size, "%s:%u", locus->beg.file, locus->beg.line); else if (strcmp(locus->beg.file, locus->end.file)) grecs_asprintf(&locstr, &size, "%s:%u.%u-%s:%u.%u", locus->beg.file, locus->beg.line, locus->beg.col, locus->end.file, locus->end.line, locus->end.col); else if (locus->beg.line != locus->end.line) grecs_asprintf(&locstr, &size, "%s:%u.%u-%u.%u", locus->beg.file, locus->beg.line, locus->beg.col, locus->end.line, locus->end.col); else grecs_asprintf(&locstr, &size, "%s:%u.%u-%u", locus->beg.file, locus->beg.line, locus->beg.col, locus->end.col); } if (locstr) { if (errcode) wy_log(err ? LOG_ERR : LOG_WARNING, "%s: %s: %s", locstr, msg, strerror(errcode)); else wy_log(err ? LOG_ERR : LOG_WARNING, "%s: %s", locstr, msg); free(locstr); } else { if (errcode) wy_log(err ? LOG_ERR : LOG_WARNING, "%s: %s", msg, strerror(errcode)); else wy_log(err ? LOG_ERR : LOG_WARNING, "%s", msg); } } static int uidc; static uid_t *uidv; static void collect_uids(int argc, char **argv) { int i; uidc = argc; uidv = grecs_calloc(uidc, sizeof(uidv[0])); for (i = 0; i < argc; i++) { struct passwd *pw = getpwnam(argv[i]); if (!pw) { char *p; unsigned n = strtoul(argv[i], &p, 10); if (*p) { wy_log(LOG_ERR, _("no such user: %s"), argv[i]); exit(EX_NOUSER); } uidv[i] = n; } else uidv[i] = pw->pw_uid; } } char **x_argv; extern int reconfigure; void wydawca_daemon() { if (!foreground) { if (daemon(0, 0)) { wy_log(LOG_ERR, "%s", strerror(errno)); exit(EX_OSERR); } wy_log(LOG_NOTICE, _("daemon launched")); } check_pidfile(); wydawca_listener(); remove_pidfile(); } #include "cmdline.h" void version_hook(FILE * stream) { printf("Compiled with:"); #ifdef WITH_LIBWRAP printf(" libwrap"); #endif #ifdef WITH_INOTIFY printf(" inotify"); #endif putchar('\n'); } int main(int argc, char **argv) { struct grecs_node *tree; const char *p; program_name = argv[0]; proginfo.print_version_hook = version_hook; config_init(); x_argv = argv; parse_options(argc, argv); argv += optind; argc -= optind; p = gpgme_check_version("1.1.0"); if (!p) { wy_log(LOG_CRIT, _("GPGMe version check failed")); exit(EX_UNAVAILABLE); } else wy_debug(4, (_("using GPGME version %s"), p)); if (argc) collect_uids(argc, argv); if (preprocess_only) exit(grecs_preproc_run(conffile, grecs_preprocessor) ? EX_CONFIG : 0); tree = grecs_parse(conffile); if (!tree) exit(EX_CONFIG); config_finish(tree); modules_load(); if (lint_mode && wy_debug_level) { grecs_print_node(tree, GRECS_NODE_FLAG_DEFAULT| (wy_debug_level > 1 ? GRECS_NODE_FLAG_LOCUS : 0), stdout); fputc('\n', stdout); } grecs_tree_free(tree); if (lint_mode) exit(0); if (wy_dry_run || selected_spools()) cron_option = 1; if (cron_option) daemon_mode = 0; if (foreground_option >= 0) foreground = foreground_option; if (single_process_option >= 0) single_process = single_process_option; if (wy_log_to_stderr == -1) wy_log_to_stderr = (!daemon_mode || foreground) && isatty(0); grecs_log_to_stderr = wy_log_to_stderr; if (!wy_log_to_stderr) { openlog(wy_syslog_tag, LOG_PID, wy_log_facility); log_printer = syslog_printer; } if (getgid() == 0) { if (wydawca_uid == 0) { if (!force_startup) { wy_log(LOG_CRIT, _("won't run with root privileges")); exit(EX_UNAVAILABLE); } } else if (wydawca_userprivs(wydawca_uid, wydawca_gid, wydawca_supp_groups, wydawca_supp_groupc)) exit(EX_UNAVAILABLE); } wydawca_lock_init(); wy_log(LOG_NOTICE, _("wydawca (%s) started"), PACKAGE_STRING); if (!daemon_mode) { scan_all_spools(uidc, uidv); logstats(); } else wydawca_daemon(); modules_close(); wy_log(LOG_NOTICE, _("wydawca (%s) finished"), PACKAGE_STRING); if (reconfigure) { int i; for (i = getdtablesize(); i > 2; i--) close(i); remove_pidfile(); execv(x_argv[0], x_argv); } exit(0); }