aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-06-14 21:44:53 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-06-14 21:44:53 +0300
commit923d8c2d2a728d40c46bdc4b381308bf0b50048d (patch)
tree26440749d8b87ad98276f67a259c260240997afd
parenta3de6c9ab6a862ede6235b4d34dbf9386627c4d4 (diff)
downloadmailfromd-923d8c2d2a728d40c46bdc4b381308bf0b50048d.tar.gz
mailfromd-923d8c2d2a728d40c46bdc4b381308bf0b50048d.tar.bz2
Fix and improve termination actions in pies.
* pies/pies.h (MAX_RETURN_CODE): Remove. (STATUS_SIG_BIT, STATUS_CODE): New defines (struct action): New fields next, nstat, status, command. (struct component): Keep singly-linked list of termination actions. * pies/progman.c (run_command): New function. (progman_cleanup): Redo iteration over termination actions. * pies/pies.c (return_code_cfg_param): Pass offsets in struct component. (create_action): Accept signal numbers (SIG.* or SIG\+[0-9]+) in tag. (return_code_section_parser): Update. (pies_check_status): Set *pid before returning pies_status_stale. * doc/pies.texi: Document changes. * NEWS: Updated.
-rw-r--r--NEWS26
-rw-r--r--doc/pies.texi47
-rw-r--r--pies/pies.c156
-rw-r--r--pies/pies.h12
-rw-r--r--pies/progman.c109
5 files changed, 299 insertions, 51 deletions
diff --git a/NEWS b/NEWS
index 4a5a3ab0..34a02f68 100644
--- a/NEWS
+++ b/NEWS
@@ -108,6 +108,32 @@ The sockmap.mf module provides functions for interfacing with MeTA1
- string sockmap_lookup(number FD, string MAP, string ARG)
- string sockmap_single_lookup(string URL, string MAP, string ARG)
+* pies
+
+Signals can be specified in tag list of `return-code' statement.
+A signal is given either by its name, or as SIG+n, where n is
+its number. Valid signal names are: SIGHUP, SIGINT, SIGQUIT, SIGILL,
+SIGTRAP, SIGABRT, SIGIOT, SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV,
+SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD, SIGCONT,
+SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ,
+SIGVTALRM, SIGPROF, SIGWINCH, SIGPOLL, SIGIO, SIGPWR, SIGSYS.
+
+Examples of usage:
+
+ return-code (SIGABRT, EX_USAGE) {
+ ...
+ }
+
+ return-code SIG+6, EX_USAGE {
+ ...
+ }
+
+New action is allowed in `return-code' block:
+
+ exec COMMAND;
+
+It executes the given COMMAND before other actions.
+
* Debugging
New function mailutils_set_debug_level allows to set global Mailutils
diff --git a/doc/pies.texi b/doc/pies.texi
index 1d9df839..7f020f11 100644
--- a/doc/pies.texi
+++ b/doc/pies.texi
@@ -379,8 +379,9 @@ return-code @var{codes} @{
@}
@end smallexample
- Its argument is a list of exit codes. Exit codes can be specified
-as decimal numbers, or as symbolic code names from the table below:
+ The @var{codes} argument is a list of exit codes or signal names.
+Exit codes can be specified either as decimal numbers or as symbolic code
+names from the table below:
@multitable @columnfractions 0.5 0.3
@headitem Name @tab Numeric value
@@ -402,9 +403,45 @@ as decimal numbers, or as symbolic code names from the table below:
@item EX_CONFIG @tab 78
@end multitable
- If the component exits with an exit code listed in @var{codes},
-@command{pies} executes actions specified by its substatements. These
-are:
+Signal codes can be given either as @samp{SIG+@var{n}}, where @var{n}
+is the signal number, or as signal names from the following list:
+@samp{SIGHUP}, @samp{SIGINT}, @samp{SIGQUIT}, @samp{SIGILL},
+@samp{SIGTRAP}, @samp{SIGABRT}, @samp{SIGIOT}, @samp{SIGBUS},
+@samp{SIGFPE}, @samp{SIGKILL}, @samp{SIGUSR1}, @samp{SIGSEGV},
+@samp{SIGUSR2}, @samp{SIGPIPE}, @samp{SIGALRM}, @samp{SIGTERM},
+@samp{SIGSTKFLT}, @samp{SIGCHLD}, @samp{SIGCONT}, @samp{SIGSTOP},
+@samp{SIGTSTP}, @samp{SIGTTIN}, @samp{SIGTTOU}, @samp{SIGURG},
+@samp{SIGXCPU}, @samp{SIGXFSZ}, @samp{SIGVTALRM}, @samp{SIGPROF},
+@samp{SIGWINCH}, @samp{SIGPOLL}, @samp{SIGIO}, @samp{SIGPWR},
+@samp{SIGSYS}.
+
+ If the component exits with an exit code listed in @var{codes}
+or is terminated on a signal listed in @var{codes},
+@command{pies} executes actions specified by its substatements.
+They are executed in the order of their appearance below:
+
+@deffn {Pies Conf} exec @var{command}
+Execute external command. Prior to execution of @var{command} all
+file descriptors are closed. It inherits the environment from the
+main @command{pies} process with the following additional variables:
+
+@table @env
+@item PIES_VERSION
+The @command{pies} version number (@value{VERSION}).
+
+@item PIES_COMPONENT
+Tag of the terminated component (@pxref{Component Statement, tag}).
+
+@item PIES_PID
+PID of the terminated component.
+
+@item PIES_SIGNAL
+If the component terminated on signal, the number of that signal.
+
+@item PIES_STATUS
+Program exit code.
+@end table
+@end deffn
@deffn {Pies Conf} action @samp{disable | restart}
If @samp{restart} is given, restart the component. This is the
diff --git a/pies/pies.c b/pies/pies.c
index de46cac2..8948bcee 100644
--- a/pies/pies.c
+++ b/pies/pies.c
@@ -115,23 +115,26 @@ _cb_notify_addr (mu_debug_t debug, void *data, mu_config_value_t *arg)
struct mu_cfg_param return_code_cfg_param[] = {
{ "action", mu_cfg_callback, NULL,
- mu_offsetof (struct action, act), _cb_action,
+ mu_offsetof (struct component, act_temp.act), _cb_action,
N_("Specifies action to take when a component finishes with this "
"return code."),
/* TRANSLATORS: disable and restart are keywords, do not translate them. */
N_("arg: {disable | restart}") },
{ "notify", mu_cfg_callback, NULL,
- mu_offsetof (struct action, addr), _cb_notify_addr,
+ mu_offsetof (struct component, act_temp.addr), _cb_notify_addr,
N_("Notify this address when then component terminates."),
N_("arg: email-list") },
{ "message", mu_cfg_string, NULL,
- mu_offsetof (struct action, message), NULL,
+ mu_offsetof (struct component, act_temp.message), NULL,
N_("Notification message text (with headers).") },
+ { "exec", mu_cfg_string, NULL,
+ mu_offsetof (struct component, act_temp.command), NULL,
+ N_("Execute this command.") },
{ NULL }
};
-static struct mu_kwd ex_kwtab[] = {
#define S(s) { #s, s }
+static struct mu_kwd ex_kwtab[] = {
S (EX_OK),
S (EX_USAGE),
S (EX_DATAERR),
@@ -151,13 +154,73 @@ static struct mu_kwd ex_kwtab[] = {
{ NULL }
};
+static struct mu_kwd sig_kwtab[] = {
+ S (SIGHUP),
+ S (SIGINT),
+ S (SIGQUIT),
+ S (SIGILL),
+ S (SIGTRAP),
+ S (SIGABRT),
+ S (SIGIOT),
+ S (SIGBUS),
+ S (SIGFPE),
+ S (SIGKILL),
+ S (SIGUSR1),
+ S (SIGSEGV),
+ S (SIGUSR2),
+ S (SIGPIPE),
+ S (SIGALRM),
+ S (SIGTERM),
+#ifdef SIGSTKFLT
+ S (SIGSTKFLT),
+#endif
+ S (SIGCHLD),
+ S (SIGCONT),
+ S (SIGSTOP),
+ S (SIGTSTP),
+ S (SIGTTIN),
+ S (SIGTTOU),
+#ifdef SIGURG
+ S (SIGURG),
+#endif
+#ifdef SIGXCPU
+ S (SIGXCPU),
+#endif
+#ifdef SIGXFSZ
+ S (SIGXFSZ),
+#endif
+#ifdef SIGVTALRM
+ S (SIGVTALRM),
+#endif
+#ifdef SIGPROF
+ S (SIGPROF),
+#endif
+#ifdef SIGWINCH
+ S (SIGWINCH),
+#endif
+#ifdef SIGPOLL
+ S (SIGPOLL),
+#endif
+#ifdef SIGIO
+ S (SIGIO),
+#endif
+#ifdef SIGPWR
+ S (SIGPWR),
+#endif
+#ifdef SIGSYS
+ S (SIGSYS),
+#endif
+ { NULL }
+};
+#undef S
+
static struct action *
create_action(struct component *comp,
mu_debug_t debug, mu_config_value_t *val, int argc,
const char *(*getarg) (mu_config_value_t *, int, mu_debug_t))
{
int i;
- int *retv;
+ unsigned *retv;
int retc = 0;
int allflag = 0;
struct action *act;
@@ -169,8 +232,9 @@ create_action(struct component *comp,
{
for (i = 0; i < argc; i++)
{
- int n;
+ unsigned n;
const char *arg = getarg(val, i, debug);
+ size_t len = strlen (arg);
if (isdigit (arg[0]))
{
@@ -183,6 +247,27 @@ create_action(struct component *comp,
continue;
}
}
+ else if (len > 3 && memcmp (arg, "SIG", 3) == 0)
+ {
+ if (arg[4] == '+')
+ {
+ char *p;
+ n = strtoul (arg + 4, &p, 0);
+ if (*p)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("%s: not a number"), p);
+ continue;
+ }
+ }
+ else if (mu_kwd_xlat_name_ci (sig_kwtab, arg, &n))
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("%s: not a signal code"), arg);
+ continue;
+ }
+ n |= STATUS_SIG_BIT;
+ }
else if (mu_kwd_xlat_name_ci (ex_kwtab, arg, &n))
{
mu_cfg_format_error (debug, MU_DEBUG_ERROR,
@@ -190,14 +275,8 @@ create_action(struct component *comp,
continue;
}
- if (n > MAX_RETURN_CODE)
- mu_cfg_format_error (debug, MU_DEBUG_ERROR,
- _("%s: invalid return code"), arg);
- else
- {
- /* Alles in ordnung */
- retv[retc++] = n;
- }
+ /* Alles in ordnung */
+ retv[retc++] = n;
}
}
@@ -208,16 +287,16 @@ create_action(struct component *comp,
}
act = xzalloc (sizeof *act);
- if (allflag)
+ if (!allflag)
{
- for (i = 0; i <= MAX_RETURN_CODE; i++)
- if (comp->act[i] == NULL)
- comp->act[i] = act;
+ act->nstat = retc;
+ act->status = retv;
}
+ if (comp->act_tail)
+ comp->act_tail->next = act;
else
- for (i = 0; i < retc; i++)
- comp->act[retv[i]] = act;
- free (retv);
+ comp->act_head = act;
+ comp->act_tail = act;
return act;
}
@@ -267,6 +346,12 @@ return_code_section_parser (enum mu_cfg_section_stage stage,
struct component *comp = *section_data;
size_t count;
struct action *act;
+
+ if (!node->label)
+ {
+ mu_cfg_format_error (tree->debug, MU_DEBUG_ERROR, _("missing tag"));
+ return 1;
+ }
switch (stage)
{
@@ -274,30 +359,35 @@ return_code_section_parser (enum mu_cfg_section_stage stage,
switch (node->label->type)
{
case MU_CFG_STRING:
- act = create_action(comp, tree->debug, node->label,
- 1,
- _get_string_arg);
+ act = create_action (comp, tree->debug, node->label,
+ 1,
+ _get_string_arg);
break;
case MU_CFG_ARRAY:
- act = create_action(comp, tree->debug, node->label,
- node->label->v.arg.c,
- _get_array_arg);
+ act = create_action (comp, tree->debug, node->label,
+ node->label->v.arg.c,
+ _get_array_arg);
break;
case MU_CFG_LIST:
mu_list_count (node->label->v.list, &count);
- act = create_action(comp, tree->debug, node->label,
- count,
- _get_list_arg);
+ act = create_action (comp, tree->debug, node->label,
+ count,
+ _get_list_arg);
}
if (!act)
return 1;
- *section_data = act;
+ memset (&comp->act_temp, 0, sizeof (comp->act_temp));
break;
case mu_cfg_section_end:
+ act = comp->act_tail;
+ act->act = comp->act_temp.act;
+ act->addr = comp->act_temp.addr;
+ act->message = comp->act_temp.message;
+ act->command = comp->act_temp.command;
break;
}
return 0;
@@ -1151,11 +1241,11 @@ pies_check_status (pid_t *ppid)
if (pid == -1)
return pies_status_ctr;
+ *ppid = pid;
+
if (kill (pid, SIGUSR2))
return pies_status_stale;
- *ppid = pid;
-
for (i = 0; i < 4 && (rc = access (statfile, R_OK)); i++)
sleep (1);
diff --git a/pies/pies.h b/pies/pies.h
index 56597495..69683dd9 100644
--- a/pies/pies.h
+++ b/pies/pies.h
@@ -73,19 +73,24 @@ struct redirector
typedef struct limits_rec *limits_record_t;
-#define MAX_RETURN_CODE 127
-
enum return_action
{
action_restart,
action_disable,
};
+#define STATUS_SIG_BIT 0x80000000
+#define STATUS_CODE(c) ((c) & ~STATUS_SIG_BIT)
+
struct action
{
+ struct action *next;
+ size_t nstat;
+ unsigned *status;
enum return_action act; /* Action to take when the component terminates */
mu_address_t addr; /* Addresses to notify about it. */
char *message; /* Notification mail. */
+ char *command; /* Execute this command */
};
enum pies_comp_mode
@@ -136,7 +141,8 @@ struct component
int facility; /* Syslog facility. */
struct redirector redir[2]; /* Repeaters for stdout and stderr */
/* Actions to execute on various exit codes: */
- struct action *act[MAX_RETURN_CODE+1];
+ struct action *act_head, *act_tail;
+ struct action act_temp; /* Auxiliary object used during configuration */
};
extern char *syslog_tag;
diff --git a/pies/progman.c b/pies/progman.c
index 31820f7b..50db9137 100644
--- a/pies/progman.c
+++ b/pies/progman.c
@@ -243,9 +243,6 @@ register_prog0 (struct component *comp, int index)
newp->v.p.status = status_disabled;
else if (comp->mode == pies_comp_inetd)
newp->v.p.status = status_listener;
- for (i = 0; i <= MAX_RETURN_CODE; i++)
- if (!comp->act[i])
- comp->act[i] = default_component.act[i];
if (comp->mode != pies_comp_exec)
comp->redir[RETR_OUT].type = redir_null;
@@ -1461,6 +1458,78 @@ notify (const char *tag, int status, struct action *act)
mu_message_destroy (&msg, mu_message_get_owner (msg));
}
+static int
+status_matches_p (struct action *act, unsigned status)
+{
+ int i;
+
+ if (act->nstat == 0)
+ return 1;
+ for (i = 0; i < act->nstat; i++)
+ if (act->status[i] == status)
+ return 1;
+ return 0;
+}
+
+static void
+run_command (struct action *act, struct prog *prog, unsigned retcode,
+ pid_t child_pid)
+{
+ pid_t pid;
+ char *argv[4];
+ char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+ static RETSIGTYPE (*saved_handler) (int sig);
+ int status;
+
+ saved_handler = signal (SIGPIPE, SIG_IGN);
+
+ pid = fork ();
+
+ if (pid == (pid_t) -1)
+ {
+ mu_error ("fork: %s", mu_strerror (errno));
+ return;
+ }
+
+ if (pid == 0)
+ {
+ int i;
+
+ MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1,
+ _("executing %s\n"), act->command);
+ /* Child */
+ setenv ("PIES_VERSION", PACKAGE_VERSION, 1);
+ setenv ("PIES_COMPONENT", prog->tag, 1);
+ setenv ("PIES_PID", umaxtostr (child_pid, buf), 1);
+ if (retcode & STATUS_SIG_BIT)
+ setenv ("PIES_SIGNAL", umaxtostr (STATUS_CODE (retcode), buf), 1);
+ else
+ setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1);
+
+ for (i = getmaxfd (); i >= 0; i--)
+ close (i);
+
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = act->command;
+ argv[3] = NULL;
+
+ execv (argv[0], argv);
+ exit (127);
+ }
+
+ /* Master */
+ while (waitpid (pid, &status, 0) == -1)
+ if (errno != EINTR)
+ {
+ mu_error ("waitpid: %s", mu_strerror (errno));
+ break;
+ }
+ signal (SIGPIPE, saved_handler);
+
+ print_status (act->command, pid, status, 1);
+}
+
void
progman_cleanup (int expect_term)
{
@@ -1491,13 +1560,31 @@ progman_cleanup (int expect_term)
prog_stop_dependents (prog);
if (!expect_term)
{
+ unsigned retcode;
+ struct action *act = prog->v.p.comp->act_head;
+
+ if (!act)
+ act = default_component.act_head;
+
if (WIFEXITED (status))
+ retcode = WEXITSTATUS (status);
+ else if (WIFSIGNALED (status))
+ retcode = STATUS_SIG_BIT | WTERMSIG (status);
+ else
{
- struct action *act;
- status = WEXITSTATUS (status);
- if (status <= MAX_RETURN_CODE
- && (act = prog->v.p.comp->act[status]))
+ /* Enforce default action: */
+ act = NULL;
+ }
+
+ for (; act; act = act->next)
+ {
+ if (status_matches_p (act, retcode))
{
+ if (act->command)
+ {
+ run_command (act, prog, retcode, pid);
+ }
+
switch (act->act)
{
case action_restart:
@@ -1513,11 +1600,13 @@ progman_cleanup (int expect_term)
}
if (act->addr)
notify (prog->tag, status, act);
- continue;
+ break;
}
}
- /* Default action: */
- prog_start (prog);
+
+ if (!act)
+ /* Default action: */
+ prog_start (prog);
}
}
}

Return to:

Send suggestions and report system problems to the System administrator.