/* wydawca - automatic release submission daemon Copyright (C) 2007, 2009 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" #include "argmatch.h" #include "version-etc.h" 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; gl_list_t all_spool_aliases; struct gconf_sockaddr listen_sockaddr; unsigned wydawca_stat[MAX_STAT]; 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 = x2realloc (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"), }; 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", }; 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) { char sbuf[INT_BUFSIZE_BOUND (wydawca_stat[0])]; def->storage = xstrdup (uinttostr (wydawca_stat[(int) def->data], sbuf)); def->value = def->storage; return def->value; } struct metadef * make_stat_expansion (size_t count) { int i; struct metadef *def, *p; def = xcalloc (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 gconf_print_diag (gconf_locus_t *locus, int err, int errcode, const char *msg) { if (locus) { if (errcode) logmsg (err ? LOG_ERR : LOG_WARNING, "%s:%lu: %s: %s", locus->file, (unsigned long)locus->line, msg, strerror (errcode)); else logmsg (err ? LOG_ERR : LOG_WARNING, "%s:%lu: %s", locus->file, (unsigned long)locus->line, msg); } 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 int collect_uids (int argc, char **argv) { int i; uidc = argc; uidv = xcalloc (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" int main (int argc, char **argv) { program_name = argv[0]; mu_register_all_mailer_formats (); config_init (); x_argv = argv; parse_options (argc, argv); argv += optind; argc -= optind; if (argc) collect_uids (argc, argv); if (preprocess_only) exit (gconf_preproc_run (conffile, gconf_preprocessor) ? EX_CONFIG : 0); if (gconf_parse (conffile)) exit (EX_CONFIG); if (lint_mode) exit (0); if (dry_run_mode) 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); gconf_log_to_stderr = log_to_stderr; if (!log_to_stderr) { openlog (syslog_tag, LOG_PID, log_facility); log_printer = syslog_printer; } 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); }