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) (show whitespace changes)
-rw-r--r--src/comp.c65
-rw-r--r--src/pies.c3
-rw-r--r--src/pies.h8
-rw-r--r--src/progman.c47
-rw-r--r--src/socket.c4
-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, 213 insertions, 31 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,8 +222,13 @@ component_ref_decr (struct component *comp)
{
assert (comp->ref_count > 0);
if (--comp->ref_count == 0)
+ {
+ if (component_is_active (comp))
+ comp_array_remove (comp->arridx);
+ else
component_free (comp);
}
+}
static int
argvcmp (char **a, char **b)
@@ -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);
- }
else
i++;
@@ -528,8 +539,17 @@ 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; )
+ {
+ struct component *next = comp->next;
+ if (loaded && comp->mode == pies_comp_startup)
+ {
+ /* Ignore startup components */
+ component_unlink (comp);
+ component_free (comp);
+ }
+ else
{
match = complist_find_match (prev, comp);
if (match)
@@ -543,7 +563,12 @@ component_config_commit (void)
}
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
@@ -820,6 +820,8 @@ 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},
@@ -2228,6 +2230,7 @@ main (int argc, char **argv)
signal_setup (sig_handler);
progman_create_sockets ();
+ program_init_startup ();
progman_start ();
do
diff --git a/src/pies.h b/src/pies.h
index a7f6567..bdc406b 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -138,6 +138,13 @@ enum pies_comp_mode
`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
*/
@@ -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);
diff --git a/src/progman.c b/src/progman.c
index 1b09cd5..5bc4eb3 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -317,6 +317,19 @@ 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)
{
@@ -324,7 +337,9 @@ progman_waiting_p (void)
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),
@@ -1526,12 +1541,32 @@ 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"));
@@ -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
diff --git a/src/socket.c b/src/socket.c
index aa01543..40c7aa7 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -24,12 +24,15 @@ switch_eids (uid_t *puid, gid_t *pgid, mode_t *pumask)
gid_t ogid = getegid ();
mode_t omask = umask (*pumask);
+ 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;
@@ -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.