aboutsummaryrefslogtreecommitdiff
path: root/src/progman.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/progman.c')
-rw-r--r--src/progman.c672
1 files changed, 389 insertions, 283 deletions
diff --git a/src/progman.c b/src/progman.c
index 2a073af..43f0a6b 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -1,5 +1,5 @@
/* This file is part of GNU Pies.
- Copyright (C) 2007-2020 Sergey Poznyakoff
+ Copyright (C) 2007-2023 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -94,15 +94,18 @@ prog_tag (struct prog const *prog)
case TYPE_COMPONENT:
return prog->v.p.comp->tag;
- case TYPE_REDIRECTOR:
- return prog->v.r.tag;
-
case TYPE_COMMAND:
return prog->v.c.tag;
}
abort ();
}
+int
+prog_sigterm (struct prog const *prog)
+{
+ return (prog && prog->type == TYPE_COMPONENT) ? prog->v.p.comp->sigterm : SIGTERM;
+}
+
void
link_prog (struct prog *prog, struct prog *ref)
{
@@ -147,6 +150,21 @@ unlink_prog (struct prog *pp)
progtail = pp->prev;
}
+static inline void
+prog_stop_redirectors (struct prog *p)
+{
+ if (p->v.p.redir[RETR_OUT] != -1)
+ {
+ deregister_socket (p->v.p.redir[RETR_OUT]);
+ p->v.p.redir[RETR_OUT] = -1;
+ }
+ if (p->v.p.redir[RETR_ERR] != -1)
+ {
+ deregister_socket (p->v.p.redir[RETR_ERR]);
+ p->v.p.redir[RETR_ERR] = -1;
+ }
+}
+
void
destroy_prog (struct prog **pp)
{
@@ -156,31 +174,14 @@ destroy_prog (struct prog **pp)
switch (p->type)
{
case TYPE_COMPONENT:
+ environ_free (p->v.p.env);
+ if (p->v.p.comp->flags & CF_EXPANDENV)
+ argv_free (p->v.p.argv);
component_ref_decr (p->v.p.comp);
if (p->v.p.status == status_listener && p->v.p.socket != -1)
deregister_socket (p->v.p.socket);
/* FIXME: Remove also all dependent progs (esp. tcpmux) */
- if (p->v.p.redir[RETR_OUT])
- p->v.p.redir[RETR_OUT]->v.r.master = NULL;
- if (p->v.p.redir[RETR_ERR])
- p->v.p.redir[RETR_ERR]->v.r.master = NULL;
- break;
-
- case TYPE_REDIRECTOR:
- {
- struct prog *master = p->v.r.master;
- component_ref_decr (p->v.r.comp);
- if (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);*/
- free (p->v.r.tag);
- }
+ prog_stop_redirectors (p);
break;
case TYPE_COMMAND:
@@ -191,50 +192,6 @@ destroy_prog (struct prog **pp)
*pp = NULL;
}
-static char *
-redir_tag (struct prog *master, int type)
-{
- static char *redirstr[2] = { "stdout", "stderr" };
- char *str = NULL;
- size_t len = 0;
- char const *tag = prog_tag (master);
- if (type < ARRAY_SIZE(redirstr))
- grecs_asprintf (&str, &len, "%s/%s", tag, redirstr[type]);
- else
- grecs_asprintf (&str, &len, "%s/%d", tag, type);
- return str;
-}
-
-static struct prog *
-register_redir (int type, struct prog *master)
-{
- char *tag = redir_tag (master, type);
- struct prog *pp = grecs_zalloc (sizeof (*pp));
-
- pp->type = TYPE_REDIRECTOR;
- pp->v.r.tag = tag;
- pp->v.r.master = master;
- pp->v.r.comp = master->v.p.comp;
- component_ref_incr (pp->v.r.comp);
- link_prog (pp, NULL);
- return pp;
-}
-
-void
-update_redir (int type, struct prog *master, pid_t pid)
-{
- struct prog *pp;
- if (master->v.p.redir[type])
- {
- pp = master->v.p.redir[type];
- prog_stop (pp, SIGKILL); /* Just in case */
- }
-
- pp = register_redir (type, master);
- master->v.p.redir[type] = pp;
- pp->pid = pid;
-}
-
/* Given the component COMP find the element of the program list
after which to link in the new prog associated with that COMP.
The progs in the resulting list must be arranged exactly in the
@@ -254,7 +211,7 @@ find_prog_ref (struct component *comp)
{
comp = comp->prev;
if (!comp)
- return NULL; /* FIXME: Skip redirectors? */
+ return NULL;
}
if (comp->prog)
@@ -361,12 +318,6 @@ progman_waiting_p (void)
return 0;
}
-RETSIGTYPE
-redir_exit (int sig)
-{
- _exit (0);
-}
-
int
redirect_to_file (struct prog *master, int stream)
{
@@ -400,20 +351,113 @@ redirect_to_file (struct prog *master, int stream)
}
return fd;
}
+
+struct read_buffer
+{
+ struct prog *master;
+ int stream;
+ char text[PIES_LOG_BUF_SIZE];
+ size_t len;
+ int overflow;
+};
-static void
-close_fds (fd_set *fdset)
+static int
+redirect_read (int fd, void *data)
{
- int i;
+ struct read_buffer *rb = data;
+ int n;
+ int prio = rb->master->v.p.comp->redir[rb->stream].v.prio;
+ char const *tag = prog_tag (rb->master);
+ pid_t pid = rb->master->pid;
+ char *p;
+ static char *retr_stream_name[] = {
+ [RETR_OUT] = "stdout",
+ [RETR_ERR] = "stderr"
+ };
- for (i = FD_SETSIZE-1; i >= 0; i--)
+ n = read (fd, rb->text + rb->len, sizeof (rb->text) - rb->len);
+ if (n == -1)
{
- if (fdset && FD_ISSET (i, fdset))
- continue;
- close (i);
+ if (errno != EINTR)
+ {
+ logmsg (LOG_INFO, _("%s: %s while reading %s"),
+ tag, strerror (errno), retr_stream_name[rb->stream]);
+ rb->master->v.p.redir[rb->stream] = -1;
+ close (fd);
+ deregister_socket (fd);
+ return -1;
+ }
+ }
+ else if (n == 0)
+ {
+ debug (3, (_("%s: EOF on %s"),
+ tag, retr_stream_name[rb->stream]));
+ rb->master->v.p.redir[rb->stream] = -1;
+ close (fd);
+ deregister_socket (fd);
}
+ else
+ {
+ rb->len += n;
+
+ while (rb->len)
+ {
+ p = memchr (rb->text, '\n', rb->len);
+ if (p)
+ {
+ *p++ = 0;
+ if (rb->overflow)
+ rb->overflow = 0;
+ else
+ pies_syslog_message (prio, rb->text, tag, pid);
+ n = rb->len - (p - rb->text);
+ if (n > 0)
+ memmove (rb->text, p, n);
+ rb->len = n;
+ }
+ else if (rb->len == sizeof (rb->text))
+ {
+ rb->text[sizeof (rb->text) - 1] = 0;
+ pies_syslog_message (prio, rb->text, tag, pid);
+ rb->len = 0;
+ rb->overflow = 1;
+ }
+ else
+ break;
+ }
+ }
+ return 0;
}
+static void
+read_buffer_free (void *p)
+{
+ free (p);
+}
+
+int
+redirect_to_syslog (struct prog *master, int stream, int *fd)
+{
+ struct read_buffer *rb;
+ int p[2];
+
+ if (pipe (p))
+ {
+ logmsg (LOG_CRIT, "pipe: %s", strerror (errno));
+ return -1;
+ }
+
+ rb = grecs_zalloc (sizeof (*rb));
+ rb->master = master;
+ rb->stream = stream;
+ rb->len = 0;
+ rb->overflow = 0;
+
+ register_socket (p[0], redirect_read, NULL, NULL, rb, read_buffer_free);
+ *fd = p[0];
+ return p[1];
+}
+
void
free_redirector (struct redirector *rp)
{
@@ -422,73 +466,22 @@ free_redirector (struct redirector *rp)
}
int
-open_redirector (struct prog *master, int stream)
+open_redirector (struct prog *master, int stream, int *fd)
{
- int p[2];
- FILE *fp;
- char *buf = NULL;
- size_t size = 0;
- pid_t pid;
- int prio;
- char *tag;
- fd_set fdset;
-
switch (master->v.p.comp->redir[stream].type)
{
case redir_null:
- return -1;
-
+ *fd = -1;
+ break;
+
case redir_file:
+ *fd = -1;
return redirect_to_file (master, stream);
case redir_syslog:
- break;
- }
-
- if (pipe (p))
- {
- logmsg (LOG_CRIT, "pipe: %s", strerror (errno));
- return -1;
- }
-
- switch (pid = fork ())
- {
- case 0:
- /* Redirector process */
- tag = redir_tag (master, stream);
- mf_proctitle_format ("%s redirector", tag);
- free (tag);
-
- FD_ZERO (&fdset);
- FD_SET (p[0], &fdset);
- close_fds (&fdset);
-
- diag_setup (0);
- signal_setup (redir_exit);
-
- close (p[1]);
- fp = fdopen (p[0], "r");
- if (fp == NULL)
- _exit (1);
- openlog (prog_tag (master), LOG_PID, master->v.p.comp->facility);
- prio = master->v.p.comp->redir[stream].v.prio;
- while (getline (&buf, &size, fp) > 0)
- syslog (prio, "%s", buf);
- _exit (0);
-
- case -1:
- logmsg (LOG_CRIT,
- _("cannot run redirector `%s': fork failed: %s"),
- prog_tag (master), strerror (errno));
- return -1;
-
- default:
- debug (1, (_("redirector for %s started, pid=%lu"),
- prog_tag (master), (unsigned long) pid));
- update_redir (stream, master, pid);
- close (p[0]);
- return p[1];
+ return redirect_to_syslog (master, stream, fd);
}
+ return -1;
}
@@ -806,50 +799,110 @@ prog_open_socket (struct prog *prog)
}
static void
-prog_start_prologue (struct prog *prog)
+progman_ws_error (const char *fmt, ...)
{
- if (prog->v.p.comp->dir)
+ va_list ap;
+
+ va_start (ap, fmt);
+ vlogmsg (LOG_ERR, fmt, ap);
+ va_end (ap);
+}
+
+/*
+ * Initialization of the environment and argc/argv members of
+ * struct prog. For regular components this is done in the main
+ * process, so that argv can be reported correctly via the ctl
+ * interface. For tcpmux components, which are run from the
+ * listener child, this is not so. That does little harm as
+ * these components are not visible from the ctl interface anyway.
+ */
+static int
+prog_init (struct prog *prog)
+{
+ if ((prog->v.p.env = environ_create (environ)) == NULL)
{
- debug (1, (_("chdir %s"), prog->v.p.comp->dir));
- if (chdir (prog->v.p.comp->dir))
- logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"),
- prog_tag (prog), prog->v.p.comp->dir, strerror (errno));
+ logmsg (LOG_CRIT, "environ_create: %s", strerror (errno));
+ return -1;
}
-
- prog->v.p.env = environ_create (environ);
+
if (prog->v.p.comp->flags & CF_SOCKENV)
{
size_t i;
for (i = 0; sockenv_var[i]; i++)
environ_unset (prog->v.p.env, sockenv_var[i], NULL);
}
- envop_exec (prog->v.p.comp->envop, prog->v.p.env);
+
+ if (envop_exec (prog->v.p.comp->envop, prog->v.p.env))
+ {
+ logmsg (LOG_CRIT, "environ_exec: %s", strerror (errno));
+ return -1;
+ }
+
if (SYSVINIT_ACTIVE)
{
size_t i;
for (i = 0; sysvinit_environ_hint[i]; i++)
- environ_add (prog->v.p.env, sysvinit_environ_hint[i]);
+ {
+ if (environ_add (prog->v.p.env, sysvinit_environ_hint[i]))
+ {
+ logmsg (LOG_CRIT, "environ_add: %s", strerror (errno));
+ return -1;
+ }
+ }
}
- debug_environ (prog, 4);
+ debug_environ (prog, 4);
- pies_priv_setup (&prog->v.p.comp->privs);
- if (prog->v.p.comp->umask)
- umask (prog->v.p.comp->umask);
+ if (prog->v.p.comp->flags & CF_EXPANDENV)
+ {
+ struct wordsplit ws;
- set_limits (prog_tag (prog),
- prog->v.p.comp->limits ?
- prog->v.p.comp->limits : pies_limits);
+ ws.ws_env = (const char **) environ_ptr (prog->v.p.env);
+ ws.ws_error = progman_ws_error;
+ if (wordsplit (prog->v.p.comp->command, &ws,
+ WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_NOCMD | WRDSF_ENV | WRDSF_ERROR))
+ {
+ logmsg (LOG_ERR, _("%s: can't split command line: %s"),
+ prog_tag (prog), wordsplit_strerror (&ws));
+ return -1;
+ }
+ wordsplit_get_words (&ws, &prog->v.p.argc, &prog->v.p.argv);
+ wordsplit_free (&ws);
+ }
+ else
+ {
+ prog->v.p.argc = prog->v.p.comp->argc;
+ prog->v.p.argv = prog->v.p.comp->argv;
+ }
- if (debug_level >= 1)
+ if (debug_level >= 1 && prog->v.p.argv)
{
int i;
- struct component *comp = prog->v.p.comp;
-
logmsg_printf (LOG_DEBUG, "executing");
- for (i = 0; i < comp->argc; i++)
- logmsg_printf (LOG_DEBUG, " %s", quotearg (comp->argv[i]));
+ for (i = 0; i < prog->v.p.argc; i++)
+ logmsg_printf (LOG_DEBUG, " %s", quotearg (prog->v.p.argv[i]));
logmsg_printf (LOG_DEBUG, "\n");
}
+ return 0;
+}
+
+static void
+prog_start_prologue (struct prog *prog)
+{
+ if (prog->v.p.comp->dir)
+ {
+ debug (1, (_("chdir %s"), prog->v.p.comp->dir));
+ if (chdir (prog->v.p.comp->dir))
+ logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"),
+ prog_tag (prog), prog->v.p.comp->dir, strerror (errno));
+ }
+
+ pies_priv_setup (&prog->v.p.comp->privs);
+ if (prog->v.p.comp->umask)
+ umask (prog->v.p.comp->umask);
+
+ set_limits (prog_tag (prog),
+ prog->v.p.comp->limits ?
+ prog->v.p.comp->limits : pies_limits);
}
static void
@@ -865,14 +918,18 @@ prog_execute (struct prog *prog)
}
execvp (prog->v.p.comp->program ?
- prog->v.p.comp->program : prog->v.p.comp->argv[0],
- prog->v.p.comp->argv);
- openlog (log_tag, LOG_PID, prog->v.p.comp->facility);
+ prog->v.p.comp->program : prog->v.p.argv[0],
+ prog->v.p.argv);
+ //FIXME: pies_syslog?
syslog (LOG_CRIT, _("cannot start `%s': %s"), prog_tag (prog),
strerror (errno));
_exit (EX_SOFTWARE);
}
+/*
+ * Run a TCPMUX component. This function is invoked from a child
+ * process.
+ */
void
progman_run_comp (struct component *comp, int fd,
union pies_sockaddr_storage *sa, socklen_t salen)
@@ -882,6 +939,8 @@ progman_run_comp (struct component *comp, int fd,
prog->v.p.sa_storage = *sa;
prog->v.p.sa_len = salen;
prog->v.p.cclass = conn_class_lookup (comp->tag, sa, salen);
+ if (prog_init (prog))
+ _exit (127);
prog_start_prologue (prog);
prog_sockenv (prog);
prog_execute (prog);
@@ -892,7 +951,6 @@ prog_start (struct prog *prog)
{
pid_t pid;
int redir[2];
- fd_set fdset;
if (prog->pid > 0 || !IS_COMPONENT (prog))
return;
@@ -972,8 +1030,13 @@ prog_start (struct prog *prog)
return;
}
- redir[RETR_OUT] = open_redirector (prog, RETR_OUT);
- redir[RETR_ERR] = open_redirector (prog, RETR_ERR);
+ if (prog_init (prog))
+ return; //FIXME
+
+ redir[RETR_OUT] = open_redirector (prog, RETR_OUT,
+ &prog->v.p.redir[RETR_OUT]);
+ redir[RETR_ERR] = open_redirector (prog, RETR_ERR,
+ &prog->v.p.redir[RETR_ERR]);
switch (pid = fork ())
{
@@ -1054,13 +1117,8 @@ prog_start (struct prog *prog)
}
/* Close unneeded descripitors */
- FD_ZERO (&fdset);
- FD_SET (0, &fdset);
- FD_SET (1, &fdset);
- FD_SET (2, &fdset);
- if (prog->v.p.comp->mode == pies_comp_pass_fd)
- FD_SET (prog->v.p.socket, &fdset);
- close_fds (&fdset);
+ pies_close_fds ((prog->v.p.comp->mode == pies_comp_pass_fd
+ ? prog->v.p.socket : 2) + 1);
prog_execute (prog);
@@ -1092,7 +1150,7 @@ prog_start (struct prog *prog)
if (redir[RETR_OUT] != -1)
close (redir[RETR_OUT]);
- if (redir[RETR_ERR])
+ if (redir[RETR_ERR] != -1)
close (redir[RETR_ERR]);
prog->pid = pid;
prog->v.p.status = status_running;
@@ -1289,7 +1347,7 @@ prog_create_socket (struct prog *prog, void *data)
comp->privs.user, comp->umask);
if (fd == -1)
destroy_prog (&prog);
- else if (register_program_socket (comp->socket_type, fd, prog))
+ else if (register_program_socket (comp->socket_type, fd, prog, NULL))
{
close (fd);
destroy_prog (&prog);
@@ -1538,35 +1596,26 @@ prog_start_prerequisites (struct prog *prog)
}
void
-prog_stop_redirectors (struct prog *prog)
-{
- if (prog->v.p.redir[RETR_OUT])
- prog_stop (prog->v.p.redir[RETR_OUT], SIGTERM);
- if (prog->v.p.redir[RETR_ERR])
- prog_stop (prog->v.p.redir[RETR_ERR], SIGTERM);
-}
-
-void
prog_stop_dependents (struct prog *prog)
{
struct component *comp;
pies_depmap_pos_t pos;
int warned = 0;
- prog_stop_redirectors (prog);
for (comp = component_depmap_first (depmap_row, prog->v.p.comp->arridx, &pos);
comp;
comp = component_depmap_next (pos))
{
struct prog *dp = comp->prog;
- if (!dp) /* should not happen */
- continue;
- if (!warned && dp->pid)
+ if (dp)
{
- debug (1, ("stopping dependencies of %s", prog_tag (prog)));
- warned = 1;
+ if (!warned && dp->pid)
+ {
+ debug (1, ("stopping dependencies of %s", prog_tag (prog)));
+ warned = 1;
+ }
+ prog_stop (dp, prog_sigterm (dp));
}
- prog_stop (dp, SIGTERM);
}
depmap_end (pos);
}
@@ -1585,7 +1634,7 @@ prog_stop (struct prog *prog, int sig)
pies_schedule_children (PIES_CHLD_RESCHEDULE_ALARM);
}
}
- debug (1, ("stopping %s (%lu)", prog_tag (prog), (unsigned long) prog->pid));
+ debug (1, ("sending signal %d to %s (%lu)", sig, prog_tag (prog), (unsigned long) prog->pid));
if (prog->type == TYPE_COMPONENT && prog->v.p.comp->flags & CF_SIGGROUP)
kill (-prog->pid, sig);
else
@@ -1620,7 +1669,7 @@ print_status (const char *tag, pid_t pid, int status, int expect_term)
{
char const *coremsg = "";
- if (expect_term && WTERMSIG (status) == SIGTERM)
+ if (expect_term && WTERMSIG (status) == expect_term)
prio = LOG_DEBUG;
#ifdef WCOREDUMP
@@ -1961,14 +2010,33 @@ notify (const char *tag, int status, struct action *act)
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;
+ int result;
+
+ if (act->cond_list == NULL)
+ result = 1;
+ else
+ {
+ struct grecs_list_entry *ep;
+
+ for (ep = act->cond_list->head; ep; ep = ep->next)
+ {
+ struct status_cond *cp = ep->data;
+ result = cp->status == status;
+ if (cp->neg)
+ {
+ if ((status & STATUS_SIG_BIT) == (cp->status & STATUS_SIG_BIT))
+ {
+ result = !result;
+ if (!result)
+ break;
+ }
+ }
+ else if (result)
+ break;
+ }
+ }
+
+ return result;
}
static void
@@ -2004,7 +2072,7 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
else
setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1);
- close_fds (NULL);
+ pies_close_fds (3);
argv[0] = "/bin/sh";
argv[1] = "-c";
@@ -2091,26 +2159,27 @@ react (struct prog *prog, int status, pid_t pid)
}
void
-progman_cleanup (int expect_term)
+progman_cleanup (int flags)
{
pid_t pid;
int status;
+ int expect_term = (flags & CLEANUP_EXPECT_TERM) || progman_waiting_p ();
- if (!expect_term)
- expect_term = progman_waiting_p ();
while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
{
struct prog *prog = prog_lookup_by_pid (pid);
if (!prog)
{
- print_status (_("unknown child"), pid, status, expect_term);
+ print_status (_("unknown child"), pid, status,
+ expect_term ? SIGTERM : 0);
continue;
}
prog->pid = 0;
switch (prog->type)
{
case TYPE_COMPONENT:
- print_status (prog_tag (prog), pid, status, expect_term);
+ print_status (prog_tag (prog), pid, status,
+ expect_term ? prog_sigterm (prog) : 0);
prog->stop = 0;
if (prog->v.p.comp->mode == pies_comp_inetd)
{
@@ -2171,8 +2240,9 @@ progman_cleanup (int expect_term)
prog_tag (prog), pid, "");
prog->v.p.status = status_stopped;
+ prog_stop_redirectors (prog);
prog_stop_dependents (prog);
- if (!expect_term)
+ if (!expect_term && component_is_active (prog->v.p.comp))
react (prog, status, pid);
}
@@ -2182,19 +2252,9 @@ progman_cleanup (int expect_term)
break;
- case TYPE_REDIRECTOR:
- /* It was a redirector of an already finished process. */
- print_status (prog_tag (prog), pid, status,
- expect_term ||
- (prog->v.r.master &&
- prog->v.r.master->v.p.status == status_stopping));
- debug (1, (_("removing redirector %s, pid=%lu"),
- prog_tag (prog), (unsigned long)pid));
- destroy_prog (&prog);
- break;
-
case TYPE_COMMAND:
- print_status (prog_tag (prog), pid, status, expect_term);
+ print_status (prog_tag (prog), pid, status,
+ expect_term ? prog_sigterm (prog) : 0);
destroy_prog (&prog);
break;
}
@@ -2215,7 +2275,7 @@ progman_stop_component (struct prog **progptr)
{
case status_running:
logmsg (LOG_INFO, _("stopping component %s"), prog_tag (prog));
- prog_stop (prog, SIGTERM);
+ prog_stop (prog, prog_sigterm (prog));
break;
case status_listener:
@@ -2279,7 +2339,7 @@ prog_activate_listener (struct prog *prog)
comp->privs.user, comp->umask);
if (fd == -1)
return -1;
- else if (register_program_socket (comp->socket_type, fd, prog))
+ else if (register_program_socket (comp->socket_type, fd, prog, NULL))
{
close (fd);
return -1;
@@ -2308,7 +2368,7 @@ prog_to_stop (struct prog *prog)
void
progman_gc (void)
{
- time_t start;
+ struct timespec ts;
struct prog *prog, *next;
/* Find first marked prog */
@@ -2316,10 +2376,8 @@ progman_gc (void)
if (!prog)
return;
- /* First round: */
/* Gracefully stop it and all marked programs that follow */
diagmsg (DIAG_CON, LOG_INFO, "Sending processes the TERM signal");
- start = time (NULL);
do
{
next = prog->next;
@@ -2328,44 +2386,21 @@ progman_gc (void)
while ((prog = prog_to_stop (next)));
/* Wait for them to terminate */
- while (1)
- {
- progman_cleanup (1);
- prog = prog_to_stop (proghead);
- if (!prog)
- return;
- if (time (NULL) - start < shutdown_timeout)
- sleep (1);
- else
- break;
- }
+ clock_gettime (CLOCK_MONOTONIC, &ts);
+ ts.tv_sec += shutdown_timeout;
- /* Second round: */
- /* Kill the remaining programs with SIGKILL */
- diagmsg (DIAG_CON, LOG_INFO, "Sending processes the KILL signal");
- start = time (NULL);
do
{
- next = prog->next;
- prog_stop (prog, SIGKILL);
- }
- while ((prog = prog_to_stop (next)));
-
- /* Wait for them to terminate */
- while (1)
- {
progman_cleanup (1);
- prog = prog_to_stop (proghead);
- if (!prog)
+ if (!prog_to_stop (proghead))
return;
- if (time (NULL) - start < shutdown_timeout)
- sleep (1);
- else
- break;
}
-
- /* FIXME: Report remaining programs */
-
+ while (clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) != 0);
+
+ /* Kill the remaining programs with SIGKILL */
+ diagmsg (DIAG_CON, LOG_INFO, "Sending processes the KILL signal");
+ while ((prog = prog_to_stop (next)) != NULL)
+ prog_stop (prog, SIGKILL);
}
static int
@@ -2373,7 +2408,7 @@ start_shutdown (struct prog *prog, void *data)
{
if (IS_COMPONENT (prog) && prog->v.p.comp->mode == pies_comp_shutdown)
{
- int *p = data;
+ unsigned *p = data;
if (!*p)
{
diagmsg (DIAG_CON, LOG_INFO, "Starting shutdown components");
@@ -2386,41 +2421,112 @@ start_shutdown (struct prog *prog, void *data)
return 0;
}
-void
-program_shutdown (void)
+
+static void
+stop_progs_at_seqno (unsigned long seqno)
{
- time_t start = time (NULL);
- int sd = 0;
+ struct prog *prog;
+ size_t count = 0;
+ struct timespec ts;
+ int warned = 0;
- /* Activate shutdown components. */
- progman_foreach (start_shutdown, &sd);
+ /* Signal all programs that have this shutdown sequence number */
+ for (prog = proghead; prog; prog = prog->next)
+ {
+ if (IS_COMPONENT (prog) &&
+ prog->v.p.status == status_running &&
+ prog->v.p.comp->shutdown_seqno == seqno)
+ {
+ if (!warned)
+ {
+ debug (1, ("terminating processes at level %lu", seqno));
+ warned = 1;
+ }
+ prog->stop = 1;
+ prog_stop (prog, prog_sigterm (prog));
+ count++;
+ }
+ }
+
+ if (!count)
+ return;
+
+ debug (1, ("%zu processes signalled at level %lu", count, seqno));
+
+ clock_gettime (CLOCK_MONOTONIC, &ts);
+ ts.tv_sec += shutdown_timeout;
+
+ /* Wait for them to terminate */
while (prog_to_stop (proghead))
{
- progman_cleanup (1);
- if (time (NULL) - start < shutdown_timeout)
- sleep (1);
- else
+ if (clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) == 0)
{
- progman_gc ();
+ debug (1, ("killing %zu processes at level %lu", count, seqno));
+ for (prog = proghead; prog; prog = prog->next)
+ {
+ if (IS_COMPONENT (prog) &&
+ prog->v.p.comp->shutdown_seqno == seqno)
+ {
+ prog_stop (prog, SIGKILL);
+ }
+ }
break;
}
- }
-}
-static int
-mark_for_stopping (struct prog *prog, void *data)
-{
- if (IS_COMPONENT (prog))
- prog->stop = 1;
- return 0;
+ progman_cleanup (CLEANUP_EXPECT_TERM);
+ }
}
void
progman_stop (void)
{
- progman_foreach (mark_for_stopping, NULL);
- progman_gc ();
- program_shutdown ();
+ unsigned long *ordv;
+ size_t ordc;
+ size_t i;
+ int sd;
+
+ /*
+ * Stop all running components in correct order (dependents first).
+ */
+ ordc = components_shutdown_sequence_numbers (&ordv);
+
+ for (i = 0; i < ordc; i++)
+ {
+ stop_progs_at_seqno (ordv[i]);
+ }
+
+ /* Activate shutdown components. */
+ progman_foreach (start_shutdown, &sd);
+
+ /* Wait for them to finish. */
+ if (sd)
+ {
+ struct timespec ts;
+
+ clock_gettime (CLOCK_MONOTONIC, &ts);
+ ts.tv_sec += shutdown_timeout;
+
+ /* Wait for them to terminate */
+ while (prog_to_stop (proghead))
+ {
+ if (clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) == 0)
+ {
+ struct prog *prog;
+ debug (1, ("killing shutdown processes"));
+ for (prog = proghead; prog; prog = prog->next)
+ {
+ if (IS_COMPONENT (prog) &&
+ (prog->v.p.status == status_running
+ || prog->v.p.status == status_stopping))
+ {
+ prog_stop (prog, SIGKILL);
+ }
+ }
+ break;
+ }
+ progman_cleanup (CLEANUP_EXPECT_TERM);
+ }
+ }
}
/* EOF */

Return to:

Send suggestions and report system problems to the System administrator.