diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-10-13 16:53:42 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-10-13 16:53:42 +0300 |
commit | c60e857d7f35128b077eac4a30a5900925bb38e8 (patch) | |
tree | c9bae66b94b2cfbd7b8869abf1b1dbe34bcf51e9 | |
parent | 8a4ba77068e5d7f6eab2cc1c1c10f31dcbccf7a6 (diff) | |
download | pies-c60e857d7f35128b077eac4a30a5900925bb38e8.tar.gz pies-c60e857d7f35128b077eac4a30a5900925bb38e8.tar.bz2 |
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.
-rw-r--r-- | README | 84 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | doc/pies.texi | 30 | ||||
-rw-r--r-- | src/pies.c | 46 | ||||
-rw-r--r-- | src/pies.h | 6 | ||||
-rw-r--r-- | src/progman.c | 121 |
6 files changed, 240 insertions, 49 deletions
@@ -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 <bug-pies@gnu.org.ua>. + + +* 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 @@ -12,13 +12,13 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Pies. If not, see <http://www.gnu.org/licenses/>. 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]) AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 std-options silent-rules]) # Enable silent rules by default: diff --git a/doc/pies.texi b/doc/pies.texi index 22c0f83..3f9ec4b 100644 --- a/doc/pies.texi +++ b/doc/pies.texi @@ -150,13 +150,14 @@ described above. This mode of operation is similar to that of @anchor{meta1-style} @cindex meta1-style components @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 is running, @command{pies} passes it the file descriptor of the socket, using a preconfigured @acronym{UNIX}-style socket. Further handling of the socket is the responsibility of the component itself. @@ -1207,32 +1208,41 @@ acl common @{ @} @end group @end smallexample @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 components defined there into the current component list. For example: 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: @smallexample allgroups yes; @@ -1708,13 +1718,13 @@ Display program version and license information and exit. @end table @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 it. The information needed is: @itemize @@ -33,12 +33,17 @@ char *ctlfile = STATEDIR "/pies.ctl"; char *statfile = STATEDIR "/pies.stat"; mode_t pies_umask = 0; 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 */ void log_setup (int want_stderr) { @@ -1161,12 +1166,24 @@ struct grecs_keyword pies_keywords[] = { {"meta1-queue-dir", NULL, N_("Set name of MeTA1 queue directory (default /var/spool/meta1)."), 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} }; void config_init () { @@ -1255,12 +1272,13 @@ static struct argp_option options[] = { static error_t parse_opt (int key, char *arg, struct argp_state *state) { switch (key) { case 't': + log_to_stderr = 1; lint_mode = 1; break; case 'E': preprocess_only = 1; break; @@ -1271,12 +1289,13 @@ parse_opt (int key, char *arg, struct argp_state *state) case OPT_CONFIG_HELP: config_help (); exit (0); case OPT_FOREGROUND: + log_to_stderr = 1; foreground = 1; break; case OPT_RELOAD: case OPT_STATUS: case OPT_STOP: @@ -1667,12 +1686,34 @@ void remove_pidfile (char *name) { if (unlink (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 symbol suitable for this locale */ "Copyright %s 2009 Sergey Poznyakoff"; @@ -1713,24 +1754,27 @@ main (int argc, char **argv) bindtextdomain ("mailfromd", LOCALEDIR); textdomain (PACKAGE); #endif 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)) exit (EX_USAGE); if (preprocess_only) exit (grecs_preproc_run (conffile, grecs_preprocessor) ? EX_CONFIG : 0); if (grecs_parse (conffile)) exit (EX_CONFIG); + set_mailer_argcv (); + if (lint_mode) { progman_build_depmap (); exit (0); } @@ -166,14 +166,18 @@ struct component extern int log_to_stderr; 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); void progman_start (void); void progman_wake_sleeping (void); void progman_stop (void); diff --git a/src/progman.c b/src/progman.c index 3211d9a..b85a797 100644 --- a/src/progman.c +++ b/src/progman.c @@ -160,12 +160,29 @@ unlink_prog (struct prog *pp) progtail = pp->prev; } 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; } static char * @@ -1347,72 +1364,83 @@ wait_for_child (pid_t pid) return rc; } 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)) { logmsg (LOG_ERR, _("cannot parse recipient address list (%s)"), rcpts); 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)) arg++; 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 */ /* ============= */ signal (SIGCHLD, SIG_DFL); signal (SIGPIPE, SIG_DFL); @@ -1422,32 +1450,29 @@ send_msg (char *rcpts, const char *msg_text) logmsg (LOG_ERR, _("cannot send mail: pipe failed: %s"), strerror (errno)); wordsplit_free (&ws); 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 */ /* =========== */ if (p[0] != 0 && p[1] != 0) 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); } /* Child again */ close (p[0]); @@ -1463,13 +1488,13 @@ send_msg (char *rcpts, const char *msg_text) } size -= rc; msg_text += rc; } close (p[1]); - exit (wait_for_child (pid)); + exit (wait_for_child (grand_child_pid)); } static const char default_termination_message[] = "From: <>\n" "X-Agent: ${canonical-program-name} (${package} ${version})\n" "Subject: Component ${component} terminated with code ${retcode}.\n" @@ -1482,24 +1507,40 @@ notify (const char *tag, int status, struct action *act) { { "canonical-program-name", "pies" }, { "package", PACKAGE }, { "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 } }; char *msg_text = NULL; 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, mdef, NULL); send_msg (act->addr, msg_text); @@ -1611,17 +1652,27 @@ progman_cleanup (int expect_term) struct action *act = prog->v.p.comp->act_head; if (!act) 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; } for (; act; act = act->next) { @@ -1636,16 +1687,14 @@ progman_cleanup (int expect_term) { case action_restart: prog_start (prog); 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) notify (prog->tag, status, act); break; } |