From c60e857d7f35128b077eac4a30a5900925bb38e8 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 13 Oct 2009 16:53:42 +0300 Subject: Bugfixes. * README: Update. * configure.ac: Change bug-reporting address. * doc/pies.texi: Minor fixes. * src/pies.c: New configuration statements: mailer-program and mailer-command-line. (mailer_program, mailer_command_line) (mailer_argc, mailer_argv): New globals. * src/pies.h (mailer_program, mailer_command_line) (mailer_argc, mailer_argv): New globals. * src/progman.c (destroy_prog): Bugfix: update master program when destroying a retranslator. (send_msg): Several bugfixes. Use mailer_argc, mailer_argv instead of hardcoding sendmail command line. Remove invalid recipient addresses from the resulting command line. --- README | 84 ++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- doc/pies.texi | 30 ++++++++++----- src/pies.c | 46 +++++++++++++++++++++- src/pies.h | 6 ++- src/progman.c | 121 +++++++++++++++++++++++++++++++++++++++++----------------- 6 files changed, 240 insertions(+), 49 deletions(-) diff --git a/README b/README index e69de29..6b86aea 100644 --- a/README +++ b/README @@ -0,0 +1,84 @@ +Pies README +Copyright (C) 2009 Sergey Poznyakoff +See the end of file for copying conditions. + +* Introduction + +This file contains brief information about configuring, testing +and running Pies. It is *not* intended as a replacement +for the documentation, it is provided as a brief reference only. +The complete documentation for Pies is available in +doc/ subdirectory. To read it without installing the package +run `info -f doc/pies.info'. After the package is installed +the documentation can be accessed running `info Pies'. Invoking +`info pies' (with lower-case `p') will show you a concise +description of the command line syntax (similar to a man-page style). + +* Overview + +Pies (pronounced ``p-yes'') stands for the Program Invocation and +Execution Supervisor. This utility starts and controls execution of +external programs, called ``components''. Each component is a stand-alone +program, designed to be executed in the foreground. Upon startup pies +reads the list of components from its configuration file, starts them, +and remains in the background, controlling their execution. When a +component terminates, pies tries to restarts it. Its configuration allows +to specify actions other than simple restart, depending on the exit code +of the component. + +Pies supports a wide variety of component types. For example, it can +bind the standard input and output of a component to a network socket, +which makes pies a replacement for the inetd utility. Pies implements +powerful access control lists, which are especially useful with such +inetd-style components. + +Pies can also be used to manage MeTA1 (http://meta1.org) components. +Moreover, it is able to use MeTA1 configuration file directly, so that +migration from the native mcp utility to pies does not require any +efforts. + +Pies gives you complete control over the execution environment of +each component. This includes modifying shell environment, running +components with the given user privileges, etc. The standard error +and/or output of any component may be redirected either to a disk +file or to syslog. + +* Building + +A usual three-state procedure: + + ./configure + make + make install + +See INSTALL for a generic options to ./configure. + +* Configuring and Running + +Please, see the Pies documentation. + +* Bug reporting. + +Send bug reports to . + + +* Copyright information: + +Copyright (C) 2009 Sergey Poznyakoff + + Permission is granted to anyone to make or distribute verbatim copies + of this document as received, in any medium, provided that the + copyright notice and this permission notice are preserved, + thus giving the recipient permission to redistribute in turn. + + Permission is granted to distribute modified versions + of this document, or of portions of it, + under the above conditions, provided also that they + carry prominent notices stating who last changed them. + + +Local Variables: +mode: outline +paragraph-separate: "[ ]*$" +version-control: never +End: diff --git a/configure.ac b/configure.ac index e454566..6903b8e 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ # along with Pies. If not, see . AC_PREREQ([2.63]) -AC_INIT([pies], [1.0], [bug-mailfromd@gnu.org.ua]) +AC_INIT([pies], [1.0], [bug-pies@gnu.org.ua]) AC_CONFIG_SRCDIR([src/pies.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) diff --git a/doc/pies.texi b/doc/pies.texi index 22c0f83..3f9ec4b 100644 --- a/doc/pies.texi +++ b/doc/pies.texi @@ -153,7 +153,8 @@ described above. This mode of operation is similar to that of @cindex smtps The third type of components, supported by @command{pies} are @dfn{meta1-style} components. As the name suggests this type is -designed expressly as a support for MeTA1 components, namely +designed expressly as a support for MeTA1@footnote{See +@uref{http://www.meta1.org}} components, namely @command{smtps}. This type can be regarded as a mixture of the above two. For each meta1-style component @command{pies} opens a socket after start-up, and then executes the component. Once the component @@ -1210,9 +1211,16 @@ acl common @{ @node include-meta1 @section Using MeTA1 Configuration File -@cindex /etc/meta1/meta1.conf - @command{Pies} is able to take a list of components from MeTA1 -configuration file: +@flindex /etc/meta1/meta1.conf + MeTA1 is a mail transfer agent of new generation, designed +to replace Sendmail in the future (@uref{http://www.meta1.org}). +It has a modular structure, each module being an independent +program, which is responsible for a particular task. The components +are configured in the MeTA1 configuration file +@file{/etc/meta1/meta1.conf}. + + @command{Pies} is able to take a list of components directly +from MeTA1 configuration file: @deffn {Config} include-meta1 @var{file} Parse @var{file} as MeTA1 configuration file and incorporate @@ -1224,12 +1232,14 @@ include-meta1 /etc/meta1/meta1.conf; @end deffn Thus, you can use @command{pies} instead of the default MeTA1 program -manager @command{mcp}. +manager @command{mcp}. This is particularly useful if you use +@samp{Mailfromd} (@uref{http://mailfromd.software.gnu.org.ua}) to +control the mail flow. -To ensure compatibility with MeTA1, the components read from MeTA1 -configuration are started in the reverse order (i.e. from last to first), -and stopped in the order of their appearance in @var{file}. Of course, -this does not affect normal @command{pies} components. +To ensure compatibility with MeTA1, the components read from its +configuration file are started in the reverse order (i.e. from last to +first), and stopped in the order of their appearance in @var{file}. +Of course, this does not affect normal @command{pies} components. The following @command{pies} statements are silently applied to all MeTA1 components: @@ -1711,7 +1721,7 @@ Display program version and license information and exit. @node Reporting Bugs @chapter How to Report a Bug - Send bug-reports and suggestions to @email{bug-mailfromd@@gnu.org.ua}. + Send bug-reports and suggestions to @email{bug-pies@@gnu.org.ua}. If you think you've found a bug, please be sure to include maximum information needed to reliably reproduce it, or at least to analyze diff --git a/src/pies.c b/src/pies.c index 87ddad3..3fcc529 100644 --- a/src/pies.c +++ b/src/pies.c @@ -36,6 +36,11 @@ unsigned long shutdown_timeout = 5; pies_acl_t pies_acl; limits_record_t pies_limits; int force_option; +char *mailer_program = "/usr/sbin/sendmail"; +char *mailer_command_line = "/usr/sbin/sendmail -oi -t"; +int mailer_argc; +char **mailer_argv; + /* Logging */ @@ -1164,6 +1169,18 @@ struct grecs_keyword pies_keywords[] = { grecs_type_string, &meta1_queue_dir, 0, NULL, }, + {"mailer-program", + NULL, + N_("Full path to the mailer binary."), + grecs_type_string, &mailer_program, 0, + NULL + }, + {"mailer-command-line", + NULL, + N_("Mailer command line (without recipient addresses)."), + grecs_type_string, &mailer_command_line, 0, + NULL + }, {NULL} }; @@ -1258,6 +1275,7 @@ parse_opt (int key, char *arg, struct argp_state *state) switch (key) { case 't': + log_to_stderr = 1; lint_mode = 1; break; @@ -1274,6 +1292,7 @@ parse_opt (int key, char *arg, struct argp_state *state) exit (0); case OPT_FOREGROUND: + log_to_stderr = 1; foreground = 1; break; @@ -1670,6 +1689,28 @@ remove_pidfile (char *name) logmsg (LOG_ERR, _("cannot unlink pidfile `%s': %s"), name, strerror (errno)); } + + +static void +set_mailer_argcv () +{ + int i; + struct wordsplit ws; + + if (wordsplit (mailer_command_line, &ws, WRDSF_DEFFLAGS)) + { + logmsg (LOG_CRIT, _("cannot parse mailer command line: %s"), + strerror (errno)); + exit (EX_CONFIG); + } + mailer_argc = ws.ws_wordc; + mailer_argv = xcalloc (mailer_argc + 1, sizeof (mailer_argv[0])); + for (i = 0; i < mailer_argc; i++) + mailer_argv[i] = xstrdup (ws.ws_wordv[i]); + mailer_argv[i] = NULL; + wordsplit_free (&ws); +} + const char version_etc_copyright[] = /* Do *not* mark this string for translation. %s is a copyright @@ -1716,7 +1757,8 @@ main (int argc, char **argv) mf_proctitle_init (argc, argv, environ); /* Set default logging */ - log_setup (!stderr_closed_p ()); + log_to_stderr = !stderr_closed_p (); + log_setup (log_to_stderr); config_init (); argp_program_version_hook = version; if (argp_parse (&argp, argc, argv, 0, &index, NULL)) @@ -1728,6 +1770,8 @@ main (int argc, char **argv) if (grecs_parse (conffile)) exit (EX_CONFIG); + set_mailer_argcv (); + if (lint_mode) { progman_build_depmap (); diff --git a/src/pies.h b/src/pies.h index c57a104..751c2a2 100644 --- a/src/pies.h +++ b/src/pies.h @@ -169,8 +169,12 @@ extern char *log_tag; extern int log_facility; extern unsigned long shutdown_timeout; extern struct component default_component; -pies_acl_t pies_acl; +extern pies_acl_t pies_acl; extern limits_record_t pies_limits; +extern char *mailer_program; +extern char *mailer_command_line; +extern int mailer_argc; +extern char **mailer_argv; void register_prog (struct component *comp); size_t progman_running_count (void); diff --git a/src/progman.c b/src/progman.c index 3211d9a..b85a797 100644 --- a/src/progman.c +++ b/src/progman.c @@ -163,6 +163,23 @@ unlink_prog (struct prog *pp) void destroy_prog (struct prog **pp) { + struct prog *p = *pp; + switch (p->type) + { + case TYPE_COMPONENT: + break; + + case TYPE_RETR: + { + struct prog *master = p->v.r.master; + if (p == master->v.p.redir[0]) + master->v.p.redir[0] = NULL; + else if (p == master->v.p.redir[1]) + master->v.p.redir[1] = NULL; + else + logmsg (LOG_NOTICE, _("orphan redirector: %s"), p->tag); + } + } unlink_prog (*pp); free (*pp); *pp = NULL; @@ -1350,13 +1367,13 @@ wait_for_child (pid_t pid) void send_msg (char *rcpts, const char *msg_text) { - int i; - pid_t pid; + int i, j, k; + pid_t child_pid, grand_child_pid; struct wordsplit ws; int p[2]; size_t size; - ws.ws_offs = 3; /* sendmail -oi -t */ + ws.ws_offs = mailer_argc; ws.ws_delim = ","; if (wordsplit (rcpts, &ws, WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM | WRDSF_DOOFFS)) @@ -1367,12 +1384,21 @@ send_msg (char *rcpts, const char *msg_text) return; } - ws.ws_wordv[0] = "/usr/sbin/sendmail"; /* FIXME: path */ - ws.ws_wordv[1] = "-oi"; - ws.ws_wordv[2] = "-t"; - for (i = 0; i < ws.ws_wordc; i++) + debug (1, (_("sending notification to %s"), rcpts)); + + /* Copy mailer arguments */ + for (i = 0; i < mailer_argc; i++) + ws.ws_wordv[i] = mailer_argv[i]; + /* j - number of the recipient; + i - index of the ws_wordv being converted; + k - index of the ws_wordv to store the converted value to. + + Normally i == k, unless there are some invalid ws_wordv's, + in which case i > k. + */ + for (j = 0, k = i; j < ws.ws_wordc; j++, i++) { - char *arg = ws.ws_wordv[3 + i]; + char *arg = ws.ws_wordv[i]; size_t len; while (*arg && c_isblank (*arg)) @@ -1380,36 +1406,38 @@ send_msg (char *rcpts, const char *msg_text) len = strlen (arg); if (len > 0) { - while (len > 0 && c_isblank(arg[len - 1])) + while (len > 0 && c_isblank (arg[len - 1])) len--; } if (len == 0) - continue; //FIXME + continue; if (arg[0] == '<' && arg[len-1] == '>') { arg++; len -= 2; } if (len == 0) - continue; //FIXME - memmove (ws.ws_wordv[3 + i], arg, len); - ws.ws_wordv[3 + i][len] = 0; + continue; + memmove (ws.ws_wordv[k], arg, len); + ws.ws_wordv[k][len] = 0; + k++; } - + ws.ws_wordv[k] = NULL; + /* Fork a child: */ - pid = fork (); - if (pid <= 0) + child_pid = fork (); + if (child_pid != 0) wordsplit_free (&ws); - if (pid < 0) + if (child_pid < 0) { logmsg (LOG_ERR, _("cannot send mail: fork failed: %s"), strerror (errno)); return; } - if (pid == 0) - //FIXME: SIGCHLD Handler? */ + if (child_pid) + /*FIXME: SIGCHLD Handler? */ return; /* Child process */ @@ -1425,18 +1453,15 @@ send_msg (char *rcpts, const char *msg_text) exit (EX_OSERR); } - pid = fork (); - if (pid <= 0) - wordsplit_free (&ws); - - if (pid < 0) + grand_child_pid = fork (); + if (grand_child_pid < 0) { logmsg (LOG_ERR, _("cannot send mail: fork failed: %s"), strerror (errno)); return; } - if (pid) + if (grand_child_pid == 0) { /* Grand-child */ /* =========== */ @@ -1444,7 +1469,7 @@ send_msg (char *rcpts, const char *msg_text) close (0); close (p[1]); dup2 (p[0], 0); - execv (ws.ws_wordv[0], ws.ws_wordv); + execv (mailer_program, ws.ws_wordv); exit (127); } @@ -1466,7 +1491,7 @@ send_msg (char *rcpts, const char *msg_text) } close (p[1]); - exit (wait_for_child (pid)); + exit (wait_for_child (grand_child_pid)); } static const char default_termination_message[] = @@ -1485,9 +1510,11 @@ notify (const char *tag, int status, struct action *act) { "version", PACKAGE_VERSION }, #define COMPONENT_IDX 3 { "component", NULL }, -#define RETCODE_IDX 4 +#define TERMINATION_IDX 4 + { "termination", NULL }, +#define RETCODE_IDX 5 { "retcode", NULL }, -#define PROGRAM_NAME_IDX 5 +#define PROGRAM_NAME_IDX 6 { "program-name", NULL }, { NULL } }; @@ -1496,7 +1523,21 @@ notify (const char *tag, int status, struct action *act) char buf[INT_BUFSIZE_BOUND (uintmax_t)]; mdef[COMPONENT_IDX].value = (char*) tag; - mdef[RETCODE_IDX].value = umaxtostr (status, buf); + if (WIFEXITED (status)) + { + mdef[TERMINATION_IDX].value = _("exited with code"); + mdef[RETCODE_IDX].value = umaxtostr (WEXITSTATUS (status), buf); + } + else if (WIFSIGNALED (status)) + { + mdef[TERMINATION_IDX].value = _("caught signal"); + mdef[RETCODE_IDX].value = umaxtostr (WTERMSIG (status), buf); + } + else + { + mdef[TERMINATION_IDX].value = "UNKNOWN"; + mdef[RETCODE_IDX].value = "UNKNOWN"; + } mdef[PROGRAM_NAME_IDX].value = (char*) program_name; msg_text = meta_expand_string (act->message ? act->message : default_termination_message, @@ -1614,11 +1655,21 @@ progman_cleanup (int expect_term) act = default_component.act_head; if (WIFEXITED (status)) - retcode = WEXITSTATUS (status); + { + retcode = WEXITSTATUS (status); + debug (1, (_("%s: terminated with code %d"), + prog->tag, retcode)); + } else if (WIFSIGNALED (status)) - retcode = STATUS_SIG_BIT | WTERMSIG (status); + { + retcode = STATUS_SIG_BIT | WTERMSIG (status); + debug (1, (_("%s: terminated on signal %d"), + prog->tag, retcode)); + } else { + debug (1, (_("%s: unrecognized termination status"), + prog->tag)); /* Enforce default action: */ act = NULL; } @@ -1639,10 +1690,8 @@ progman_cleanup (int expect_term) break; case action_disable: - logmsg (LOG_NOTICE, - _("disabling component %s: " - "exited with code %d"), - prog->tag, status); + logmsg (LOG_NOTICE, _("disabling component %s"), + prog->tag); prog->v.p.status = status_disabled; } if (act->addr) -- cgit v1.2.1