summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-05-24 09:45:25 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-05-24 10:50:39 (GMT)
commit6dd0ec08db301984b8f8f9082f28006d5915c183 (patch) (side-by-side diff)
treee916ad37fbd3cbcaf85103667f28e0d47f3c2e45
parent2a646ee7cbbcb6f4bbd8f38bb3c1e1418550f3fc (diff)
downloadpies-6dd0ec08db301984b8f8f9082f28006d5915c183.tar.gz
pies-6dd0ec08db301984b8f8f9082f28006d5915c183.tar.bz2
Initial implementation of "startup" components.
These are components that are run at program startup. Starting other components is delayed until all startup components terminate. This is similar to SysV "bootwait" components. Upon termination, startup components are removed from the configuration. They are not renewed upon configuratuion reload. * src/comp.c (comp_array_remove): Remove from the depmap as well. (component_ref_decr): Use comp_array_remove for active components and plain component_free for inactive ones. (component_build_depmap): Use comp_array_remove. (component_config_commit): Special handling for pies_comp_startup components. * src/pies.c (modetab): New component modes: "startup" and "shutdown". (main): Run program_init_startup. * src/pies.h (pies_comp_mode): New modes: pies_comp_startup and pies_comp_shutdown. (program_init_startup): New proto. * src/progman.c (progman_waiting_p): Return 1 if a startup component is still running. (program_init_startup): New function. (progman_cleanup): Handle pies_comp_startup termination. * src/socket.c (switch_eids): Avoid unnecessary calls to setegid and seteuid. * tests/atlocal.in (auxdir): New variable. * tests/mailer: Move to tests/aux/ * tests/respawn: Move to tests/aux/ * tests/retcode: Move to tests/aux/ * tests/aux/startup: New auxiliary program. * tests/redirect.at: Start components from $auxdir. * tests/respawn.at: Likewise. * tests/ret-exec.at: Likewise. * tests/ret-notify.at: Likewise. * tests/startup.at: New file. * tests/testsuite.at: Include startup.at * tests/Makefile.am: Add new tests.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/comp.c87
-rw-r--r--src/pies.c115
-rw-r--r--src/pies.h38
-rw-r--r--src/progman.c291
-rw-r--r--src/socket.c54
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/atlocal.in2
-rwxr-xr-xtests/aux/mailer (renamed from tests/mailer)0
-rwxr-xr-xtests/aux/respawn (renamed from tests/respawn)0
-rwxr-xr-xtests/aux/retcode (renamed from tests/retcode)0
-rwxr-xr-xtests/aux/startup7
-rw-r--r--tests/redirect.at2
-rw-r--r--tests/respawn.at2
-rw-r--r--tests/ret-exec.at4
-rw-r--r--tests/ret-notify.at6
-rw-r--r--tests/startup.at84
-rw-r--r--tests/testsuite.at1
17 files changed, 442 insertions, 260 deletions
diff --git a/src/comp.c b/src/comp.c
index c3e998a..2346306 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -21,27 +21,32 @@
struct complist
{
struct component *head;
struct component *tail;
};
+/* 0 on the first load, and 1 on all subsequent reloads. Tells the
+ component_config_commit whether we're starting from scratch or just
+ updating an already loaded configuration */
+static int loaded;
+
static struct complist comp_list[2];
static int cur;
static struct component **comp_array;
static size_t comp_count;
static pies_depmap_t depmap;
-static int
+static inline int
next_index (void)
{
return (cur + 1) % ARRAY_SIZE (comp_list);
}
-static int
+static inline int
prev_index (void)
{
return (cur + ARRAY_SIZE (comp_list) - 1) % ARRAY_SIZE (comp_list);
}
void
@@ -82,12 +87,28 @@ void
component_append (struct component *comp)
{
component_link (comp, comp_list[comp->listidx].tail);
}
void
+comp_array_remove (size_t i)
+{
+ struct component *comp = comp_array[i];
+
+ depmap_remove (depmap, i);
+ while (i < comp_count -1)
+ {
+ comp_array[i] = comp_array[i+1];
+ comp_array[i]->arridx = i;
+ i++;
+ }
+ component_free (comp);
+ comp_count--;
+}
+
+void
component_unlink (struct component *comp)
{
struct complist *list = &comp_list[comp->listidx];
struct component *x;
if ((x = comp->prev))
@@ -198,13 +219,18 @@ component_ref_incr (struct component *comp)
void
component_ref_decr (struct component *comp)
{
assert (comp->ref_count > 0);
if (--comp->ref_count == 0)
- component_free (comp);
+ {
+ if (component_is_active (comp))
+ comp_array_remove (comp->arridx);
+ else
+ component_free (comp);
+ }
}
static int
argvcmp (char **a, char **b)
{
size_t i;
@@ -422,23 +448,12 @@ report_cyclic_dependency (pies_depmap_t dp, size_t idx)
}
while (i != idx);
logmsg_printf (LOG_NOTICE, "%s\n", comp_array[idx]->tag);
}
void
-comp_array_remove (size_t i)
-{
- struct component *comp = comp_array[i];
- if (i < comp_count - 1)
- memmove (&comp_array[i], &comp_array[i+1],
- (comp_count - i - 1) * sizeof comp_array[0]);
- component_free (comp);
- comp_count--;
-}
-
-void
component_build_depmap (void)
{
size_t i;
pies_depmap_t dp;
free (depmap);
@@ -457,13 +472,12 @@ component_build_depmap (void)
{
logmsg (LOG_ERR,
_("component %s depends on %s, "
"which is not declared"),
comp->tag, tag);
comp_array_remove (i);
- depmap_remove (depmap, i);
continue;
}
depmap_set (depmap, i, tgt);
}
if (comp->depend)
@@ -494,16 +508,13 @@ component_build_depmap (void)
report_cyclic_dependency (dp, i);
}
for (i = 0; i < comp_count;)
if (comp_array[i]->flags & CF_REMOVE)
- {
- comp_array_remove (i);
- depmap_remove (depmap, i);
- }
+ comp_array_remove (i);
else
i++;
free (dp);
}
@@ -525,28 +536,42 @@ component_config_commit (void)
comp_array = NULL;
}
else
comp_array = grecs_realloc (comp_array, i * sizeof (comp_array[0]));
comp_count = i;
- /* Rearrange components, registering prog entries for the new ones */
- for (comp = list->head, i = 0; comp; comp = comp->next, i++)
+ /* Rearrange components, registering entries for the new ones */
+ for (comp = list->head, i = 0; comp; )
{
- match = complist_find_match (prev, comp);
- if (match)
+ struct component *next = comp->next;
+ if (loaded && comp->mode == pies_comp_startup)
{
- component_merge (match, comp);
- component_unlink (match);
- match->listidx = cur;
- component_link (match, comp->prev);
+ /* Ignore startup components */
+ component_unlink (comp);
component_free (comp);
- comp = match;
}
- comp_array[i] = comp;
- comp->arridx = i;
+ else
+ {
+ match = complist_find_match (prev, comp);
+ if (match)
+ {
+ component_merge (match, comp);
+ component_unlink (match);
+ match->listidx = cur;
+ component_link (match, comp->prev);
+ component_free (comp);
+ comp = match;
+ }
+ comp_array[i] = comp;
+ comp->arridx = i;
+ i++;
+ }
+ comp = next;
}
+ /* Adjust comp_count */
+ comp_count = i;
/* Mark orphaned progs for termination */
list = &comp_list[prev];
if (list->head)
{
progman_foreach (mark_prog, NULL);
@@ -557,12 +582,14 @@ component_config_commit (void)
component_build_depmap ();
/* Register new progs */
for (comp = comp_list[cur].head; comp; comp = comp->next)
if (!comp->prog)
register_prog (comp);
+
+ loaded = 1;
}
static int
component_verify (struct component *comp, grecs_locus_t *locus)
{
int header = 0;
diff --git a/src/pies.c b/src/pies.c
index 89c0b7e..98488a6 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -129,13 +129,13 @@ config_file_add_type (enum config_syntax_type syntax, const char *name)
}
int
config_file_remove (const char *name)
{
struct grecs_list_entry *ep;
-
+
for (ep = config_list->head; ep; ep = ep->next)
{
struct config_file *file = ep->data;
if (strcmp (file->name, name) == 0)
{
grecs_list_remove_entry (config_list, ep);
@@ -153,13 +153,13 @@ config_file_remove_all (void)
}
void
config_file_list_serialize (struct json_value *ar)
{
struct grecs_list_entry *ep;
-
+
for (ep = config_list->head; ep; ep = ep->next)
{
struct config_file *file = ep->data;
struct json_value *obj = json_new_object ();
json_object_set (obj, "syntax", json_new_string (file->syntax->name));
json_object_set (obj, "file", json_new_string (file->name));
@@ -324,13 +324,13 @@ action_free (struct action *act)
return;
if (act->nstat > 0)
free (act->status);
free (act->addr);
free (act->message);
free (act->command);
-
+
free (act);
}
static void
free_entry_action (void *act)
{
@@ -356,13 +356,13 @@ create_action (struct component *comp,
{
for (i = 0; i < argc; i++)
{
unsigned n;
const char *arg = getarg (val, i, locus);
size_t len = strlen (arg);
-
+
if (isdigit (arg[0]))
{
char *p;
n = strtoul (arg, &p, 0);
if (*p)
{
@@ -391,18 +391,18 @@ create_action (struct component *comp,
}
else if (strtotok_ci (ex_tokendef, arg, (int *) &n))
{
grecs_error (locus, 0, _("%s: not a return code"), arg);
continue;
}
-
+
/* Alles in ordnung */
retv[retc++] = n;
}
}
-
+
if (retc == 0 && !allflag)
{
free (retv);
return NULL;
}
@@ -469,33 +469,33 @@ return_code_section_parser (enum grecs_callback_command cmd,
case grecs_callback_section_begin:
if (GRECS_VALUE_EMPTY_P (value))
{
grecs_error (locus, 0, _("missing tag"));
return 1;
}
-
+
switch (value->type)
{
case GRECS_TYPE_STRING:
act = create_action (comp, locus, value, 1, _get_string_arg);
break;
-
+
case GRECS_TYPE_ARRAY:
act = create_action (comp, locus, value,
value->v.arg.c, _get_array_arg);
break;
-
+
case GRECS_TYPE_LIST:
count = grecs_list_size (value->v.list);
act = create_action (comp, locus, value, count, _get_list_arg);
}
if (!act)
return 1;
*(struct action **) cb_data = act;
break;
-
+
case grecs_callback_section_end:
break;
case grecs_callback_set_value:
grecs_error (locus, 0, _("invalid use of block statement"));
}
@@ -539,13 +539,13 @@ _cb_command (enum grecs_callback_command cmd,
grecs_error (locus, 0, "wordsplit: %s", strerror (errno));
return 1;
}
wordsplit_get_words (&ws, &comp->argc, &comp->argv);
wordsplit_free (&ws);
break;
-
+
case GRECS_TYPE_ARRAY:
comp->argv = config_array_to_argv (value, locus, &comp->argc);
break;
case GRECS_TYPE_LIST:
grecs_error (locus, 0, _("unexpected list"));
@@ -699,13 +699,13 @@ _cb_redir (enum grecs_callback_command cmd,
{"null", redir_null},
{"syslog", redir_syslog},
{"file", redir_file},
{NULL}
};
int res;
-
+
switch (value->type)
{
case GRECS_TYPE_STRING:
if (strcmp (value->v.string, "null") == 0)
{
rp->type = redir_null;
@@ -716,13 +716,13 @@ _cb_redir (enum grecs_callback_command cmd,
{
grecs_error (locus, 0, _("unknown syslog priority %s"),
value->v.string);
return 0;
}
break;
-
+
case GRECS_TYPE_ARRAY:
if (assert_grecs_value_type (locus, value->v.arg.v[0],
GRECS_TYPE_STRING))
return 0;
if (strtotok (redirtab, value->v.arg.v[0]->v.string, &res))
grecs_error (locus, 0, _("%s: unrecognised redirector type"),
@@ -736,48 +736,48 @@ _cb_redir (enum grecs_callback_command cmd,
grecs_error (locus, 0, _("wrong number of arguments"));
return 0;
}
if (assert_grecs_value_type (locus, value->v.arg.v[1],
GRECS_TYPE_STRING))
return 0;
-
+
switch (res)
{
case redir_null:
break;
-
+
case redir_syslog:
if (string_to_syslog_priority (value->v.arg.v[1]->v.string,
&rp->v.prio))
{
grecs_error (locus, 0,
_("unknown syslog priority %s"),
value->v.arg.v[1]->v.string);
return 0;
}
break;
-
+
case redir_file:
rp->v.file = grecs_strdup (value->v.arg.v[1]->v.string);
break;
}
}
rp->type = res;
}
break;
-
+
default:
grecs_error (locus, 0, _("unexpected list"));
}
-
+
return 0;
}
static struct tokendef socktype_xtab[] = {
- { "stream", SOCK_STREAM },
- { "dgram", SOCK_DGRAM },
+ { "stream", SOCK_STREAM },
+ { "dgram", SOCK_DGRAM },
{ "seqpacket", SOCK_SEQPACKET },
{ "raw", SOCK_RAW },
{ "rdm", SOCK_RDM },
#ifdef SOCK_PACKET
{ "packet", SOCK_PACKET },
#endif
@@ -817,18 +817,20 @@ static struct tokendef modetab[] = {
{"once", pies_comp_once},
{"accept", pies_comp_accept},
{"inetd", pies_comp_inetd},
{"nostartaccept", pies_comp_inetd},
{"pass-fd", pies_comp_pass_fd},
{"pass", pies_comp_pass_fd},
+ {"startup", pies_comp_startup},
+ {"shutdown", pies_comp_shutdown},
{"boot", pies_comp_boot},
{"bootwait", pies_comp_boot},
{"powerfail", pies_comp_powerfail},
{"powerwait", pies_comp_powerwait},
{"powerokwait", pies_comp_powerokwait},
- {"ctrlaltdel", pies_comp_ctrlaltdel},
+ {"ctrlaltdel", pies_comp_ctrlaltdel},
{"ondemand", pies_comp_ondemand},
{"sysinit", pies_comp_sysinit},
{"powerfailnow", pies_comp_powerfailnow},
{"kbrequest", pies_comp_kbrequest},
{NULL}
@@ -917,17 +919,17 @@ _cb_flags (enum grecs_callback_command cmd,
if (str_to_cf (value->v.string, flags))
{
grecs_error (locus, 0, _("%s: unrecognised flag"), value->v.string);
return 1;
}
break;
-
+
case GRECS_TYPE_LIST:
{
struct grecs_list_entry *ep;
-
+
for (ep = value->v.list->head; ep; ep = ep->next)
{
const grecs_value_t *vp = ep->data;
if (assert_grecs_value_type (locus, vp, GRECS_TYPE_STRING))
return 1;
if (str_to_cf (vp->v.string, flags))
@@ -936,13 +938,13 @@ _cb_flags (enum grecs_callback_command cmd,
vp->v.string);
return 1;
}
}
}
break;
-
+
case GRECS_TYPE_ARRAY:
grecs_error (locus, 0, _("too many arguments"));
return 1;
}
return 0;
}
@@ -1225,13 +1227,13 @@ struct grecs_keyword component_keywords[] = {
};
struct grecs_keyword *
find_component_keyword (const char *ident)
{
struct grecs_keyword *kwp;
-
+
for (kwp = component_keywords; kwp->ident; kwp++)
if (strcmp (kwp->ident, ident) == 0)
return kwp;
return NULL;
}
@@ -1253,13 +1255,13 @@ component_section_parser (enum grecs_callback_command cmd,
break;
case grecs_callback_section_end:
comp = *(struct component **) section_data;
component_finish (comp, locus);
break;
-
+
case grecs_callback_set_value:
grecs_error (locus, 0, _("expected block statement"));
}
return 0;
}
@@ -1531,13 +1533,13 @@ pies_config_parse (char const *name)
{
struct grecs_node *node;
struct grecs_node *tree = grecs_parse (name);
if (!tree)
return 1;
-
+
for (node = tree; node; node = node->next)
{
node = grecs_find_node (node, "identity-provider");
if (!node)
break;
pies_config_provider (node);
@@ -1547,13 +1549,13 @@ pies_config_parse (char const *name)
return 1;
grecs_tree_free (tree);
if (grecs_error_count)
return 1;
-
+
return 0;
}
void
config_help (void)
{
@@ -1570,26 +1572,26 @@ int
pies_read_config (void)
{
struct grecs_list_entry *ep;
int err = 0;
component_config_begin ();
-
+
for (ep = config_list->head; ep; ep = ep->next)
{
struct config_file *file = ep->data;
if (file->syntax->parser (file->name))
++err;
}
if (init_process)
err = 0;
-
+
if (err)
component_config_rollback ();
-
+
return err;
}
int
pies_reread_config (void)
{
@@ -1653,13 +1655,13 @@ sig_handler (int sig)
void
setsigvhan (RETSIGTYPE (*handler) (int signo), int *sigv, int sigc)
{
int i;
struct sigaction act;
-
+
act.sa_flags = 0;
sigemptyset (&act.sa_mask);
for (i = 0; i < sigc; i++)
sigaddset (&act.sa_mask, sigv[i]);
act.sa_handler = handler;
@@ -1776,13 +1778,13 @@ pies_check_status (pid_t *ppid)
int
request_restart_components (size_t cc, char **cv)
{
char **argv;
size_t i, j;
-
+
argv = grecs_calloc (5 + 3 * cc - 1, sizeof (*argv));
argv[0] = "piesctl";
argv[1] = "--url";
argv[2] = (char*) pies_control_url ();
argv[3] = "restart";
j = 4;
@@ -1800,13 +1802,13 @@ request_restart_components (size_t cc, char **cv)
}
void
list_components (void)
{
char *argv[5];
-
+
argv[0] = "piesctl";
argv[1] = "--url";
argv[2] = (char*) pies_control_url ();
argv[3] = "list";
argv[4] = NULL;
execvp (argv[0], argv);
@@ -1939,13 +1941,13 @@ remove_pidfile (char *name)
static void
set_mailer_argcv (void)
{
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);
}
@@ -2030,61 +2032,61 @@ main (int argc, char **argv)
{
pid_t pid;
extern char **environ;
struct grecs_list_entry *ep;
int diag_flags;
int i;
-
+
set_program_name (argv[0]);
#ifdef ENABLE_NLS
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
#endif
mf_proctitle_init (argc, argv, environ);
grecs_print_diag_fun = pies_diag_printer;
-
+
pies_master_argc = argc;
pies_master_argv = argv;
-
+
set_quoting_style (NULL, shell_quoting_style);
init_process = getpid () == 1;
for (i = 1; i < argc; i++)
{
if (strcmp (argv[i], "--no-init") == 0)
{
init_process = 0;
break;
}
}
-
+
/* Set default logging */
if (init_process)
{
log_facility = LOG_DAEMON;
diag_flags = DIAG_TO_STDERR | DIAG_REOPEN_LOG;
}
else
diag_flags = DIAG_TO_SYSLOG | (stderr_closed_p () ? 0 : DIAG_TO_STDERR);
-
+
diag_setup (diag_flags);
-
+
config_init ();
parse_options (&argc, &argv);
-
+
if (argc && !(command == COM_RESTART_COMPONENT
|| command == COM_TRACE_DEPEND
|| command == COM_TRACE_PREREQ))
{
logmsg (LOG_ERR, "extra command line arguments");
exit (EX_USAGE);
}
-
+
if (!instance)
{
instance = strrchr (program_name, '/');
if (!instance)
instance = (char*) program_name;
else
@@ -2116,39 +2118,39 @@ main (int argc, char **argv)
exit (EX_CONFIG);
component_config_commit ();
set_state_file_names (instance);
set_mailer_argcv ();
-
+
if (lint_mode)
exit (0);
/* Re-setup logging: it might have been reset in the config file */
diag_setup (log_to_stderr_only ? DIAG_TO_STDERR : 0);
-
+
if (!control.url)
{
char const *str = default_control_url[init_process];
if (pies_url_create (&control.url, str))
{
logmsg (LOG_CRIT, _("%s: cannot create control URL: %s"),
str, strerror (errno));
if (!init_process)
exit (EX_OSERR);
}
}
-
+
switch (command)
{
case COM_RESTART_COMPONENT:
pies_priv_setup (&pies_privs);
if (pies_umask)
umask (pies_umask);
exit (request_restart_components (argc, argv));
-
+
case COM_RELOAD:
exit (request_reload ());
case COM_STATUS:
exit (request_status ());
@@ -2159,17 +2161,17 @@ main (int argc, char **argv)
components_dump_depmap ();
exit (0);
case COM_TRACE_DEPEND:
components_trace (argv, depmap_row);
exit (0);
-
- case COM_TRACE_PREREQ:
+
+ case COM_TRACE_PREREQ:
components_trace (argv, depmap_col);
exit (0);
-
+
default:
pies_priv_setup (&pies_privs);
if (pies_umask)
umask (pies_umask);
}
@@ -2190,47 +2192,48 @@ main (int argc, char **argv)
logmsg (LOG_ERR,
_("another pies instance may be running (pid %lu), "
"use --force to override"), (unsigned long) pid);
exit (EX_USAGE);
}
break;
-
+
case pies_status_running:
logmsg (LOG_ERR, _("another pies instance already running (pid %lu)"),
(unsigned long) pid);
exit (EX_USAGE);
}
-
+
if (!foreground)
{
check_pidfile (pidfile);
if (daemon (0, 0) == -1)
{
logfuncall ("daemon", NULL, errno);
exit (EX_SOFTWARE);
}
diag_setup (DIAG_TO_SYSLOG);
}
logmsg (LOG_INFO, _("%s %s starting"), proginfo.package, proginfo.version);
-
+
if (!init_process)
{
if (ctl_open ())
exit (EX_UNAVAILABLE);
create_pidfile (pidfile);
}
-
+
if (pies_master_argv[0][0] != '/')
logmsg (LOG_NOTICE,
_("not started as an absolute pathname; "
"restart will not work"));
signal_setup (sig_handler);
progman_create_sockets ();
+ program_init_startup ();
progman_start ();
do
{
if (children_op == PIES_CHLD_NONE)
pies_pause ();
@@ -2258,13 +2261,13 @@ main (int argc, char **argv)
progman_create_sockets ();
progman_start ();
pies_schedule_children (PIES_CHLD_WAKEUP);
action = ACTION_CONT;
break;
-
+
case ACTION_STOP:
if (init_process)
{
debug (1, ("ignoring stop/restart"));
action = ACTION_CONT;
}
@@ -2273,13 +2276,13 @@ main (int argc, char **argv)
case ACTION_CTRLALTDEL:
debug (1, ("ctrl-alt-del"));
sysvinit_runlevel_setup (PIES_COMP_MASK (pies_comp_ctrlaltdel));
pies_schedule_children (PIES_CHLD_WAKEUP);
action = ACTION_CONT;
break;
-
+
case ACTION_KBREQUEST:
debug (1, ("kbrequest"));
sysvinit_runlevel_setup (PIES_COMP_MASK (pies_comp_kbrequest));
pies_schedule_children (PIES_CHLD_WAKEUP);
action = ACTION_CONT;
break;
diff --git a/src/pies.h b/src/pies.h
index a7f6567..bdc406b 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -101,13 +101,13 @@ struct action
{
size_t nstat;
unsigned *status;
enum return_action act; /* Action to take when the component terminates */
char *addr; /* Addresses to notify about it. */
char *message; /* Notification mail. */
- char *command; /* Execute this command */
+ char *command; /* Execute this command */
};
/* user privs */
struct pies_privs
{
@@ -134,20 +134,27 @@ enum pies_comp_mode
*/
pies_comp_inetd,
/* Open a socket, start a component, and pass the socket fd to the
component via the UNIX domain socket. Corresponds to
`start_action = pass' in MeTA1. */
pies_comp_pass_fd,
-
+
+ /* Components of this type runs once on program startup. Running other
+ components is delayed until the last startup component finishes. */
+ pies_comp_startup,
+
+ /* FIXME: Runs before program termination */
+ pies_comp_shutdown,
+
/*
** Init-style components
*/
pies_mark_sysvinit,
/* Start the process when the specified runlevel is entered and wait
for its termination */
- pies_comp_wait = pies_mark_sysvinit,
+ pies_comp_wait = pies_mark_sysvinit,
/* Execute the component once, when the specified runlevel is entered */
pies_comp_once,
/* Execute the component during system boot. Ignore runlevel settings. */
pies_comp_boot,
/* Execute the component during system boot and wait for it to terminate.
Ignore runlevel settings. */
@@ -159,13 +166,13 @@ enum pies_comp_mode
pies_comp_powerwait,
/* Execute the component when the power is restored. Wait for it to
terminate. */
pies_comp_powerokwait,
/* Execute the process when SIGINT is delivered, i.e. someone has
pressed the Ctrl+Alt+Del combination. */
- pies_comp_ctrlaltdel,
+ pies_comp_ctrlaltdel,
/* Execute the component when a specified ondemand runlevel is called */
pies_comp_ondemand,
/* Execute the component on the system boot. */
pies_comp_sysinit,
/* Execute the component when running on the UPS and pies is informed that
the UPS battery is almost empty. */
@@ -181,22 +188,22 @@ enum pies_comp_mode
#define PIES_COMP_DEFAULT 0
#define PIES_COMP_MASK(m) (1 << ((m)))
#define CF_DISABLED 0x001 /* The componenet is disabled */
#define CF_PRECIOUS 0x002 /* The component is precious (should not
- be disabled) */
+ be disabled) */
#define CF_WAIT 0x004 /* Wait for the component instance to
- terminate. */
+ terminate. */
#define CF_TCPMUX 0x008 /* A plain TCPMUX service */
#define CF_TCPMUXPLUS 0x010 /* A TCPMUX-plus service, i.e. pies
- must emit a '+' response before starting
- it */
+ must emit a '+' response before starting
+ it */
#define CF_INTERNAL 0x020 /* An internal inetd service */
#define CF_SOCKENV 0x040 /* Component wants socket information in
- the environment */
+ the environment */
#define CF_RESOLVE 0x080 /* Resolve IP addresses */
#define CF_SIGGROUP 0x100 /* Send signals to the process group */
#define CF_NULLINPUT 0x200 /* Provide null input stream */
#define CF_REMOVE 0x400 /* Marked for removal */
@@ -207,15 +214,15 @@ struct prog;
struct component
{
struct component *prev, *next; /* Components form doubly-linked list. */
int listidx; /* Index of the list. */
size_t arridx; /* Index of this component. */
- size_t ref_count; /* Reference count. */
+ size_t ref_count; /* Reference count. */
struct prog *prog; /* Prog associated with this component. */
-
+
enum pies_comp_mode mode;
char *tag; /* Entry tag (for diagnostics purposes) */
char *program; /* Program name */
size_t argc; /* Number of command line arguments */
char **argv; /* Program command line */
char **env; /* Program environment */
@@ -229,13 +236,13 @@ struct component
struct pies_privs privs; /* UID/GIDS+groups to run as */
mode_t umask; /* Umask to install before starting */
limits_record_t limits; /* System limits */
/* For exec (init) components */
char *runlevels;
-
+
/* For inetd components */
size_t max_rate; /* Maximum number of invocations per minute */
size_t max_ip_connections; /* Max. number of connections per IP address */
int socket_type; /* Socket type */
struct inetd_builtin *builtin; /* Builtin function */
char *service;
@@ -250,15 +257,15 @@ struct component
char *tcpmux; /* Master service for TCPMUX */
/* Optional error messages to be sent back on the socket: */
char *access_denied_message;
char *max_instances_message;
char *max_ip_connections_message;
-
+
/* Redirectors: */
- int facility; /* Syslog facility. */
+ int facility; /* Syslog facility. */
struct redirector redir[2]; /* Repeaters for stdout and stderr */
/* Actions to execute on various exit codes: */
struct grecs_list *act_list;
/* ACLs for control interface */
pies_acl_t list_acl; /* List access control list */
pies_acl_t adm_acl; /* Administrative ACL (stop, start, etc.) */
@@ -331,12 +338,13 @@ void free_action (struct action *act);
void pies_schedule_children (int op);
int pies_read_config (void);
int pies_reread_config (void);
void register_prog (struct component *comp);
+void program_init_startup (void);
int progman_waiting_p (void);
void progman_start (void);
void progman_gc (void);
void progman_wake_sleeping (int);
void progman_stop (void);
void progman_cleanup (int expect_term);
@@ -591,13 +599,13 @@ struct sysvinit_request
/* utmp.c */
#define SYSV_ACCT_BOOT 0
#define SYSV_ACCT_RUNLEVEL 1
#define SYSV_ACCT_PROC_START 2
-#define SYSV_ACCT_PROC_STOP 3
+#define SYSV_ACCT_PROC_STOP 3
void sysvinit_acct (int what, const char *user, const char *id, pid_t pid,
const char *line);
/* ctl.c */
diff --git a/src/progman.c b/src/progman.c
index 1b09cd5..5bc4eb3 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -62,13 +62,13 @@ progman_lookup_component (const char *tag)
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
if (IS_COMPONENT (prog) && strcmp (prog_tag (prog), tag) == 0)
return prog->v.p.comp;
return NULL;
-}
+}
struct component *
progman_lookup_tcpmux (const char *service, const char *master)
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
@@ -119,13 +119,13 @@ link_prog (struct prog *prog, struct prog *ref)
else
{
struct prog *x;
prog->prev = ref;
prog->next = ref->next;
-
+
if ((x = ref->next))
x->prev = prog;
else
progtail = prog;
ref->next = prog;
@@ -148,27 +148,27 @@ unlink_prog (struct prog *pp)
}
void
destroy_prog (struct prog **pp)
{
struct prog *p = *pp;
-
+
unlink_prog (p);
switch (p->type)
{
case TYPE_COMPONENT:
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) */
+ 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)
{
@@ -179,13 +179,13 @@ destroy_prog (struct prog **pp)
}
/* else
logmsg (LOG_NOTICE, _("orphan redirector: %s"), p->tag);*/
free (p->v.r.tag);
}
break;
-
+
case TYPE_COMMAND:
free (p->v.c.tag);
free (p->v.c.command);
}
free (p);
*pp = NULL;
@@ -253,13 +253,13 @@ find_prog_ref (struct component *comp)
if (!comp->prog)
{
comp = comp->prev;
if (!comp)
return NULL; /* FIXME: Skip redirectors? */
}
-
+
if (comp->prog)
{
for (prog = comp->prog;
prog->next
&& IS_COMPONENT (prog->next)
&& prog->next->v.p.comp == comp;
@@ -267,18 +267,18 @@ find_prog_ref (struct component *comp)
;
}
else
prog = NULL;
return prog;
}
-
+
static struct prog *
register_prog0 (struct component *comp)
{
struct prog *newp;
-
+
newp = grecs_zalloc (sizeof (*newp));
newp->type = TYPE_COMPONENT;
newp->pid = 0;
newp->v.p.comp = comp;
newp->v.p.socket = -1;
@@ -288,13 +288,13 @@ register_prog0 (struct component *comp)
newp->v.p.status = status_stopped;
if ((comp->flags & CF_DISABLED) || comp->mode == pies_comp_ondemand)
newp->active = 0;
else
newp->active = 1;
-
+
if (comp->mode != pies_comp_exec)
comp->redir[RETR_OUT].type = redir_null;
link_prog (newp, find_prog_ref (comp));
component_ref_incr (comp);
return newp;
@@ -314,20 +314,35 @@ register_command (char *tag, char *command, pid_t pid)
newp->pid = pid;
newp->v.c.tag = grecs_strdup (tag);
newp->v.c.command = command;
link_prog (newp, progtail);
}
+static inline int
+progman_startup_phase (void)
+{
+ struct prog *prog;
+
+ for (prog = proghead; prog; prog = prog->next)
+ {
+ if (IS_COMPONENT (prog) && prog->v.p.comp->mode == pies_comp_startup)
+ return 1;
+ }
+ return 0;
+}
+
int
progman_waiting_p (void)
{
struct prog *prog;
-
+
for (prog = proghead; prog; prog = prog->next)
{
- if (IS_COMPONENT (prog) && prog->wait && prog->pid > 0)
+ if (IS_COMPONENT (prog)
+ && prog->pid > 0
+ && (prog->wait || prog->v.p.comp->mode == pies_comp_startup))
{
debug (3, ("%s: waiting for %s (%lu)",
__FUNCTION__, prog_tag (prog),
(unsigned long) prog->pid));
return 1;
}
@@ -403,48 +418,48 @@ open_redirector (struct prog *master, int stream)
{
case redir_null:
return -1;
case redir_file:
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;
@@ -463,13 +478,13 @@ conn_class_hasher (void *data, unsigned long n_buckets)
{
struct conn_class *pcclass = data;
unsigned char const *tag = (unsigned char const *)pcclass->tag;
size_t value = 0;
unsigned char ch;
size_t len;
-
+
while ((ch = *tag++))
value = (value * 31 + ch) % n_buckets;
for (tag = (const unsigned char *)&pcclass->sa_storage,
len = pcclass->sa_len;
len;
@@ -527,13 +542,13 @@ conn_class_lookup (const char *tag,
default:
logmsg (LOG_ERR, _("unexpected address family: %d"),
probe->sa_storage.s.sa_family);
break;
}
-
+
probe->count = 0;
if (!conn_tab)
{
conn_tab = grecs_symtab_create(sizeof (struct conn_class),
conn_class_hasher,
conn_class_compare,
@@ -722,13 +737,13 @@ var_is_unset (char **env, const char *name)
static char *
env_concat (const char *name, size_t namelen, const char *a, const char *b)
{
char *res;
size_t len;
-
+
if (a && b)
{
res = grecs_malloc (namelen + 1 + strlen (a) + strlen (b) + 1);
strcpy (res + namelen + 1, a);
strcat (res + namelen + 1, b);
}
@@ -750,71 +765,71 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b)
strcpy (res + namelen + 1, b);
}
memcpy (res, name, namelen);
res[namelen] = '=';
return res;
}
-
+
static void
environ_setup (char **hint)
{
char **old_env = environ;
char **new_env;
size_t count, i, j, n;
-
+
if (!hint)
return;
if (strcmp (hint[0], "-") == 0)
{
old_env = NULL;
hint++;
}
-
+
/* Count new environment size */
count = 0;
if (old_env)
for (i = 0; old_env[i]; i++)
count++;
-
+
for (i = 0; hint[i]; i++)
count++;
/* Allocate new environment. */
new_env = grecs_calloc (count + 1, sizeof new_env[0]);
-
+
/* Populate the environment. */
n = 0;
-
+
if (old_env)
for (i = 0; old_env[i]; i++)
{
if (!var_is_unset (hint, old_env[i]))
new_env[n++] = old_env[i];
}
for (i = 0; hint[i]; i++)
{
char *p;
-
+
if (hint[i][0] == '-')
{
/* Skip unset directives. */
continue;
}
/* Find the slot for the variable. Use next available
slot if there's no such variable in new_env */
if (find_env_pos (new_env, hint[i], &j, NULL))
j = n;
-
+
if ((p = strchr (hint[i], '=')))
{
if (p == hint[i])
continue; /* Ignore erroneous entry */
- if (p[-1] == '+')
+ if (p[-1] == '+')
new_env[j] = env_concat (hint[i], p - hint[i] - 1,
find_env_ptr (environ, hint[i], 1),
p + 1);
else if (p[1] == '+')
new_env[j] = env_concat (hint[i], p - hint[i],
p + 2,
@@ -832,13 +847,13 @@ environ_setup (char **hint)
++n;
}
new_env[n] = NULL;
if (envsize)
free (environ);
-
+
environ = new_env;
envsize = count + 1;
}
/* Pass socket information in environment variables. */
void
@@ -849,29 +864,29 @@ prog_sockenv (struct prog *prog)
struct hostent *host;
union pies_sockaddr_storage sa_server;
socklen_t len = sizeof (sa_server);
union pies_sockaddr_storage *sa_client = &prog->v.p.sa_storage;
socklen_t cltlen = prog->v.p.sa_len;
const char *proto = NULL;
-
+
if (!(prog->v.p.comp->flags & CF_SOCKENV))
return;
if (socket_type_to_str (prog->v.p.comp->socket_type, &proto))
proto = umaxtostr (prog->v.p.comp->socket_type, buf);
add_env (ENV_SOCKTYPE, proto);
-
+
if (prog->v.p.comp->socket_url)
proto = prog->v.p.comp->socket_url->proto_s;
else if (prog->v.p.listener)
proto = prog->v.p.listener->v.p.comp->socket_url->proto_s;
else if (ISCF_TCPMUX (prog->v.p.comp->flags))
proto = "TCP";
add_env (ENV_PROTO, proto);
-
+
if (getsockname (prog->v.p.socket,
(struct sockaddr *) &sa_server, &len) < 0)
logmsg (LOG_WARNING, "getsockname(): %s", strerror (errno));
else if (sa_server.s.sa_family == AF_INET)
{
p = inet_ntoa (sa_server.s_in.sin_addr);
@@ -917,31 +932,31 @@ prog_sockenv (struct prog *prog)
}
static int
check_rate (struct prog *prog, unsigned testtime, size_t max_count)
{
time_t now;
-
+
time (&now);
if (prog->v.p.timestamp + testtime > now)
prog->v.p.failcount++;
else
{
prog->v.p.failcount = 0;
prog->v.p.timestamp = now;
}
-
+
if (prog->v.p.failcount > max_count)
{
prog->v.p.timestamp = now;
prog->v.p.status = status_sleeping;
pies_schedule_children (PIES_CHLD_RESCHEDULE_ALARM);
return 1;
}
-
+
return 0;
}
static int
check_spawn_rate (struct prog *prog)
{
@@ -958,13 +973,13 @@ check_spawn_rate (struct prog *prog)
}
static int
check_connection_rate (struct prog *prog)
{
size_t max_rate = prog->v.p.comp->max_rate
- ? prog->v.p.comp->max_rate : default_max_rate;
+ ? prog->v.p.comp->max_rate : default_max_rate;
if (max_rate && check_rate (prog, 60, max_rate))
{
logmsg (LOG_NOTICE,
ngettext ("%s is starting too often, disabled for %d minute",
"%s is starting too often, disabled for %d minutes",
SLEEPTIME / 60),
@@ -1006,33 +1021,33 @@ prog_start_prologue (struct prog *prog)
{
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));
}
-
+
environ_setup (prog->v.p.comp->env ?
prog->v.p.comp->env :
((prog->v.p.comp->flags & CF_SOCKENV) ? sockenv_hint : NULL));
if (init_process)
environ_setup (sysvinit_environ_hint);
DEBUG_ENVIRON (4);
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);
-
+
if (debug_level >= 1)
{
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]));
logmsg_printf (LOG_DEBUG, "\n");
}
}
@@ -1044,13 +1059,13 @@ prog_execute (struct prog *prog)
{
mf_proctitle_format ("inetd %s",
prog->v.p.comp->builtin->service);
prog->v.p.comp->builtin->fun (0, prog->v.p.comp);
_exit (0);
}
-
+
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);
syslog (LOG_CRIT, _("cannot start `%s': %s"), prog_tag (prog),
strerror (errno));
@@ -1074,13 +1089,13 @@ progman_run_comp (struct component *comp, int fd,
static void
prog_start (struct prog *prog)
{
pid_t pid;
int redir[2];
fd_set fdset;
-
+
if (prog->pid > 0 || !IS_COMPONENT (prog))
return;
if (is_sysvinit (prog->v.p.comp))
{
if (!init_process)
@@ -1120,13 +1135,13 @@ prog_start (struct prog *prog)
logfuncall ("unlink", prog->v.p.comp->pass_fd_socket, errno);
return;
}
if (prog_open_socket (prog))
return;
break;
-
+
case pies_comp_accept:
if (check_spawn_rate (prog))
return;
if (prog_open_socket (prog))
return;
break;
@@ -1136,15 +1151,15 @@ prog_start (struct prog *prog)
if (prog->v.p.socket == -1)
return;
default:
break;
}
-
+
debug (1, (_("starting %s"), prog_tag (prog)));
-
+
if (prog->v.p.comp->rmfile)
{
debug (1, (_("unlinking %s"), prog->v.p.comp->rmfile));
if (unlink (prog->v.p.comp->rmfile) && errno != ENOENT)
logmsg (LOG_ERR, _("%s: cannot remove file `%s': %s"),
prog_tag (prog), prog->v.p.comp->rmfile, strerror (errno));
@@ -1155,37 +1170,37 @@ prog_start (struct prog *prog)
prog->v.p.comp->builtin->fun (prog->v.p.socket, prog->v.p.comp);
return;
}
redir[RETR_OUT] = open_redirector (prog, RETR_OUT);
redir[RETR_ERR] = open_redirector (prog, RETR_ERR);
-
+
switch (pid = fork ())
{
/* The child branch. */
case 0:
signal_setup (SIG_DFL);
setsid ();
prog_start_prologue (prog);
switch (prog->v.p.comp->mode)
- {
- case pies_comp_accept:
- case pies_comp_inetd:
+ {
+ case pies_comp_accept:
+ case pies_comp_inetd:
prog_sockenv (prog);
- dup2 (prog->v.p.socket, 0);
- dup2 (prog->v.p.socket, 1);
- close (prog->v.p.socket);
+ dup2 (prog->v.p.socket, 0);
+ dup2 (prog->v.p.socket, 1);
+ close (prog->v.p.socket);
prog->v.p.socket = -1;
- break;
+ break;
default:
if (init_process)
{
int fd = console_open (O_RDWR|O_NOCTTY);
- if (fd < 0)
+ if (fd < 0)
{
logmsg (LOG_CRIT, "open(%s): %s",
console_device, strerror (errno));
fd = open ("/dev/null", O_RDWR);
}
if (fd != 0)
@@ -1215,14 +1230,14 @@ prog_start (struct prog *prog)
}
else if (redir[RETR_OUT] != 1)
{
dup2 (redir[RETR_OUT], 1);
}
}
- break;
- }
+ break;
+ }
if (!init_process)
{
if (redir[RETR_ERR] == -1)
{
if (!DIAG_OUTPUT (DIAG_TO_STDERR))
@@ -1233,25 +1248,25 @@ prog_start (struct prog *prog)
}
else if (redir[RETR_ERR] != 1)
{
dup2 (redir[RETR_ERR], 2);
}
}
-
+
/* 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);
prog_execute (prog);
-
-
+
+
case -1:
logmsg (LOG_CRIT,
_("cannot run `%s': fork failed: %s"),
prog_tag (prog), strerror (errno));
break;
@@ -1288,20 +1303,20 @@ prog_start (struct prog *prog)
int
check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen,
pies_identity_t identity)
{
struct acl_input input;
int rc;
-
+
if (!acl)
return 0;
input.addr = s;
input.addrlen = salen;
input.identity = identity;
-
+
rc = pies_acl_check (acl, &input, 1);
if (rc == 0)
{
char *p = sockaddr_to_astr (s, salen);
logmsg (LOG_ERR, _("access from %s blocked"), p);
free (p);
@@ -1312,13 +1327,13 @@ check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen,
}
void
fd_report (int fd, const char *msg)
{
size_t len;
-
+
if (!msg)
return;
for (len = strlen (msg); len; )
{
ssize_t rc = write (fd, msg, len);
@@ -1331,30 +1346,30 @@ fd_report (int fd, const char *msg)
}
else if (rc == 0)
break;
len -= rc;
msg += rc;
}
-}
+}
static int
_prog_accept (struct prog *p)
{
int fd;
struct prog *pinst;
union pies_sockaddr_storage addr;
socklen_t addrlen = sizeof addr;
struct conn_class *pcclass;
-
+
fd = accept (p->v.p.socket, (struct sockaddr*) &addr, &addrlen);
if (fd == -1)
{
logfuncall ("accept", NULL, errno);
return 1;
}
-
+
if (debug_level >= 1)
{
char *s = sockaddr_to_astr ((struct sockaddr *)&addr, addrlen);
logmsg (LOG_DEBUG, _("%s wants %s"), s, prog_tag (p));
free (s);
}
@@ -1391,13 +1406,13 @@ _prog_accept (struct prog *p)
prog_tag (p), s);
free (s);
fd_report (fd, p->v.p.comp->max_ip_connections_message);
close (fd);
return 1;
}
-
+
if (check_connection_rate (p))
{
disable_socket (p->v.p.socket);
close (fd);
return 1;
}
@@ -1444,22 +1459,22 @@ _prog_wait (struct prog *p)
pinst->v.p.socket = -1;
p->v.p.num_instances++;
return 0;
}
-
+
int
progman_accept (int socket, void *data)
{
struct prog *p = data;
if (p->v.p.comp->socket_type == SOCK_STREAM
&& !(p->v.p.comp->flags & CF_WAIT))
return _prog_accept (p);
-
+
return _prog_wait (p);
}
static int
prog_create_socket (struct prog *prog, void *data)
{
@@ -1523,20 +1538,40 @@ progman_recompute_alarm (void)
debug (2, ("alarm=%lu", (unsigned long)alarm_time));
if (alarm_time)
alarm (alarm_time);
}
void
+program_init_startup (void)
+{
+ struct prog *prog;
+
+ for (prog = proghead; prog; prog = prog->next)
+ if (IS_COMPONENT (prog) && prog->v.p.comp->mode == pies_comp_startup)
+ {
+ debug (1, ("running startup components"));
+ break;
+ }
+
+ for (; prog; prog = prog->next)
+ if (IS_COMPONENT (prog) && prog->v.p.comp->mode == pies_comp_startup)
+ {
+ prog_start (prog);
+ }
+}
+
+void
progman_start (void)
{
struct prog *prog;
if (progman_waiting_p ())
- /* Noting to do if there are processes left in the previous runlevel */
+ /* Noting to do if there are processes left in the previous runlevel
+ (in sysv-init mode) or startup components running. */
return;
-
+
debug (1, ("starting components"));
for (prog = proghead; prog; prog = prog->next)
if (IS_COMPONENT (prog))
{
switch (prog->v.p.status)
{
@@ -1562,14 +1597,14 @@ progman_start (void)
static void
check_stopping (struct prog *prog, time_t now)
{
if (now - prog->v.p.timestamp >= shutdown_timeout)
{
if (prog->pid == 0)
- logmsg (LOG_EMERG,
- _("INTERNAL ERROR: attempting to kill unexisting process %s"),
+ logmsg (LOG_EMERG,
+ _("INTERNAL ERROR: attempting to kill unexisting process %s"),
prog_tag (prog));
else if (prog->v.p.comp->flags & CF_SIGGROUP)
kill (-prog->pid, SIGKILL);
else
kill (prog->pid, SIGKILL);
}
@@ -1622,43 +1657,43 @@ progman_wake_sleeping (int onalrm)
/* If there is no alarm pending, recompute next alarm.
This allows to cope with eventual clock inaccuracies. */
if (onalrm)
pies_schedule_children (PIES_CHLD_RESCHEDULE_ALARM);
}
break;
-
+
case status_stopping:
check_stopping (prog, now);
break;
case status_stopped:
if (IS_ACTIVE_COMPONENT (prog))
prog_start (prog);
break;
-
+
default:
break;
}
}
static int
prog_start_prerequisites (struct prog *prog)
{
int ret = 0;
pies_depmap_pos_t pos;
struct component *comp;
int warned = 0;
-
+
if (!prog->active)
return 1;
for (comp = component_depmap_first (depmap_col, prog->v.p.comp->arridx, &pos);
comp;
comp = component_depmap_next (pos))
{
struct prog *p;
-
+
if (!comp->prog || comp->flags & CF_PRECIOUS)
continue;
if (!warned)
{
debug (1, ("starting prerequisites of %s", prog_tag (prog)));
warned = 1;
@@ -1666,22 +1701,22 @@ prog_start_prerequisites (struct prog *prog)
if (!prog->active)
{
prog->active = 0;
return 1;
}
-
+
p = comp->prog;
switch (p->v.p.status)
{
case status_running:
continue;
-
+
case status_stopped:
break;
-
+
case status_listener:
continue;
case status_sleeping:
/* FIXME: What to do in this case? */
break;
@@ -1697,13 +1732,13 @@ prog_start_prerequisites (struct prog *prog)
prog_start (p);
if (p->v.p.comp->mode == pies_comp_once
|| p->v.p.status != status_running)//FIXME
ret = 1;
}
depmap_end (pos);
-
+
return ret;
}
void
prog_stop_redirectors (struct prog *prog)
{
@@ -1754,13 +1789,13 @@ prog_stop (struct prog *prog, int sig)
}
debug (1, ("stopping %s (%lu)", prog_tag (prog), (unsigned long) prog->pid));
if (prog->type == TYPE_COMPONENT && prog->v.p.comp->flags & CF_SIGGROUP)
kill (-prog->pid, sig);
else
kill (prog->pid, sig);
-}
+}
static int
mark_for_stopping (struct prog *prog, void *data)
{
if (IS_COMPONENT (prog))
prog->stop = 1;
@@ -1784,13 +1819,13 @@ print_status (const char *tag, pid_t pid, int status, int expect_term)
if (debug_level <= 1)
return;
prio = LOG_DEBUG;
}
else
prio = LOG_ERR;
-
+
if (WIFEXITED (status))
{
if (WEXITSTATUS (status) == 0)
debug (1, (_("%s (%lu) exited successfully"),
tag, (unsigned long) pid));
else
@@ -1798,13 +1833,13 @@ print_status (const char *tag, pid_t pid, int status, int expect_term)
tag, (unsigned long) pid,
WEXITSTATUS (status));
}
else if (WIFSIGNALED (status))
{
char const *coremsg = "";
-
+
if (expect_term && WTERMSIG (status) == SIGTERM)
prio = LOG_DEBUG;
#ifdef WCOREDUMP
if (WCOREDUMP (status))
coremsg = _(" (core dumped)");
@@ -1820,13 +1855,13 @@ print_status (const char *tag, pid_t pid, int status, int expect_term)
else
logmsg (prio, _("%s (%lu) terminated with unrecognized status: %d"),
tag, (unsigned long) pid, status);
}
static void propagate_child_exit (pid_t) ATTRIBUTE_NORETURN;
-
+
static void
propagate_child_exit (pid_t pid)
{
int wait_status;
while (waitpid (pid, &wait_status, 0) == -1)
@@ -1852,13 +1887,13 @@ wordsplit_string (struct wordsplit const *ws)
{
char *ret, *p;
size_t count = ws->ws_wordc + ws->ws_offs;
char **argv = grecs_calloc (count, sizeof (argv[0]));
size_t i;
size_t len = 0;
-
+
for (i = 0; i < count; i++)
{
argv[i] = quotearg_n (i, ws->ws_wordv[i]);
len += strlen (argv[i]);
}
len += count;
@@ -1880,26 +1915,26 @@ send_msg (char *rcpts, const char *msg_text)
{
int i, j, k;
pid_t child_pid, grand_child_pid;
struct wordsplit ws;
int p[2];
size_t size;
-
+
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;
}
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.
@@ -1908,13 +1943,13 @@ send_msg (char *rcpts, const char *msg_text)
in which case i > k.
*/
for (j = 0, k = i; j < ws.ws_wordc; j++, 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]))
@@ -1931,16 +1966,16 @@ send_msg (char *rcpts, const char *msg_text)
continue;
memmove (ws.ws_wordv[k], arg, len);
ws.ws_wordv[k][len] = 0;
k++;
}
ws.ws_wordv[k] = NULL;
-
+
/* Fork a child: */
child_pid = fork ();
-
+
if (child_pid < 0)
{
wordsplit_free (&ws);
logmsg (LOG_ERR,
_("cannot send mail: fork failed: %s"), strerror (errno));
return;
@@ -1952,25 +1987,25 @@ send_msg (char *rcpts, const char *msg_text)
wordsplit_free (&ws);
debug (1, (_("started mailer: %s, pid=%lu"),
cmd, (unsigned long) child_pid));
register_command (mailer_program, cmd, child_pid);
return;
}
-
+
/* Child process */
/* ============= */
signal_setup (SIG_DFL);
setsid ();
if (pipe (p))
{
logmsg (LOG_ERR, _("cannot send mail: pipe failed: %s"),
strerror (errno));
wordsplit_free (&ws);
exit (EX_OSERR);
}
-
+
grand_child_pid = fork ();
if (grand_child_pid < 0)
{
logmsg (LOG_ERR,
_("cannot send mail: fork failed: %s"), strerror (errno));
return;
@@ -2027,22 +2062,22 @@ notify_get_tag (char **ret, void *data)
{
struct notify_closure const *clos = data;
char *s = strdup (clos->tag);
if (!s)
return WRDSE_NOSPACE;
*ret = s;
- return WRDSE_OK;
+ return WRDSE_OK;
}
static int
notify_get_termination (char **ret, void *data)
{
struct notify_closure const *clos = data;
char const *msg;
char *s;
-
+
if (WIFEXITED (clos->status))
/* TRANSLATORS: The subject of this statement is 'component' */
msg = _("exited with code");
else if (WIFSIGNALED (clos->status))
/* TRANSLATORS: The subject of this statement is 'component' */
msg = _("terminated on signal");
@@ -2050,34 +2085,34 @@ notify_get_termination (char **ret, void *data)
msg = "UNKNOWN";
s = strdup (msg);
if (!s)
return WRDSE_NOSPACE;
*ret = s;
- return WRDSE_OK;
+ return WRDSE_OK;
}
-
+
static int
notify_get_retcode (char **ret, void *data)
{
struct notify_closure const *clos = data;
char *s = NULL;
size_t l = 0;
-
+
if (WIFEXITED (clos->status))
grecs_asprintf (&s, &l, "%d", WEXITSTATUS (clos->status));
else if (WIFSIGNALED (clos->status))
grecs_asprintf (&s, &l, "%d", WTERMSIG (clos->status));
else
s = strdup ("UNKNOWN");
if (!s)
return WRDSE_NOSPACE;
*ret = s;
- return WRDSE_OK;
-}
-
+ return WRDSE_OK;
+}
+
struct notify_variable
{
char *name;
size_t name_length;
int (*get) (char **ret, void *data);
};
@@ -2087,23 +2122,23 @@ static struct notify_variable notify_vartab[] = {
{ S(component), notify_get_tag },
{ S(termination), notify_get_termination },
{ S(retcode), notify_get_retcode },
#undef S
{ NULL }
};
-
+
static int
notify_getvar (char **ret, const char *vptr, size_t vlen, void *data)
{
struct notify_variable *var;
for (var = notify_vartab; var->name; var++)
if (var->name_length == vlen && memcmp (var->name, vptr, vlen) == 0)
return var->get (ret, data);
return WRDSE_UNDEF;
}
-
+
static void
notify (const char *tag, int status, struct action *act)
{
const char *env[] = {
#define PROGRAM_NAME_IDX 1
"program_name", NULL,
@@ -2117,13 +2152,13 @@ notify (const char *tag, int status, struct action *act)
struct wordsplit ws;
struct notify_closure closure;
closure.tag = tag;
closure.status = status;
closure.act = act;
-
+
env[PROGRAM_NAME_IDX] = program_name;
env[INSTANCE_IDX] = instance;
ws.ws_env = env;
ws.ws_getvar = notify_getvar;
ws.ws_closure = &closure;
@@ -2141,13 +2176,13 @@ 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;
@@ -2181,13 +2216,13 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
if (retcode & STATUS_SIG_BIT)
setenv ("PIES_SIGNAL", umaxtostr (STATUS_CODE (retcode), buf), 1);
else
setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1);
close_fds (NULL);
-
+
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = act->command;
argv[3] = NULL;
execv (argv[0], argv);
@@ -2205,13 +2240,13 @@ react (struct prog *prog, int status, pid_t pid)
{
unsigned retcode;
struct grecs_list *list = prog->v.p.comp->act_list;
if (!list)
list = default_component.act_list;
-
+
if (WIFEXITED (status))
{
retcode = WEXITSTATUS (status);
debug (1, (_("%s: terminated with code %d"), prog_tag (prog), retcode));
}
else if (WIFSIGNALED (status))
@@ -2230,27 +2265,27 @@ react (struct prog *prog, int status, pid_t pid)
if (list)
{
struct grecs_list_entry *ep;
for (ep = list->head; ep; ep = ep->next)
{
struct action *act = ep->data;
-
+
if (status_matches_p (act, retcode))
{
if (act->command)
{
run_command (act, prog, retcode, pid);
}
-
+
switch (act->act)
{
case action_restart:
if (prog->v.p.comp->mode != pies_comp_inetd)
prog_start (prog);
break;
-
+
case action_disable:
logmsg (LOG_NOTICE, _("disabling component %s"),
prog_tag (prog));
prog->active = 0;
/* FIXME:
if (prog->v.p.comp->mode == pies_comp_inetd)
@@ -2260,13 +2295,13 @@ react (struct prog *prog, int status, pid_t pid)
if (act->addr)
notify (prog_tag (prog), status, act);
break;
}
}
}
-
+
if (!list && prog->v.p.comp->mode != pies_comp_inetd)
/* Default action: */
prog_start (prog);
}
void
@@ -2291,26 +2326,26 @@ progman_cleanup (int expect_term)
case TYPE_COMPONENT:
print_status (prog_tag (prog), pid, status, expect_term);
prog->stop = 0;
if (prog->v.p.comp->mode == pies_comp_inetd)
{
struct prog *listener = prog->v.p.listener;
-
+
listener->v.p.num_instances--;
if (prog->v.p.cclass)
{
prog->v.p.cclass->count--;
if (debug_level > 1)
conn_class_report (LOG_DEBUG, prog->v.p.cclass);
if (prog->v.p.cclass->count == 0)
{
conn_class_remove (prog->v.p.cclass);
prog->v.p.cclass = NULL;
}
}
-
+
prog_stop_redirectors (prog);
if (listener->v.p.num_instances == 0
&& !component_is_active (prog->v.p.comp))
destroy_prog (&listener);
else
{
@@ -2318,21 +2353,29 @@ progman_cleanup (int expect_term)
react (listener, status, pid);
if (listener->v.p.comp->flags & CF_WAIT)
enable_socket (listener->v.p.socket);
}
destroy_prog (&prog);
}
+ else if (prog->v.p.comp->mode == pies_comp_startup)
+ {
+ debug (1, (_("removing startup component %s, pid=%lu"),
+ prog_tag (prog), (unsigned long)pid));
+ destroy_prog (&prog);
+ if (!progman_startup_phase ())
+ pies_schedule_children (PIES_CHLD_WAKEUP);
+ }
else
{
if (prog->v.p.comp->mode >= pies_mark_sysvinit
&& prog->v.p.comp->mode != pies_comp_ondemand)
{
sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog_tag (prog),
pid, "");
prog->v.p.status = status_finished;
-
+
if (prog->wait)
{
pies_schedule_children (PIES_CHLD_WAKEUP);
prog->wait = 0;
}
}
@@ -2348,13 +2391,13 @@ progman_cleanup (int expect_term)
react (prog, status, pid);
}
if (!component_is_active (prog->v.p.comp))
destroy_prog (&prog);
}
-
+
break;
case TYPE_REDIRECTOR:
/* It was a redirector of an already finished process. */
print_status (prog_tag (prog), pid, status,
expect_term ||
@@ -2368,13 +2411,13 @@ progman_cleanup (int expect_term)
case TYPE_COMMAND:
print_status (prog_tag (prog), pid, status, expect_term);
destroy_prog (&prog);
break;
}
}
-
+
if (!expect_term)
/* This will also recompute alarm settings, if necessary */
progman_wake_sleeping (0);
}
void
@@ -2386,13 +2429,13 @@ progman_stop_component (struct prog **progptr)
switch (prog->v.p.status)
{
case status_running:
logmsg (LOG_INFO, _("stopping component %s"), prog_tag (prog));
prog_stop (prog, SIGTERM);
break;
-
+
case status_listener:
prog_deactivate_listener (prog);
/* fall through */
case status_stopped:
prog->stop = 0;
if (!component_is_active (prog->v.p.comp))
@@ -2410,13 +2453,13 @@ progman_stop_component (struct prog **progptr)
prog->v.p.failcount = 0;
}
break;
case status_stopping:
break;
-
+
case status_finished:
prog->stop = 0;
if (!component_is_active (prog->v.p.comp))
destroy_prog (progptr);
else
logmsg (LOG_INFO,
@@ -2438,13 +2481,13 @@ prog_deactivate_listener (struct prog *prog)
}
int
prog_activate_listener (struct prog *prog)
{
struct component *comp = prog->v.p.comp;
-
+
logmsg (LOG_INFO, _("activating listener %s"), prog_tag (prog));
if (comp->mode == pies_comp_inetd && !ISCF_TCPMUX (comp->flags)
&& prog->v.p.socket == -1)
{
int fd = create_socket (comp->socket_url,
comp->socket_type,
@@ -2532,12 +2575,12 @@ progman_gc (void)
return;
if (time (NULL) - start < shutdown_timeout)
sleep (1);
else
break;
}
-
+
/* FIXME: Report remaining programs */
-
+
}
-
+
/* EOF */
diff --git a/src/socket.c b/src/socket.c
index aa01543..40c7aa7 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -20,19 +20,22 @@
static void
switch_eids (uid_t *puid, gid_t *pgid, mode_t *pumask)
{
uid_t ouid = geteuid ();
gid_t ogid = getegid ();
mode_t omask = umask (*pumask);
-
- if (setegid (*pgid))
- logmsg (LOG_ERR, _("cannot switch to EGID %lu: %s"),
- (unsigned long) *pgid, strerror (errno));
- if (seteuid (*puid))
- logmsg (LOG_ERR, _("cannot switch to EUID %lu: %s"),
- (unsigned long) *puid, strerror (errno));
+
+ if ((*puid && *puid != ouid) || (*pgid && *pgid != ogid))
+ {
+ if (setegid (*pgid))
+ logmsg (LOG_ERR, _("cannot switch to EGID %lu: %s"),
+ (unsigned long) *pgid, strerror (errno));
+ if (seteuid (*puid))
+ logmsg (LOG_ERR, _("cannot switch to EUID %lu: %s"),
+ (unsigned long) *puid, strerror (errno));
+ }
*puid = ouid;
*pgid = ogid;
*pumask = omask;
}
int
@@ -48,20 +51,20 @@ create_socket (struct pies_url *url, int socket_type,
struct sockaddr_un s_un;
} addr;
socklen_t socklen;
uid_t uid = 0;
gid_t gid = 0;
int switch_back;
-
+
if (strcmp (url->scheme, "unix") == 0
|| strcmp (url->scheme, "file") == 0
|| strcmp (url->scheme, "socket") == 0)
{
struct stat st;
const char *group = NULL;
-
+
user = url->user;
if (url->argc)
{
size_t i;
for (i = 0; i < url->argc; i++)
{
@@ -96,36 +99,36 @@ create_socket (struct pies_url *url, int socket_type,
url->string, arg + len + 1);
else
umaskval = 0777 & ~n;
}
}
}
-
+
if (user)
{
struct passwd *pw = getpwnam (user);
if (!pw)
{
logmsg (LOG_ERR, _("no such user: %s"), user);
return -1;
}
uid = pw->pw_uid;
gid = pw->pw_gid;
}
-
+
if (group)
{
struct group *grp = getgrnam (group);
if (!grp)
{
logmsg (LOG_ERR, _("no such group: %s"), user);
return -1;
}
gid = grp->gr_gid;
}
-
+
if (strlen (url->path) > sizeof addr.s_un.sun_path)
{
errno = EINVAL;
logmsg (LOG_ERR, _("%s: UNIX socket name too long"), url->path);
return -1;
}
@@ -156,20 +159,20 @@ create_socket (struct pies_url *url, int socket_type,
}
}
else if (strcmp (url->scheme, "inet") == 0)
{
const char *host = url->host;
short port = url->port;
-
+
uid = 0;
gid = 0;
umaskval = 0;
addr.sa.sa_family = PF_INET;
socklen = sizeof (addr.s_in);
-
+
if (!host)
addr.s_in.sin_addr.s_addr = INADDR_ANY;
else
{
struct hostent *hp = gethostbyname (host);
if (!hp)
@@ -182,26 +185,26 @@ create_socket (struct pies_url *url, int socket_type,
switch (hp->h_addrtype)
{
case AF_INET:
memmove (&addr.s_in.sin_addr, hp->h_addr, 4);
addr.s_in.sin_port = htons (port);
break;
-
+
default:
logmsg (LOG_ERR, _("%s: unsupported address family"),
url->string);
return -1;
}
}
}
else
{
logmsg (LOG_ERR, "%s: unknown scheme", url->string);
return -1;
}
-
+
fd = socket (addr.sa.sa_family, socket_type, url->proto);
if (fd == -1)
{
logfuncall ("socket", url->string, errno);
return -1;
}
@@ -247,13 +250,13 @@ pass_fd0 (int fd, int payload)
# ifndef CMSG_LEN
# define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size))
# endif /* ! CMSG_LEN */
# ifndef CMSG_SPACE
# define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
# endif /* ! CMSG_SPACE */
-
+
char control[CMSG_SPACE (sizeof (int))];
struct cmsghdr *cmptr;
msg.msg_control = (caddr_t) control;
msg.msg_controllen = CMSG_LEN (sizeof (int));
@@ -287,21 +290,21 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime)
enum { fds_init, fds_open, fds_connected, fds_ready } state = fds_init;
static char *fds_descr[] = { "init", "open", "connected", "ready" };
time_t start = time (NULL);
int sockfd = -1;
int res = -1;
struct sockaddr_un addr;
-
+
if (strlen (socket_name) > sizeof addr.sun_path)
{
logmsg (LOG_ERR, _("%s: UNIX socket name too long"), socket_name);
return -1;
}
addr.sun_family = AF_UNIX;
strcpy (addr.sun_path, socket_name);
-
+
for (;;)
{
time_t now = time (NULL);
if (now - start > maxtime)
{
@@ -359,13 +362,13 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime)
if (state == fds_connected)
{
int rc;
fd_set fds;
struct timeval tv;
-
+
FD_ZERO (&fds);
FD_SET (sockfd, &fds);
tv.tv_usec = 0;
tv.tv_sec = maxtime - (now - start);
rc = select (sockfd + 1, NULL, &fds, NULL, &tv);
if (rc == 0)
@@ -427,13 +430,13 @@ calc_fd_max (void)
for (sp = si_head; sp; sp = sp->next)
if (sp->fd > fd_max)
fd_max = sp->fd;
}
void *
-register_socket (int fd,
+register_socket (int fd,
socket_handler_t rd,
socket_handler_t wr,
socket_handler_t ex,
void *data)
{
struct sockinst *sip = grecs_malloc (sizeof *sip);
@@ -451,13 +454,13 @@ register_socket (int fd,
{
FD_ZERO (&fdset[PIES_EVT_RD]);
FD_ZERO (&fdset[PIES_EVT_WR]);
FD_ZERO (&fdset[PIES_EVT_EX]);
si_head = sip;
}
-
+
si_tail = sip;
if (rd)
FD_SET (fd, &fdset[PIES_EVT_RD]);
if (wr)
FD_SET (fd, &fdset[PIES_EVT_WR]);
if (ex)
@@ -490,13 +493,13 @@ delete_sockinst (struct sockinst *sp)
FD_CLR (sp->fd, &fdset[PIES_EVT_RD]);
if (sp->handler[PIES_EVT_WR])
FD_CLR (sp->fd, &fdset[PIES_EVT_WR]);
if (sp->handler[PIES_EVT_EX])
FD_CLR (sp->fd, &fdset[PIES_EVT_EX]);
fd_max = -1;
-
+
if (sp->prev)
sp->prev->next = sp->next;
else
si_head = sp->next;
if (sp->next)
sp->next->prev = sp->prev;
@@ -569,22 +572,22 @@ pies_set_hook (int (*f) (void))
void
pies_pause (void)
{
if (pies_pause_hook && pies_pause_hook ())
return;
-
+
if (fd_max == -1)
calc_fd_max ();
while (1)
{
fd_set rdset = fdset[PIES_EVT_RD];
fd_set wrset = fdset[PIES_EVT_WR];
fd_set exset = fdset[PIES_EVT_EX];
-
+
int rc = select (fd_max + 1, &rdset, &wrset, &exset, NULL);
if (rc > 0)
{
struct sockinst *sp;
int delete = 0;
++si_iterating;
@@ -634,7 +637,6 @@ pies_pause (void)
if (errno != EINTR)
logmsg (LOG_ERR, "select: %s", strerror (errno));
break;
}
}
}
-
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 447104b..b2f2719 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -11,13 +11,19 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Pies. If not, see <http://www.gnu.org/licenses/>.
-EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 respawn retcode mailer
+AUXTOOLS = \
+ aux/respawn\
+ aux/retcode\
+ aux/mailer\
+ aux/startup
+
+EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 $(AUXTOOLS)
DISTCLEANFILES = atconfig $(check_SCRIPTS)
MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE)
## ------------ ##
## package.m4. ##
## ------------ ##
@@ -43,12 +49,13 @@ TESTSUITE_AT = \
control.at\
cyclic.at\
respawn.at\
redirect.at\
ret-exec.at\
ret-notify.at\
+ startup.at\
version.at
TESTSUITE = $(srcdir)/testsuite
M4=m4
AUTOTEST = $(AUTOM4TE) --language=autotest
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 9069bbd..1992b80 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -1,10 +1,10 @@
# @configure_input@ -*- shell-script -*-
# Configurable variable values for GNU Pies test suite.
# Copyright (C) 2016-2019 Sergey Poznyakoff
PATH=@abs_builddir@:@abs_top_builddir@/src:$srcdir:$PATH
XFAILFILE=$abs_builddir/.badversion
-
+auxdir="$abs_srcdir/aux"
trimws() {
sed 's/[ ][ ]*$//'
}
diff --git a/tests/mailer b/tests/aux/mailer
index f832ff5..f832ff5 100755
--- a/tests/mailer
+++ b/tests/aux/mailer
diff --git a/tests/respawn b/tests/aux/respawn
index 11d59f6..11d59f6 100755
--- a/tests/respawn
+++ b/tests/aux/respawn
diff --git a/tests/retcode b/tests/aux/retcode
index b827ba9..b827ba9 100755
--- a/tests/retcode
+++ b/tests/aux/retcode
diff --git a/tests/aux/startup b/tests/aux/startup
new file mode 100755
index 0000000..b9d92a3
--- a/dev/null
+++ b/tests/aux/startup
@@ -0,0 +1,7 @@
+#!/bin/sh
+dir=${1:?}
+time=${2:?}
+tag=${3:?}
+
+touch $dir/$tag
+sleep $time
diff --git a/tests/redirect.at b/tests/redirect.at
index 9e53ba2..3a8cca7 100644
--- a/tests/redirect.at
+++ b/tests/redirect.at
@@ -21,13 +21,13 @@ PIES_XFAIL_CHECK
PIES_CONTROL_INIT
comp_pid_file=$PWD/comp.pid
outfile=$PWD/out
cat > pies.conf <<_EOT
component test {
mode respawn;
- command "$abs_srcdir/respawn -tag respawn -append -pid $comp_pid_file";
+ command "$auxdir/respawn -tag respawn -append -pid $comp_pid_file";
stdout file "$outfile";
}
_EOT
pies --config-file control.conf --config-file pies.conf
diff --git a/tests/respawn.at b/tests/respawn.at
index 8d72c40..4a8e3a7 100644
--- a/tests/respawn.at
+++ b/tests/respawn.at
@@ -20,13 +20,13 @@ AT_CHECK([
PIES_XFAIL_CHECK
PIES_CONTROL_INIT
comp_pid_file=$PWD/comp.pid
cat > pies.conf <<_EOT
component test {
mode respawn;
- command "$abs_srcdir/respawn -append -pid $comp_pid_file";
+ command "$auxdir/respawn -append -pid $comp_pid_file";
}
_EOT
pies --config-file control.conf --config-file pies.conf
n=0
diff --git a/tests/ret-exec.at b/tests/ret-exec.at
index bf2c1a4..0b3d716 100644
--- a/tests/ret-exec.at
+++ b/tests/ret-exec.at
@@ -23,16 +23,16 @@ PIES_CONTROL_INIT
comp_pid_file=$PWD/comp.pid
report_file=$PWD/report
cat > pies.conf <<_EOT
component test {
mode respawn;
return-code 10 {
- exec "$abs_srcdir/retcode $report_file";
+ exec "$auxdir/retcode $report_file";
action disable;
}
- command "$abs_srcdir/respawn -sleep 2 -pid $comp_pid_file -exit 10";
+ command "$auxdir/respawn -sleep 2 -pid $comp_pid_file -exit 10";
}
_EOT
>$report_file
pies --config-file control.conf --config-file pies.conf
diff --git a/tests/ret-notify.at b/tests/ret-notify.at
index d1a7f39..a7768aa 100644
--- a/tests/ret-notify.at
+++ b/tests/ret-notify.at
@@ -19,21 +19,21 @@ AT_KEYWORDS([ret-notify])
AT_CHECK([
PIES_XFAIL_CHECK
PIES_CONTROL_INIT
report_file=$PWD/report
cat > pies.conf <<_EOT
-mailer-program "$abs_srcdir/mailer";
-mailer-command-line "$abs_srcdir/mailer $report_file";
+mailer-program "$auxdir/mailer";
+mailer-command-line "$auxdir/mailer $report_file";
component test {
mode respawn;
return-code 10 {
notify root;
action disable;
}
- command "$abs_srcdir/respawn -sleep 2 -exit 10";
+ command "$auxdir/respawn -sleep 2 -exit 10";
}
_EOT
>$report_file
pies --config-file control.conf --config-file pies.conf
diff --git a/tests/startup.at b/tests/startup.at
new file mode 100644
index 0000000..72017ce
--- a/dev/null
+++ b/tests/startup.at
@@ -0,0 +1,84 @@
+# This file is part of GNU pies testsuite. -*- Autotest -*-
+# Copyright (C) 2019 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
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU pies is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU pies. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Startup components])
+
+AT_CHECK([
+PIES_XFAIL_CHECK
+PIES_CONTROL_INIT
+comp_pid_file=$PWD/comp.pid
+
+cat > pies.conf <<_EOT
+component b1 {
+ mode startup;
+ command "$auxdir/startup $PWD 1 b1";
+}
+
+component b2 {
+ mode startup;
+ command "$auxdir/startup $PWD 2 b2";
+}
+
+component test {
+ mode respawn;
+ command "$auxdir/respawn -append -pid $comp_pid_file";
+}
+_EOT
+
+pies --config-file control.conf --config-file pies.conf
+
+n=0
+res=
+b1=
+b2=
+while :
+do
+ echo "n=$n" >> tracefile
+ if test -z "$b1" && test -f b1; then
+ res="${res}b1"
+ b1=1
+ echo "got b1" >> tracefile
+ fi
+ if test -z "$b2" && test -f b2; then
+ res="${res}b2"
+ b2=1
+ echo "got b2" >> tracefile
+ fi
+ if test -f $comp_pid_file; then
+ echo "got pidfile" >> tracefile
+ res="${res}pid"
+ break
+ fi
+ sleep 1
+ n=$(($n + 1))
+ if test $n -gt 10; then
+ echo >&2 "timed out"
+ break
+ fi
+done
+
+PIES_STOP
+case $res in
+b1b2pid|b2b1pid) echo b1b2pid;;
+*) echo $res
+esac
+],
+[0],
+[b1b2pid
+])
+
+AT_CLEANUP
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 03ddd50..2a1167d 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -62,6 +62,7 @@ AT_BANNER([Dependencies])
m4_include([cyclic.at])
AT_BANNER([Components])
m4_include([respawn.at])
m4_include([redirect.at])
m4_include([ret-exec.at])
m4_include([ret-notify.at])
+m4_include([startup.at])

Return to:

Send suggestions and report system problems to the System administrator.