summaryrefslogtreecommitdiffabout
Side-by-side diff
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.