/* wydawca - automatic release submission daemon Copyright (C) 2007, 2009-2012 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" #include "mail.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" ; int debug_level; int dry_run_mode; int log_to_stderr = -1; /* -1 means autodetect */ int log_facility = LOG_LOCAL1; char *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 *wydawca_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 = mu_syslog_priority_to_string (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 = mu_syslog_priority_to_string (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 logmsg (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); } 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 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 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 metadef * make_stat_expansion (size_t count) { int i; struct 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 (stat_mask_p (print_stats)) { for (i = 0; i < MAX_STAT; i++) if (print_stats & STAT_MASK (i)) logmsg (LOG_INFO, "%s: %u", gettext (stat_name[i]), wydawca_stat[i]); } mail_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) logmsg (err ? LOG_ERR : LOG_WARNING, "%s: %s: %s", locstr, msg, strerror (errcode)); else logmsg (err ? LOG_ERR : LOG_WARNING, "%s: %s", locstr, msg); free (locstr); } else { if (errcode) logmsg (err ? LOG_ERR : LOG_WARNING, "%s: %s", msg, strerror (errcode)); else logmsg (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) { logmsg (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)) { logmsg (LOG_ERR, "%s", strerror (errno)); exit (EX_OSERR); } logmsg (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]; print_version_hook = version_hook; mu_register_all_mailer_formats (); mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); config_init (); x_argv = argv; parse_options (argc, argv); argv += optind; argc -= optind; p = gpgme_check_version ("1.1.0"); if (!p) { logmsg (LOG_CRIT, _("GPGMe version check failed")); exit (EX_UNAVAILABLE); } else if (debug_level > 3) logmsg (LOG_DEBUG, _("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); grecs_tree_free (tree); if (lint_mode) exit (0); if (dry_run_mode || 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 (log_to_stderr == -1) log_to_stderr = (!daemon_mode || foreground) && isatty (0); grecs_log_to_stderr = log_to_stderr; mu_log_tag = syslog_tag; mu_log_facility = log_facility; if (!log_to_stderr) { openlog (syslog_tag, LOG_PID, log_facility); log_printer = syslog_printer; } mu_stdstream_strerr_setup (log_to_stderr ? MU_STRERR_STDERR : MU_STRERR_SYSLOG); if (getgid () == 0) { if (wydawca_uid == 0) { if (!force_startup) { logmsg (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); } mail_init (); wydawca_lock_init (); logmsg (LOG_NOTICE, _("wydawca (%s) started"), PACKAGE_STRING); if (!daemon_mode) { scan_all_spools (uidc, uidv); logstats (); } else wydawca_daemon (); logmsg (LOG_NOTICE, _("wydawca (%s) finished"), PACKAGE_STRING); mail_finish (); if (reconfigure) { int i; for (i = getdtablesize (); i > 2; i--) close (i); remove_pidfile (); execv (x_argv[0], x_argv); } exit (0); }