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
@@ -24,6 +24,11 @@ struct complist
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;
@@ -32,13 +37,13 @@ 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);
@@ -85,6 +90,22 @@ component_append (struct component *comp)
}
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];
@@ -201,7 +222,12 @@ 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
@@ -425,17 +451,6 @@ report_cyclic_dependency (pies_depmap_t dp, size_t idx)
}
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;
@@ -460,7 +475,6 @@ component_build_depmap (void)
"which is not declared"),
comp->tag, tag);
comp_array_remove (i);
- depmap_remove (depmap, i);
continue;
}
depmap_set (depmap, i, tgt);
@@ -497,10 +511,7 @@ component_build_depmap (void)
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++;
@@ -528,22 +539,36 @@ component_config_commit (void)
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];
@@ -560,6 +585,8 @@ component_config_commit (void)
for (comp = comp_list[cur].head; comp; comp = comp->next)
if (!comp->prog)
register_prog (comp);
+
+ loaded = 1;
}
static int
diff --git a/src/pies.c b/src/pies.c
index 89c0b7e..98488a6 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -132,7 +132,7 @@ 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;
@@ -156,7 +156,7 @@ 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;
@@ -327,7 +327,7 @@ action_free (struct action *act)
free (act->addr);
free (act->message);
free (act->command);
-
+
free (act);
}
@@ -359,7 +359,7 @@ create_action (struct component *comp,
unsigned n;
const char *arg = getarg (val, i, locus);
size_t len = strlen (arg);
-
+
if (isdigit (arg[0]))
{
char *p;
@@ -394,12 +394,12 @@ create_action (struct component *comp,
grecs_error (locus, 0, _("%s: not a return code"), arg);
continue;
}
-
+
/* Alles in ordnung */
retv[retc++] = n;
}
}
-
+
if (retc == 0 && !allflag)
{
free (retv);
@@ -472,18 +472,18 @@ return_code_section_parser (enum grecs_callback_command cmd,
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);
@@ -492,7 +492,7 @@ return_code_section_parser (enum grecs_callback_command cmd,
return 1;
*(struct action **) cb_data = act;
break;
-
+
case grecs_callback_section_end:
break;
@@ -542,7 +542,7 @@ _cb_command (enum grecs_callback_command cmd,
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;
@@ -702,7 +702,7 @@ _cb_redir (enum grecs_callback_command cmd,
{NULL}
};
int res;
-
+
switch (value->type)
{
case GRECS_TYPE_STRING:
@@ -719,7 +719,7 @@ _cb_redir (enum grecs_callback_command cmd,
return 0;
}
break;
-
+
case GRECS_TYPE_ARRAY:
if (assert_grecs_value_type (locus, value->v.arg.v[0],
GRECS_TYPE_STRING))
@@ -739,12 +739,12 @@ _cb_redir (enum grecs_callback_command cmd,
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))
@@ -755,7 +755,7 @@ _cb_redir (enum grecs_callback_command cmd,
return 0;
}
break;
-
+
case redir_file:
rp->v.file = grecs_strdup (value->v.arg.v[1]->v.string);
break;
@@ -764,17 +764,17 @@ _cb_redir (enum grecs_callback_command cmd,
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 },
@@ -820,12 +820,14 @@ static struct tokendef modetab[] = {
{"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},
@@ -920,11 +922,11 @@ _cb_flags (enum grecs_callback_command cmd,
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;
@@ -939,7 +941,7 @@ _cb_flags (enum grecs_callback_command cmd,
}
}
break;
-
+
case GRECS_TYPE_ARRAY:
grecs_error (locus, 0, _("too many arguments"));
return 1;
@@ -1228,7 +1230,7 @@ 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;
@@ -1256,7 +1258,7 @@ component_section_parser (enum grecs_callback_command cmd,
comp = *(struct component **) section_data;
component_finish (comp, locus);
break;
-
+
case grecs_callback_set_value:
grecs_error (locus, 0, _("expected block statement"));
}
@@ -1534,7 +1536,7 @@ pies_config_parse (char const *name)
if (!tree)
return 1;
-
+
for (node = tree; node; node = node->next)
{
node = grecs_find_node (node, "identity-provider");
@@ -1550,7 +1552,7 @@ pies_config_parse (char const *name)
if (grecs_error_count)
return 1;
-
+
return 0;
}
@@ -1573,7 +1575,7 @@ pies_read_config (void)
int err = 0;
component_config_begin ();
-
+
for (ep = config_list->head; ep; ep = ep->next)
{
struct config_file *file = ep->data;
@@ -1583,10 +1585,10 @@ pies_read_config (void)
if (init_process)
err = 0;
-
+
if (err)
component_config_rollback ();
-
+
return err;
}
@@ -1656,7 +1658,7 @@ 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++)
@@ -1779,7 +1781,7 @@ 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";
@@ -1803,7 +1805,7 @@ void
list_components (void)
{
char *argv[5];
-
+
argv[0] = "piesctl";
argv[1] = "--url";
argv[2] = (char*) pies_control_url ();
@@ -1942,7 +1944,7 @@ 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"),
@@ -2033,7 +2035,7 @@ main (int argc, char **argv)
struct grecs_list_entry *ep;
int diag_flags;
int i;
-
+
set_program_name (argv[0]);
#ifdef ENABLE_NLS
setlocale (LC_ALL, "");
@@ -2043,10 +2045,10 @@ main (int argc, char **argv)
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;
@@ -2058,7 +2060,7 @@ main (int argc, char **argv)
break;
}
}
-
+
/* Set default logging */
if (init_process)
{
@@ -2067,13 +2069,13 @@ main (int argc, char **argv)
}
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))
@@ -2081,7 +2083,7 @@ main (int argc, char **argv)
logmsg (LOG_ERR, "extra command line arguments");
exit (EX_USAGE);
}
-
+
if (!instance)
{
instance = strrchr (program_name, '/');
@@ -2119,13 +2121,13 @@ main (int argc, char **argv)
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];
@@ -2137,7 +2139,7 @@ main (int argc, char **argv)
exit (EX_OSERR);
}
}
-
+
switch (command)
{
case COM_RESTART_COMPONENT:
@@ -2145,7 +2147,7 @@ main (int argc, char **argv)
if (pies_umask)
umask (pies_umask);
exit (request_restart_components (argc, argv));
-
+
case COM_RELOAD:
exit (request_reload ());
@@ -2162,11 +2164,11 @@ main (int argc, char **argv)
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)
@@ -2193,13 +2195,13 @@ main (int argc, char **argv)
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);
@@ -2212,14 +2214,14 @@ main (int argc, char **argv)
}
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; "
@@ -2228,6 +2230,7 @@ main (int argc, char **argv)
signal_setup (sig_handler);
progman_create_sockets ();
+ program_init_startup ();
progman_start ();
do
@@ -2261,7 +2264,7 @@ main (int argc, char **argv)
pies_schedule_children (PIES_CHLD_WAKEUP);
action = ACTION_CONT;
break;
-
+
case ACTION_STOP:
if (init_process)
{
@@ -2276,7 +2279,7 @@ main (int argc, char **argv)
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));
diff --git a/src/pies.h b/src/pies.h
index a7f6567..bdc406b 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -104,7 +104,7 @@ struct action
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 */
};
@@ -137,14 +137,21 @@ enum pies_comp_mode
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. */
@@ -162,7 +169,7 @@ enum pies_comp_mode
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. */
@@ -184,16 +191,16 @@ enum pies_comp_mode
#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 */
@@ -210,9 +217,9 @@ 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 */
@@ -232,7 +239,7 @@ struct component
/* 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 */
@@ -253,9 +260,9 @@ struct component
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;
@@ -334,6 +341,7 @@ 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);
@@ -594,7 +602,7 @@ struct sysvinit_request
#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);
diff --git a/src/progman.c b/src/progman.c
index 1b09cd5..5bc4eb3 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -65,7 +65,7 @@ progman_lookup_component (const char *tag)
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)
@@ -122,7 +122,7 @@ link_prog (struct prog *prog, struct prog *ref)
prog->prev = ref;
prog->next = ref->next;
-
+
if ((x = ref->next))
x->prev = prog;
else
@@ -151,21 +151,21 @@ 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;
@@ -182,7 +182,7 @@ destroy_prog (struct prog **pp)
free (p->v.r.tag);
}
break;
-
+
case TYPE_COMMAND:
free (p->v.c.tag);
free (p->v.c.command);
@@ -256,7 +256,7 @@ find_prog_ref (struct component *comp)
if (!comp)
return NULL; /* FIXME: Skip redirectors? */
}
-
+
if (comp->prog)
{
for (prog = comp->prog;
@@ -270,12 +270,12 @@ find_prog_ref (struct component *comp)
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;
@@ -291,7 +291,7 @@ register_prog0 (struct component *comp)
newp->active = 0;
else
newp->active = 1;
-
+
if (comp->mode != pies_comp_exec)
comp->redir[RETR_OUT].type = redir_null;
@@ -317,14 +317,29 @@ register_command (char *tag, char *command, pid_t pid)
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),
@@ -406,17 +421,17 @@ open_redirector (struct prog *master, int stream)
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:
@@ -428,10 +443,10 @@ open_redirector (struct prog *master, int stream)
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)
@@ -441,7 +456,7 @@ open_redirector (struct prog *master, int stream)
while (getline (&buf, &size, fp) > 0)
syslog (prio, "%s", buf);
_exit (0);
-
+
case -1:
logmsg (LOG_CRIT,
_("cannot run redirector `%s': fork failed: %s"),
@@ -466,7 +481,7 @@ conn_class_hasher (void *data, unsigned long n_buckets)
size_t value = 0;
unsigned char ch;
size_t len;
-
+
while ((ch = *tag++))
value = (value * 31 + ch) % n_buckets;
@@ -530,7 +545,7 @@ conn_class_lookup (const char *tag,
probe->sa_storage.s.sa_family);
break;
}
-
+
probe->count = 0;
if (!conn_tab)
{
@@ -725,7 +740,7 @@ 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);
@@ -753,14 +768,14 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b)
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;
@@ -769,22 +784,22 @@ environ_setup (char **hint)
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++)
{
@@ -795,7 +810,7 @@ environ_setup (char **hint)
for (i = 0; hint[i]; i++)
{
char *p;
-
+
if (hint[i][0] == '-')
{
/* Skip unset directives. */
@@ -806,12 +821,12 @@ environ_setup (char **hint)
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);
@@ -835,7 +850,7 @@ environ_setup (char **hint)
if (envsize)
free (environ);
-
+
environ = new_env;
envsize = count + 1;
}
@@ -852,14 +867,14 @@ prog_sockenv (struct prog *prog)
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)
@@ -868,7 +883,7 @@ prog_sockenv (struct prog *prog)
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));
@@ -920,7 +935,7 @@ 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)
@@ -930,7 +945,7 @@ check_rate (struct prog *prog, unsigned testtime, size_t max_count)
prog->v.p.failcount = 0;
prog->v.p.timestamp = now;
}
-
+
if (prog->v.p.failcount > max_count)
{
prog->v.p.timestamp = now;
@@ -938,7 +953,7 @@ check_rate (struct prog *prog, unsigned testtime, size_t max_count)
pies_schedule_children (PIES_CHLD_RESCHEDULE_ALARM);
return 1;
}
-
+
return 0;
}
@@ -961,7 +976,7 @@ 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,
@@ -1009,7 +1024,7 @@ prog_start_prologue (struct prog *prog)
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));
@@ -1020,16 +1035,16 @@ prog_start_prologue (struct prog *prog)
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]));
@@ -1047,7 +1062,7 @@ prog_execute (struct prog *prog)
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);
@@ -1077,7 +1092,7 @@ prog_start (struct prog *prog)
pid_t pid;
int redir[2];
fd_set fdset;
-
+
if (prog->pid > 0 || !IS_COMPONENT (prog))
return;
@@ -1123,7 +1138,7 @@ prog_start (struct prog *prog)
if (prog_open_socket (prog))
return;
break;
-
+
case pies_comp_accept:
if (check_spawn_rate (prog))
return;
@@ -1139,9 +1154,9 @@ prog_start (struct prog *prog)
default:
break;
}
-
+
debug (1, (_("starting %s"), prog_tag (prog)));
-
+
if (prog->v.p.comp->rmfile)
{
debug (1, (_("unlinking %s"), prog->v.p.comp->rmfile));
@@ -1158,7 +1173,7 @@ prog_start (struct prog *prog)
redir[RETR_OUT] = open_redirector (prog, RETR_OUT);
redir[RETR_ERR] = open_redirector (prog, RETR_ERR);
-
+
switch (pid = fork ())
{
/* The child branch. */
@@ -1167,22 +1182,22 @@ prog_start (struct prog *prog)
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));
@@ -1218,8 +1233,8 @@ prog_start (struct prog *prog)
dup2 (redir[RETR_OUT], 1);
}
}
- break;
- }
+ break;
+ }
if (!init_process)
{
@@ -1236,7 +1251,7 @@ prog_start (struct prog *prog)
dup2 (redir[RETR_ERR], 2);
}
}
-
+
/* Close unneeded descripitors */
FD_ZERO (&fdset);
FD_SET (0, &fdset);
@@ -1247,8 +1262,8 @@ prog_start (struct prog *prog)
close_fds (&fdset);
prog_execute (prog);
-
-
+
+
case -1:
logmsg (LOG_CRIT,
_("cannot run `%s': fork failed: %s"),
@@ -1291,14 +1306,14 @@ check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen,
{
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)
{
@@ -1315,7 +1330,7 @@ void
fd_report (int fd, const char *msg)
{
size_t len;
-
+
if (!msg)
return;
@@ -1334,7 +1349,7 @@ fd_report (int fd, const char *msg)
len -= rc;
msg += rc;
}
-}
+}
static int
_prog_accept (struct prog *p)
@@ -1344,14 +1359,14 @@ _prog_accept (struct prog *p)
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);
@@ -1394,7 +1409,7 @@ _prog_accept (struct prog *p)
close (fd);
return 1;
}
-
+
if (check_connection_rate (p))
{
disable_socket (p->v.p.socket);
@@ -1447,7 +1462,7 @@ _prog_wait (struct prog *p)
p->v.p.num_instances++;
return 0;
}
-
+
int
progman_accept (int socket, void *data)
{
@@ -1456,7 +1471,7 @@ progman_accept (int socket, void *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);
}
@@ -1526,14 +1541,34 @@ progman_recompute_alarm (void)
}
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))
@@ -1565,8 +1600,8 @@ 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);
@@ -1625,7 +1660,7 @@ progman_wake_sleeping (int onalrm)
pies_schedule_children (PIES_CHLD_RESCHEDULE_ALARM);
}
break;
-
+
case status_stopping:
check_stopping (prog, now);
break;
@@ -1634,7 +1669,7 @@ progman_wake_sleeping (int onalrm)
if (IS_ACTIVE_COMPONENT (prog))
prog_start (prog);
break;
-
+
default:
break;
}
@@ -1647,7 +1682,7 @@ prog_start_prerequisites (struct prog *prog)
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);
@@ -1655,7 +1690,7 @@ prog_start_prerequisites (struct prog *prog)
comp = component_depmap_next (pos))
{
struct prog *p;
-
+
if (!comp->prog || comp->flags & CF_PRECIOUS)
continue;
if (!warned)
@@ -1669,16 +1704,16 @@ prog_start_prerequisites (struct prog *prog)
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;
@@ -1700,7 +1735,7 @@ prog_start_prerequisites (struct prog *prog)
ret = 1;
}
depmap_end (pos);
-
+
return ret;
}
@@ -1757,7 +1792,7 @@ prog_stop (struct prog *prog, int sig)
kill (-prog->pid, sig);
else
kill (prog->pid, sig);
-}
+}
static int
mark_for_stopping (struct prog *prog, void *data)
@@ -1787,7 +1822,7 @@ print_status (const char *tag, pid_t pid, int status, int expect_term)
}
else
prio = LOG_ERR;
-
+
if (WIFEXITED (status))
{
if (WEXITSTATUS (status) == 0)
@@ -1801,7 +1836,7 @@ print_status (const char *tag, pid_t pid, int status, int expect_term)
else if (WIFSIGNALED (status))
{
char const *coremsg = "";
-
+
if (expect_term && WTERMSIG (status) == SIGTERM)
prio = LOG_DEBUG;
@@ -1823,7 +1858,7 @@ print_status (const char *tag, pid_t pid, int status, int expect_term)
}
static void propagate_child_exit (pid_t) ATTRIBUTE_NORETURN;
-
+
static void
propagate_child_exit (pid_t pid)
{
@@ -1855,7 +1890,7 @@ wordsplit_string (struct wordsplit const *ws)
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]);
@@ -1883,7 +1918,7 @@ send_msg (char *rcpts, const char *msg_text)
struct wordsplit ws;
int p[2];
size_t size;
-
+
ws.ws_offs = mailer_argc;
ws.ws_delim = ",";
if (wordsplit (rcpts, &ws,
@@ -1896,7 +1931,7 @@ send_msg (char *rcpts, const char *msg_text)
}
debug (1, (_("sending notification to %s"), rcpts));
-
+
/* Copy mailer arguments */
for (i = 0; i < mailer_argc; i++)
ws.ws_wordv[i] = mailer_argv[i];
@@ -1911,7 +1946,7 @@ send_msg (char *rcpts, const char *msg_text)
{
char *arg = ws.ws_wordv[i];
size_t len;
-
+
while (*arg && c_isblank (*arg))
arg++;
len = strlen (arg);
@@ -1934,10 +1969,10 @@ send_msg (char *rcpts, const char *msg_text)
k++;
}
ws.ws_wordv[k] = NULL;
-
+
/* Fork a child: */
child_pid = fork ();
-
+
if (child_pid < 0)
{
wordsplit_free (&ws);
@@ -1955,7 +1990,7 @@ send_msg (char *rcpts, const char *msg_text)
register_command (mailer_program, cmd, child_pid);
return;
}
-
+
/* Child process */
/* ============= */
signal_setup (SIG_DFL);
@@ -1967,7 +2002,7 @@ send_msg (char *rcpts, const char *msg_text)
wordsplit_free (&ws);
exit (EX_OSERR);
}
-
+
grand_child_pid = fork ();
if (grand_child_pid < 0)
{
@@ -2030,7 +2065,7 @@ notify_get_tag (char **ret, void *data)
if (!s)
return WRDSE_NOSPACE;
*ret = s;
- return WRDSE_OK;
+ return WRDSE_OK;
}
static int
@@ -2039,7 +2074,7 @@ 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");
@@ -2053,16 +2088,16 @@ notify_get_termination (char **ret, void *data)
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))
@@ -2072,9 +2107,9 @@ notify_get_retcode (char **ret, void *data)
if (!s)
return WRDSE_NOSPACE;
*ret = s;
- return WRDSE_OK;
-}
-
+ return WRDSE_OK;
+}
+
struct notify_variable
{
char *name;
@@ -2090,7 +2125,7 @@ static struct notify_variable notify_vartab[] = {
#undef S
{ NULL }
};
-
+
static int
notify_getvar (char **ret, const char *vptr, size_t vlen, void *data)
{
@@ -2100,7 +2135,7 @@ notify_getvar (char **ret, const char *vptr, size_t vlen, void *data)
return var->get (ret, data);
return WRDSE_UNDEF;
}
-
+
static void
notify (const char *tag, int status, struct action *act)
{
@@ -2120,7 +2155,7 @@ notify (const char *tag, int status, struct action *act)
closure.tag = tag;
closure.status = status;
closure.act = act;
-
+
env[PROGRAM_NAME_IDX] = program_name;
env[INSTANCE_IDX] = instance;
@@ -2144,7 +2179,7 @@ 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++)
@@ -2184,7 +2219,7 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1);
close_fds (NULL);
-
+
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = act->command;
@@ -2208,7 +2243,7 @@ react (struct prog *prog, int status, pid_t pid)
if (!list)
list = default_component.act_list;
-
+
if (WIFEXITED (status))
{
retcode = WEXITSTATUS (status);
@@ -2233,21 +2268,21 @@ react (struct prog *prog, int status, pid_t pid)
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));
@@ -2263,7 +2298,7 @@ react (struct prog *prog, int status, pid_t pid)
}
}
}
-
+
if (!list && prog->v.p.comp->mode != pies_comp_inetd)
/* Default action: */
prog_start (prog);
@@ -2294,7 +2329,7 @@ progman_cleanup (int expect_term)
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)
{
@@ -2307,7 +2342,7 @@ progman_cleanup (int expect_term)
prog->v.p.cclass = NULL;
}
}
-
+
prog_stop_redirectors (prog);
if (listener->v.p.num_instances == 0
&& !component_is_active (prog->v.p.comp))
@@ -2321,6 +2356,14 @@ progman_cleanup (int expect_term)
}
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
@@ -2329,7 +2372,7 @@ progman_cleanup (int expect_term)
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);
@@ -2351,7 +2394,7 @@ progman_cleanup (int expect_term)
if (!component_is_active (prog->v.p.comp))
destroy_prog (&prog);
}
-
+
break;
case TYPE_REDIRECTOR:
@@ -2371,7 +2414,7 @@ progman_cleanup (int expect_term)
break;
}
}
-
+
if (!expect_term)
/* This will also recompute alarm settings, if necessary */
progman_wake_sleeping (0);
@@ -2389,7 +2432,7 @@ progman_stop_component (struct prog **progptr)
logmsg (LOG_INFO, _("stopping component %s"), prog_tag (prog));
prog_stop (prog, SIGTERM);
break;
-
+
case status_listener:
prog_deactivate_listener (prog);
/* fall through */
@@ -2413,7 +2456,7 @@ progman_stop_component (struct prog **progptr)
case status_stopping:
break;
-
+
case status_finished:
prog->stop = 0;
if (!component_is_active (prog->v.p.comp))
@@ -2441,7 +2484,7 @@ 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)
@@ -2535,9 +2578,9 @@ progman_gc (void)
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
@@ -23,13 +23,16 @@ 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;
@@ -51,14 +54,14 @@ create_socket (struct pies_url *url, int socket_type,
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)
{
@@ -99,7 +102,7 @@ create_socket (struct pies_url *url, int socket_type,
}
}
}
-
+
if (user)
{
struct passwd *pw = getpwnam (user);
@@ -111,7 +114,7 @@ create_socket (struct pies_url *url, int socket_type,
uid = pw->pw_uid;
gid = pw->pw_gid;
}
-
+
if (group)
{
struct group *grp = getgrnam (group);
@@ -122,7 +125,7 @@ create_socket (struct pies_url *url, int socket_type,
}
gid = grp->gr_gid;
}
-
+
if (strlen (url->path) > sizeof addr.s_un.sun_path)
{
errno = EINVAL;
@@ -159,14 +162,14 @@ create_socket (struct pies_url *url, int socket_type,
{
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
@@ -185,7 +188,7 @@ create_socket (struct pies_url *url, int socket_type,
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);
@@ -198,7 +201,7 @@ create_socket (struct pies_url *url, int socket_type,
logmsg (LOG_ERR, "%s: unknown scheme", url->string);
return -1;
}
-
+
fd = socket (addr.sa.sa_family, socket_type, url->proto);
if (fd == -1)
{
@@ -250,7 +253,7 @@ pass_fd0 (int fd, int payload)
# ifndef CMSG_SPACE
# define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
# endif /* ! CMSG_SPACE */
-
+
char control[CMSG_SPACE (sizeof (int))];
struct cmsghdr *cmptr;
@@ -290,7 +293,7 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime)
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);
@@ -298,7 +301,7 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime)
}
addr.sun_family = AF_UNIX;
strcpy (addr.sun_path, socket_name);
-
+
for (;;)
{
time_t now = time (NULL);
@@ -362,7 +365,7 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime)
int rc;
fd_set fds;
struct timeval tv;
-
+
FD_ZERO (&fds);
FD_SET (sockfd, &fds);
tv.tv_usec = 0;
@@ -430,7 +433,7 @@ calc_fd_max (void)
}
void *
-register_socket (int fd,
+register_socket (int fd,
socket_handler_t rd,
socket_handler_t wr,
socket_handler_t ex,
@@ -454,7 +457,7 @@ register_socket (int fd,
FD_ZERO (&fdset[PIES_EVT_EX]);
si_head = sip;
}
-
+
si_tail = sip;
if (rd)
FD_SET (fd, &fdset[PIES_EVT_RD]);
@@ -493,7 +496,7 @@ delete_sockinst (struct sockinst *sp)
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
@@ -572,7 +575,7 @@ pies_pause (void)
{
if (pies_pause_hook && pies_pause_hook ())
return;
-
+
if (fd_max == -1)
calc_fd_max ();
@@ -581,7 +584,7 @@ pies_pause (void)
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)
{
@@ -637,4 +640,3 @@ pies_pause (void)
}
}
}
-
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 447104b..b2f2719 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -14,7 +14,13 @@
# 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)
@@ -46,6 +52,7 @@ TESTSUITE_AT = \
redirect.at\
ret-exec.at\
ret-notify.at\
+ startup.at\
version.at
TESTSUITE = $(srcdir)/testsuite
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 9069bbd..1992b80 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -4,7 +4,7 @@
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
@@ -24,7 +24,7 @@ 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
diff --git a/tests/respawn.at b/tests/respawn.at
index 8d72c40..4a8e3a7 100644
--- a/tests/respawn.at
+++ b/tests/respawn.at
@@ -23,7 +23,7 @@ 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
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
@@ -26,10 +26,10 @@ 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
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
@@ -22,15 +22,15 @@ 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
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
@@ -65,3 +65,4 @@ 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.