aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2008-01-13 09:02:15 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2008-01-13 09:02:15 +0000
commit815aa54b792dc3a5d76feda5f607751800947089 (patch)
tree9faeb5c7463d4b6c746f2a33c21273e03a22ca36
parentc26d08f65eb38c411939fe35c3d318dc1c1388a6 (diff)
downloadmailfromd-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--ChangeLog14
-rw-r--r--Makefile.am4
-rw-r--r--NEWS14
-rw-r--r--configure.ac3
-rw-r--r--lib/libmf.h8
-rw-r--r--pies/Makefile.am39
-rw-r--r--pies/pies.c779
-rw-r--r--pies/pies.h83
-rw-r--r--pies/pies.rcin7
-rw-r--r--pies/progman.c626
-rw-r--r--pmult/pmult.c3
-rw-r--r--smap/smap.c112
12 files changed, 1582 insertions, 110 deletions
diff --git a/ChangeLog b/ChangeLog
index dcc6bbb8..933d2514 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 3f56c4b1..4cfcfb8e 100644
--- a/NEWS
+++ b/NEWS
@@ -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 = &comp;
+ 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", &section))
+ 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;
+