diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-01-13 09:02:15 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-01-13 09:02:15 +0000 |
commit | 815aa54b792dc3a5d76feda5f607751800947089 (patch) | |
tree | 9faeb5c7463d4b6c746f2a33c21273e03a22ca36 | |
parent | c26d08f65eb38c411939fe35c3d318dc1c1388a6 (diff) | |
download | mailfromd-815aa54b792dc3a5d76feda5f607751800947089.tar.gz mailfromd-815aa54b792dc3a5d76feda5f607751800947089.tar.bz2 |
* pies: New directory.
* pies/Makefile.am: New file.
* pies/pies.c, pies/progman.c, pies/pies.h, pies/pies.rcin: New
files.
* smap/smap.c (switch_to_privs): Remove. Use library version instead.
* pmult/pmult.c: New configuration file statement `pidfile'.
(pmult_connect): Ignore gsrv if its remote milter is not
listening.
* configure.ac, Makefile.am: Add pies.
* lib/libmf.h (getmaxfd): New define.
* NEWS: Update.
git-svn-id: file:///svnroot/mailfromd/branches/gmach@1561 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | NEWS | 14 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | lib/libmf.h | 8 | ||||
-rw-r--r-- | pies/Makefile.am | 39 | ||||
-rw-r--r-- | pies/pies.c | 779 | ||||
-rw-r--r-- | pies/pies.h | 83 | ||||
-rw-r--r-- | pies/pies.rcin | 7 | ||||
-rw-r--r-- | pies/progman.c | 626 | ||||
-rw-r--r-- | pmult/pmult.c | 3 | ||||
-rw-r--r-- | smap/smap.c | 112 |
12 files changed, 1582 insertions, 110 deletions
@@ -1,3 +1,17 @@ +2008-01-13 Sergey Poznyakoff <gray@gnu.org.ua> + + * pies: New directory. + * pies/Makefile.am: New file. + * pies/pies.c, pies/progman.c, pies/pies.h, pies/pies.rcin: New + files. + * smap/smap.c (switch_to_privs): Remove. Use library version instead. + * pmult/pmult.c: New configuration file statement `pidfile'. + (pmult_connect): Ignore gsrv if its remote milter is not + listening. + * configure.ac, Makefile.am: Add pies. + * lib/libmf.h (getmaxfd): New define. + * NEWS: Update. + 2008-01-12 Sergey Poznyakoff <gray@gnu.org.ua> * lib/libmf.h: Add switch_to_privs. diff --git a/Makefile.am b/Makefile.am index 7d255764..9b4ef660 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ # This file is part of mailfrom filter. -# Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff +# Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. AUTOMAKE_OPTIONS = gnits 1.8.5 std-options -SUBDIRS = gnu lib gacopyz src mflib smap pmult elisp po etc doc tests +SUBDIRS = gnu lib gacopyz src mflib smap pmult pies elisp po etc doc tests ACLOCAL_AMFLAGS = -I m4 distuninstallcheck_listfiles = find . -type f -not -name 'mailfromd.rc' -print @@ -1,4 +1,4 @@ -Mailfromd NEWS -- history of user-visible changes. 2008-01-08 +Mailfromd NEWS -- history of user-visible changes. 2008-01-13 Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff See the end of file for copying conditions. @@ -9,10 +9,20 @@ Version 4.2.91 (SVN) * Requires Mailutils 1.2.90 or better. -* Includes smap. +* New programs: + +** smap. Smap is a general-purpose remote map for MeTA1. +** pmult + +Pmult is a pmilter to milter multiplexer. + +** pies + +Pies is a process execution supervisor. + * Milter `ports' can be specified using URL notation, e.g.: inet://127.0.0.1:1234 instead of inet:1234@127.0.0.1 diff --git a/configure.ac b/configure.ac index f0c3da18..30584080 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ m4_define([MF_VERSION_MINOR], 2) m4_define([MF_VERSION_PATCH], 91) AC_INIT([gmach], MF_VERSION_MAJOR.MF_VERSION_MINOR[]m4_ifdef([MF_VERSION_PATCH],.MF_VERSION_PATCH), - [bug-mailfromd@gnu.org.ua]) + [bug-gmach@gnu.org.ua]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) @@ -642,6 +642,7 @@ AC_CONFIG_FILES([Makefile mflib/Makefile smap/Makefile pmult/Makefile + pies/Makefile elisp/Makefile po/Makefile.in etc/Makefile diff --git a/lib/libmf.h b/lib/libmf.h index c5e43cf3..2ec0bcbd 100644 --- a/lib/libmf.h +++ b/lib/libmf.h @@ -23,6 +23,14 @@ #define _(String) gettext(String) #define N_(String) String +#if defined HAVE_SYSCONF && defined _SC_OPEN_MAX +# define getmaxfd() sysconf(_SC_OPEN_MAX) +#elif defined (HAVE_GETDTABLESIZE) +# define getmaxfd() getdtablesize() +#else +# define getmaxfd() 256 +#endif + void mailfromd_version(const char *progname, FILE *stream); void mf_init_nls (void); int parse_time_interval(const char *str, time_t *pint, const char **endp); diff --git a/pies/Makefile.am b/pies/Makefile.am new file mode 100644 index 00000000..34f6232e --- /dev/null +++ b/pies/Makefile.am @@ -0,0 +1,39 @@ +# This file is part of mailfrom filter. +# Copyright (C) 2008 Sergey Poznyakoff +# +# This program 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, or (at your option) +# any later version. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +sbin_PROGRAMS = pies + +pies_SOURCES = pies.c progman.c pies.h +EXTRA_DIST = pies.rcin +noinst_DATA = pies.rc +DISTCLEANFILES = pies.rc +.rcin.rc: + sed 's|SBINDIR|$(sbindir)|g' $< > $@ + +INCLUDES = \ + $(MAILUTILS_INCLUDES)\ + $(MU_COMMON_INCLUDES)\ + -I$(top_srcdir)/lib\ + -I$(top_srcdir)/gnu\ + -I../gnu + +LDADD = \ + ../lib/libmf.a\ + ../gnu/libgnu.a\ + $(MAILUTILS_LIBS) + +AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"\ + -DSTATEDIR=\"$(localstatedir)\" diff --git a/pies/pies.c b/pies/pies.c new file mode 100644 index 00000000..a774ff27 --- /dev/null +++ b/pies/pies.c @@ -0,0 +1,779 @@ +/* This file is part of mailfromd. + Copyright (C) 2008 Sergey Poznyakoff + + This program 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, or (at your option) + any later version. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "pies.h" + +int log_to_stderr; /* Use stderr for logging */ +char *syslog_tag; /* Tag to mark syslog entries with. */ +mu_log_level_t debug_level; +mu_debug_t pmult_debug; +struct pies_privs_data pies_user; +int foreground; +int command; +char *pidfile = STATEDIR "/pies.pid"; +char *ctlfile = STATEDIR "/pies.ctl"; +char *statfile = STATEDIR "/pies.stat"; +mode_t pies_umask = 0; +unsigned long shutdown_timeout = 5; + + +/* Logging */ +void +log_setup (int want_stderr) +{ + mu_debug_t debug; + + mu_diag_get_debug (&debug); + + if (!want_stderr) + { + openlog (syslog_tag, LOG_PID, log_facility); + mu_debug_set_print (debug, mu_diag_syslog_printer, NULL); + mu_debug_default_printer = mu_debug_syslog_printer; + } +} + +static int +stderr_closed_p() +{ + int fd = dup (0); + if (fd < 0) + return 1; + close (fd); + return fd <= 2; +} + + +static int +_cb_group (mu_debug_t debug, void *data, char *arg) +{ + int argc, i; + char **argv; + mu_list_t *plist = data, list; + int rc; + + rc = mu_argcv_get_np (arg, strlen (arg), ",", NULL, 0, &argc, &argv, NULL); + if (rc) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + "mu_argcv_get: %s", mu_strerror (rc)); + return 1; + } + if (*plist) + list = *plist; + else + { + mu_list_create (&list); + *plist = list; + } + for (i = 0; i < argc; i++) + mu_list_append (list, xstrdup (argv[i])); + mu_argcv_free (argc, argv); + return 0; +} + + +static int +_cb_command (mu_debug_t debug, void *data, char *arg) +{ + int argc; + char **argv, ***pargv = data; + int rc; + + rc = mu_argcv_get (arg, "", NULL, &argc, &argv); + if (rc) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + "mu_argcv_get: %s", mu_strerror (rc)); + return 1; + } + *pargv = argv; + return 0; +} + +static int +_cb_depend (mu_debug_t debug, void *data, char *arg) +{ + int argc; + char **argv, ***pargv = data; + int rc; + + rc = mu_argcv_get_np (arg, strlen (arg), ",", NULL, 0, &argc, &argv, NULL); + if (rc) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + "mu_argcv_get: %s", mu_strerror (rc)); + return 1; + } + *pargv = argv; + return 0; +} + +static int +_cb_umask (mu_debug_t debug, void *data, char *arg) +{ + mode_t *pmode = data; + char *p; + unsigned long n = strtoul (arg, &p, 8); + if (*p) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("Invalid octal number")); + return 1; + } + *pmode = n; + return 0; +} + +static int +_cb_retr (mu_debug_t debug, void *data, char *arg) +{ + if (mu_string_to_syslog_priority (arg, data)) + { + mu_cfg_format_error (debug, MU_DEBUG_ERROR, + _("Unknown syslog facility `%s'"), + arg); + return 1; + } + return 0; +} + +struct mu_cfg_param component_cfg_param[] = { + { "command", mu_cfg_callback, NULL, + mu_offsetof (struct component, argv), _cb_command, + N_("Command line.") }, + { "depend", mu_cfg_callback, NULL, + mu_offsetof (struct component, depend), _cb_depend, + N_("List of dependenices (whitespace separated)"), + N_("list") }, + { "disable", mu_cfg_bool, NULL, + mu_offsetof (struct component, disabled), NULL, + N_("Disable this entry.") }, + { "remove-file", mu_cfg_string, NULL, + mu_offsetof (struct component, rmfile), NULL, + N_("Remove file before starting the component.") + N_("file") }, + { "stdout", mu_cfg_callback, NULL, + mu_offsetof (struct component, retr[RETR_OUT]), _cb_retr, + N_("Redirect program's standard output to the given syslog priority."), + N_("prio: {emerg | alert | crit | err | warning | notice | info | debug}") + }, + { "stderr", mu_cfg_callback, NULL, + mu_offsetof (struct component, retr[RETR_ERR]), _cb_retr, + N_("Redirect program's standard output to the given syslog priority."), + N_("prio: {emerg | alert | crit | err | warning | notice | info | debug}") + }, + { "user", mu_cfg_string, NULL, + mu_offsetof (struct component, privs.user), NULL, + N_("Run with this user privileges.") }, + { "group", mu_cfg_callback, NULL, + mu_offsetof (struct component, privs.groups), _cb_group, + N_("Retain supplementary group.") }, + { "umask", mu_cfg_callback, NULL, + mu_offsetof (struct component, umask), _cb_umask, + N_("Force this umask."), + N_("arg: number") }, + { NULL } +}; + +static int +component_section_parser (enum mu_cfg_section_stage stage, + const mu_cfg_node_t *node, + const char *section_label, void **section_data, + void *call_data, + mu_cfg_tree_t *tree) +{ + static struct component comp; + switch (stage) + { + case mu_cfg_section_start: + memset (&comp, 0, sizeof comp); + comp.tag = node->tag_label ? xstrdup (node->tag_label) : NULL; + *section_data = ∁ + break; + + case mu_cfg_section_end: + register_prog (&comp); + } + return 0; +} + +void +component_cfg_init () +{ + struct mu_cfg_section *section; + + if (mu_create_canned_section ("component", §ion)) + exit (EX_SOFTWARE); + section->parser = component_section_parser; + section->label = N_("<tag: string>"); + mu_cfg_section_add_params (section, component_cfg_param); +} + + + + +static int +_cb_debug (mu_debug_t debug, void *data, char *arg) +{ + int rc; + + rc = mu_debug_level_from_string (arg, &debug_level, debug); + if (rc) + return 0; + if (!pmult_debug) + mu_debug_create (&pmult_debug, NULL); + mu_debug_set_level (pmult_debug, debug_level); + return 0; +} + +struct mu_cfg_param pies_cfg_param[] = { + { "component", mu_cfg_section }, + /* MU-FIXME: */ + { "log-tag", mu_cfg_string, &syslog_tag, 0, NULL, + N_("Set syslog tag string.") }, + { "debug", mu_cfg_callback, NULL, 0, _cb_debug, + N_("Set debug verbosity level.") }, + { "pidfile", mu_cfg_string, &pidfile, 0, NULL, + N_("Write PID to this file.") }, + { "control-file", mu_cfg_string, &ctlfile, 0, NULL, + N_("Set location of the control file.") }, + { "stat-file", mu_cfg_string, &statfile, 0, NULL, + N_("Set location of the statistics output file.") }, + { "user", mu_cfg_string, &pies_user.user, 0, NULL, + N_("Run with this user privileges.") }, + { "group", mu_cfg_callback, &pies_user.groups, 0, _cb_group, + N_("Retain supplementary group.") }, + { "umask", mu_cfg_callback, &pies_umask, 0, _cb_umask, + N_("Force this umask."), + N_("arg: number") }, + { "shutdown-timeout", mu_cfg_uint, &shutdown_timeout, 0, NULL, + N_("Wait <n> seconds for all children to shut down."), + "n" }, + { NULL } +}; + + +const char *program_version = "pies (" PACKAGE_STRING ")"; +const char *package_bugreport = "<" PACKAGE_BUGREPORT ">"; +static char doc[] = N_("pies -- process inspector and execution supervisor"); +static char args_doc[] = ""; + +static const char *capa[] = { + "common", + "logging", + NULL +}; + +enum { + OPT_FOREGROUND=256, + OPTION_LOG_TAG, + OPT_SYSLOG, + OPT_STDERR +}; + +#define OPT_RESTART 'R' +#define OPT_RELOAD 'r' +#define OPT_STATUS 's' +#define OPT_STOP 'S' + +static struct argp_option options[] = { +#define GRP 0 + { "foreground", OPT_FOREGROUND, 0, 0, N_("Remain in foreground."), GRP+1}, + { "stderr", OPT_STDERR, NULL, 0, N_("Log to stderr"), }, + { "syslog", OPT_SYSLOG, NULL, 0, N_("Log to syslog"), }, + { "log-tag", OPTION_LOG_TAG, N_("STRING"), 0, + N_("Set the identifier used in syslog messages to STRING"), GRP+1 }, + { "debug", 'x', N_("LEVEL"), 0, + N_("Set debug verbosity level."), GRP+1 }, +#undef GRP + +#define GRP 10 + { "restart-component", OPT_RESTART, NULL, 0, + N_("Restart components named in the command line."), GRP+1 }, + { "reload", OPT_RELOAD, NULL, 0, + N_("Reload the running instance of pies."), GRP+1 }, + { "hup", 0, NULL, OPTION_ALIAS }, + { "status", OPT_STATUS, NULL, 0, + N_("Display info about the running instance."), GRP+1 }, + { "stop", OPT_STOP, NULL, 0, + N_("Stop the running instance."), GRP+1 }, +#undef GRP + { NULL } +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + static struct mu_argp_node_list lst; + + switch (key) + { + case OPT_FOREGROUND: + foreground = 1; + break; + + case OPT_RELOAD: + case OPT_STATUS: + case OPT_STOP: + case OPT_RESTART: + log_to_stderr = 1; + command = key; + break; + + case OPT_SYSLOG: + log_to_stderr = 0; + break; + + case OPT_STDERR: + log_to_stderr = 1; + break; + + case 'x': + mu_argp_node_list_new (&lst, "debug", arg); + break; + + case OPTION_LOG_TAG: + mu_argp_node_list_new (&lst, "log-tag", arg); + break; + + case ARGP_KEY_INIT: + mu_argp_node_list_init (&lst); + break; + + case ARGP_KEY_FINI: + mu_argp_node_list_finish (&lst, NULL, NULL); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, + parse_opt, + args_doc, + doc, + NULL, + NULL, + NULL +}; + + +static void +version (FILE *stream, struct argp_state *state) +{ + mailfromd_version ("pies", stream); +} + + +void +priv_setup (struct pies_privs_data *pr) +{ + if (pr->user) + { + struct passwd *pw = getpwnam (pr->user); + if (!pw) + { + mu_error (_("No such user: %s"), pr->user); + exit (EX_SOFTWARE); + } + if (pw && switch_to_privs (pw->pw_uid, pw->pw_gid, pr->groups)) + exit (EX_SOFTWARE); + } +} + + +#define ACTION_CONT 0 +#define ACTION_STOP 1 +#define ACTION_RESTART 2 +#define ACTION_COMPRELOAD 3 +#define ACTION_DUMPSTATS 4 + +int action = ACTION_CONT; +int children_cleanup = 0; +int got_alarm = 0; + +RETSIGTYPE +sig_handler (int sig) +{ + switch (sig) + { + case SIGCHLD: + children_cleanup = 1; + break; + + case SIGTERM: + case SIGINT: + case SIGQUIT: + action = ACTION_STOP; + mu_diag_output (MU_DIAG_NOTICE, "received signal %d", sig); + break; + + case SIGHUP: + mu_diag_output (MU_DIAG_NOTICE, "received signal %d", sig); + action = ACTION_RESTART; + break; + + case SIGALRM: + got_alarm = 1; + break; + + case SIGUSR1: + action = ACTION_COMPRELOAD; + break; + + case SIGUSR2: + action = ACTION_DUMPSTATS; + break; + } + signal (sig, sig_handler); +} + +void +signal_setup (RETSIGTYPE (*sf)(int)) +{ + signal (SIGCHLD, sf); + signal (SIGTERM, sf); + signal (SIGQUIT, sf); + signal (SIGINT, sf); + signal (SIGHUP, sf); + signal (SIGALRM, sf); + signal (SIGUSR1, sf); + signal (SIGUSR2, sf); +} + + +pid_t +pidfile_read (int must_exist) +{ + int c; + pid_t n = 0; + FILE *fp = fopen (pidfile, "r"); + if (!fp) + { + if (must_exist && errno != ENOENT) + mu_diag_output (MU_DIAG_ERR, + _("cannot open pid file `%s': %s"), + pidfile, + mu_strerror (errno)); + return -1; + } + + while ((c = fgetc (fp)) != EOF) + { + if (isdigit (c)) + n = n * 10 + c - '0'; + else if (c == '\n') + break; + else + { + mu_diag_output (MU_DIAG_ERR, + _("unexpected character %#03o in pidfile `%s'"), + c, pidfile); + return -1; + } + } + fclose (fp); + if (kill (n, 0)) + { + mu_diag_output (MU_DIAG_ERR, + _("cannot signal master process %lu: %s"), + (unsigned long) n, mu_strerror (errno)); + if (errno == EPERM) + return n; /* be on the safe side */ + return -1; + } + return n; +} + + +void +stop_components () +{ + FILE *fp; + size_t size = 0; + char *buf = NULL; + + mu_diag_output (MU_DIAG_INFO, _("stopping components")); + + fp = fopen (ctlfile, "r"); + if (!fp) + { + mu_error (_("cannot open control file `%s': %s"), + ctlfile, mu_strerror (errno)); + return; + } + if (unlink (ctlfile)) + { + mu_error (_("cannot unlink control file `%s': %s"), + ctlfile, mu_strerror (errno)); + fclose (fp); + return; + } + + while (getline (&buf, &size, fp) > 0) + { + size_t len = strlen (buf); + if (len == 0) + continue; + if (buf[len-1] == '\n') + buf[len-1] = 0; + progman_stop_component (buf); + } + + free (buf); + fclose (fp); +} + +int +request_restart_components (char **argv) +{ + FILE *fp; + pid_t pid = pidfile_read (1); + + if (pid == -1) + return 1; + + fp = fopen (ctlfile, "w"); + if (!fp) + { + mu_error (_("cannot open control file `%s': %s"), + ctlfile, mu_strerror (errno)); + return 1; + } + for (; *argv; argv++) + fprintf (fp, "%s\n", *argv); + fclose (fp); + + kill (pid, SIGUSR1); + return 0; +} + + +int +pies_reload () +{ + pid_t pid = pidfile_read (1); + + if (pid == -1) + { + mu_diag_output (MU_DIAG_CRIT, _("pies is not running")); + return 1; + } + + mu_diag_output (MU_DIAG_INFO, _("reloading pies at PID %lu"), + (unsigned long) pid); + return kill (pid, SIGHUP) ? EX_SOFTWARE : 0; +} + +int +pies_status () +{ + FILE *fp; + pid_t pid = pidfile_read (0); + int i; + + if (pid == -1) + { + mu_diag_output (MU_DIAG_INFO, _("pies is not running")); + return EX_USAGE; + } + + if (kill (pid, SIGUSR2)) + { + mu_diag_output (MU_DIAG_INFO, + _("pies is not running, but a pidfile " + "is found (pid %lu)"), + (unsigned long) pid); + return EX_USAGE; + } + + mu_diag_output (MU_DIAG_INFO, + _("pies is running; PID %lu"), + (unsigned long) pid); + + for (i = 0; i < 4 && access (statfile, R_OK); i++) + sleep (1); + + fp = fopen (statfile, "r"); + if (!fp) + mu_diag_output (MU_DIAG_ERR, _("cannot open statfile `%s': %s"), + statfile, mu_strerror (errno)); + else + { + char c; + + if (unlink (statfile)) + mu_diag_output (MU_DIAG_ERR, _("cannot unlink statfile `%s': %s"), + statfile, mu_strerror (errno)); + while ((c = fgetc (fp)) != EOF) + fputc (c, stdout); + fclose (fp); + } + return 0; +} + +int +pies_stop () +{ + pid_t pid = pidfile_read (1); + + if (pid == -1) + { + mu_diag_output (MU_DIAG_CRIT, _("pies is not running")); + return EX_USAGE; + } + + mu_diag_output (MU_DIAG_INFO, + _("stopping pies at PID %lu"), (unsigned long) pid); + return kill (pid, SIGTERM) ? EX_SOFTWARE : 0; +} + + +int +main (int argc, char **argv) +{ + int rc; + int index; + + mf_init_nls (); + if (!program_invocation_short_name) + program_invocation_short_name = argv[0]; + argp_program_version_hook = version; + /* Set default logging */ + log_facility = DEFAULT_LOG_FACILITY; + log_setup (!stderr_closed_p ()); + component_cfg_init (); + mu_argp_init (program_version, package_bugreport); + rc = mu_app_init (&argp, capa, pies_cfg_param, argc, argv, 0, &index, NULL); + if (rc) + exit (EX_CONFIG); + + log_setup (log_to_stderr); + + if (argc != index && command != 'r') + { + mu_error ("extra command line arguments"); + exit (EX_CONFIG); + } + + switch (command) + { + case OPT_RESTART: + priv_setup (&pies_user); + if (pies_umask) + umask (pies_umask); + exit (request_restart_components (argv + index)); + + case OPT_RELOAD: + exit (pies_reload ()); + + case OPT_STATUS: + exit (pies_status ()); + + case OPT_STOP: + exit (pies_stop ()); + + default: + priv_setup (&pies_user); + if (pies_umask) + umask (pies_umask); + } + + mu_diag_output (MU_DIAG_INFO, _("%s starting"), program_version); + + if (!foreground && daemon (0, 0) == -1) + { + mu_error (_("cannot become a daemon: %s"), + mu_strerror (errno)); + exit (EX_SOFTWARE); + } + + rc = mu_daemon_create_pidfile (pidfile); + if (rc) + mu_error (_("Cannot create PID file `%s': %s"), + pidfile, mu_strerror (rc)); + + if (argv[0][0] != '/') + mu_diag_output (MU_DIAG_NOTICE, + N_("not started as an absolute pathname; " + "SIGHUP will not work")); + + signal_setup (sig_handler); + + progman_start (); + + while (action == ACTION_CONT) + { + pause (); + if (children_cleanup) + { + children_cleanup = 0; + progman_cleanup (0); + } + if (got_alarm) + { + got_alarm = 0; + progman_wake_disabled (); + } + switch (action) + { + case ACTION_COMPRELOAD: + stop_components (); + action = ACTION_CONT; + break; + + case ACTION_DUMPSTATS: + progman_dump_stats (statfile); + action = ACTION_CONT; + break; + } + } + progman_stop (); + + if (action == ACTION_RESTART && argv[0][0] == '/') + { + int i; + + for (i = getmaxfd (); i > 0; i--) + close (i); + + mu_daemon_remove_pidfile (); + signal_setup (SIG_DFL); + + execv (argv[0], argv); + } + + mu_diag_output (MU_DIAG_INFO, _("%s terminated"), program_version); + exit (EX_OK); +} + +void +xalloc_die () +{ + mu_error ("not enough memory"); + abort (); +} + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ +/* EOF */ diff --git a/pies/pies.h b/pies/pies.h new file mode 100644 index 00000000..94c8ded1 --- /dev/null +++ b/pies/pies.h @@ -0,0 +1,83 @@ +/* This file is part of mailfromd. + Copyright (C) 2008 Sergey Poznyakoff + + This program 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, or (at your option) + any later version. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <syslog.h> +#include <getopt.h> +#include <errno.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include <signal.h> +#include <sysexits.h> +#include <mailutils/mailutils.h> +#include <mailutils/daemon.h> +#include <mailutils/libargp.h> + +#include "xalloc.h" +#include "libmf.h" + +#define RETR_OUT 0 +#define RETR_ERR 1 + +#define TESTTIME 2*60 +#define SLEEPTIME 5*60 +#define MAXSPAWN 10 + +struct pies_privs_data +{ + char *user; + mu_list_t groups; +}; + +struct component +{ + char *tag; /* Entry tag (for diagnostics purposes) */ + char **argv; + char **depend; /* Dependencies */ + int disabled; + char *rmfile; + int retr[2]; + struct pies_privs_data privs; + mode_t umask; +}; + +void register_prog (struct component *comp); +size_t progman_running_count (void); +void progman_start (void); +void progman_wake_disabled (void); +void progman_stop (void); +void progman_cleanup (int expect_term); +void progman_stop_component (const char *name); +void progman_dump_stats (const char *filename); + +void log_setup (int want_stderr); +void signal_setup (RETSIGTYPE (*sf)(int)); +void priv_setup (struct pies_privs_data *pr); + +extern char *syslog_tag; +extern unsigned long shutdown_timeout; + diff --git a/pies/pies.rcin b/pies/pies.rcin new file mode 100644 index 00000000..cfef9a8d --- /dev/null +++ b/pies/pies.rcin @@ -0,0 +1,7 @@ +# Sample pies configuration for running pmult. + +component pmult { + command "SBINDIR/pmult"; + user meta1s; +}; + diff --git a/pies/progman.c b/pies/progman.c new file mode 100644 index 00000000..385a1258 --- /dev/null +++ b/pies/progman.c @@ -0,0 +1,626 @@ +/* This file is part of mailfromd. + Copyright (C) 2007, 2008 Sergey Poznyakoff + + This program 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. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "pies.h" + +#define TYPE_COMPONENT 0 +#define TYPE_RETR 1 + +struct prog +{ + struct prog *next; + int type; + pid_t pid; /* PID */ + char *tag; /* Entry tag (for diagnostics purposes) */ + char **depend; + union + { + struct + { + int argc; + char **argv; /* Command line arguments */ + int retr[2]; + char *rmfile; /* Rmfile location */ + struct pies_privs_data privs; + mode_t umask; + time_t timestamp; /* Time of last startup */ + size_t count; /* Number of failed starts since timestamp */ + int disabled; /* 1 if this entry is disabled */ + } p; + |