diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-06-14 21:44:53 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-06-14 21:44:53 +0300 |
commit | ca5ea14d5f324349b6b2ffdd56721d80d5134ad0 (patch) | |
tree | a2b2adb4e465f8853dbbd763fd21f6031bd270c2 /pies | |
parent | bb86001cb89791d23fc2c728b7253182ec6149fe (diff) | |
download | pies-ca5ea14d5f324349b6b2ffdd56721d80d5134ad0.tar.gz pies-ca5ea14d5f324349b6b2ffdd56721d80d5134ad0.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.
Diffstat (limited to 'pies')
-rw-r--r-- | pies/pies.c | 156 | ||||
-rw-r--r-- | pies/pies.h | 12 | ||||
-rw-r--r-- | pies/progman.c | 109 |
3 files changed, 231 insertions, 46 deletions
diff --git a/pies/pies.c b/pies/pies.c index de46cac..8948bce 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 5659749..69683dd 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 31820f7..50db913 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); } } } |