From 27ba3b27f56c78b1757f5508c60de90c2e590be2 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Sun, 3 Apr 2022 11:56:42 +0200 Subject: [PATCH] test: extend start-stop-serv test w/ all supported combinations serv: add support for foregrounding, running with and without PID file, including custom PID filename. test: verify Finit can start & monitor services that: 1) Fork and creates a PID file in a known location 2) Don't fork and don't create a PID file, but Finit does 3) Don't fork but create a PID file 4) Don't fork and create custom named PID file Note: Finit cannot support a service that forks and doesn't create a PID file. This combination is impossible to support without tracking all processes created in /proc -- which Finit does not do atm. Signed-off-by: Joachim Wiberg --- test/common/serv.c | 81 ++++++++++++++++++++++++++++++++++------- test/start-stop-serv.sh | 67 +++++++++++++++++++++------------- test/tenv/lib.sh | 10 +++++ 3 files changed, 120 insertions(+), 38 deletions(-) diff --git a/test/common/serv.c b/test/common/serv.c index 3d2f26c6..56d9b6ff 100644 --- a/test/common/serv.c +++ b/test/common/serv.c @@ -1,4 +1,9 @@ -/* Basic forking UNIX daemon with no options to run in foreground */ +/* + * Basic UNIX daemon + * + * Options to run in foreground and to create a PID file. When running + * in foregrund it does not create a PID file by default. + */ #include #include @@ -8,43 +13,93 @@ #include #include +#define PROGNM "serv" + static void sig(int signo) { warnx("We got signal %d ...", signo); exit(0); } -static void pidfile(char *nm) +static void pidfile(char *pidfn) { char fn[80]; pid_t pid; FILE *fp; - if (!nm) - nm = "serv"; - - snprintf(fn, sizeof(fn), "%s%s.pid", _PATH_VARRUN, nm); + if (!pidfn) { + snprintf(fn, sizeof(fn), "%s%s.pid", _PATH_VARRUN, PROGNM); + pidfn = fn; + } pid = getpid(); - warnx("Creating PID file %s with %d", fn, pid); + warnx("Creating PID file %s with %d", pidfn, pid); - fp = fopen(fn, "w"); + fp = fopen(pidfn, "w"); if (!fp) exit(1); fprintf(fp, "%d\n", pid); fclose(fp); } -int main(void) +static int usage(int rc) { + FILE *fp = rc ? stderr : stdout; + + fprintf(fp, + "%s [-nhp] [-P FILE]\n" + "\n" + " -n Run in foreground\n" + " -h Show help text (this)\n" + " -p Create PID file despite running in foreground\n" + " -P FILE Create PID file using FILE\n" + "\n" + "By default this program daemonizes itself to the background, and,\n" + "when it's done setting up its signal handler(s), creates a PID file\n" + "to let the rest of the system know it's done. When the program runs\n" + "in the foreground it does not create a PID file by default.\n", + PROGNM); + + return rc; +} + +int main(int argc, char *argv[]) +{ + int do_background = 1; + int do_pidfile = 1; + char *pidfn = NULL; + int c; + + while ((c = getopt(argc, argv, "hnpP:")) != EOF) { + switch (c) { + case 'h': + return usage(0); + case 'n': + do_background = 0; + do_pidfile--; + break; + case 'p': + do_pidfile++; + break; + case 'P': + pidfn = optarg; + break; + default: + return usage(1); + } + } + /* Daemonize, fork to background etc. */ - if (daemon(0, 1)) - return 1; + if (do_background) { + if (daemon(0, 1)) + return 1; + } /* Signal handlers first *then* PID file */ signal(SIGTERM, sig); - /* Tell finit where we really are */ - pidfile(NULL); + /* Tell world where we are, but not if bg w/o pid file */ + if (do_pidfile == 1) + pidfile(pidfn); warnx("Entering while(1) loop"); while (1) diff --git a/test/start-stop-serv.sh b/test/start-stop-serv.sh index 3739ef3d..4176087a 100755 --- a/test/start-stop-serv.sh +++ b/test/start-stop-serv.sh @@ -1,11 +1,13 @@ #!/bin/sh - set -eu TEST_DIR=$(dirname "$0") -# shellcheck source=/dev/null -. "$TEST_DIR/tenv/lib.sh" +test_setup() +{ + say "Test start $(date)" + cp "$TENV_ROOT"/../common/serv "$TENV_ROOT"/test_assets/ +} test_teardown() { @@ -16,35 +18,50 @@ test_teardown() texec rm -f /test_assets/serv } -say "Test start $(date)" +test_one() +{ + pidfn=$1 + service=$2 -cp "$TENV_ROOT"/../common/serv "$TENV_ROOT"/test_assets/ + say "Add service stanza '$service' to $FINIT_CONF ..." + texec sh -c "echo '$service' > $FINIT_CONF" -say "Add service stanza in $FINIT_CONF" -texec sh -c "echo 'service [2345] pid:!/run/serv.pid /test_assets/serv -- Forking service' > $FINIT_CONF" + say 'Reload Finit' + #texec sh -c "initctl debug" + texec sh -c "initctl reload" + #texec sh -c "initctl status" + #texec sh -c "ps" -say 'Reload Finit' -#texec sh -c "initctl debug" -texec sh -c "initctl reload" -#texec sh -c "initctl status" -#texec sh -c "ps" + #texec sh -c "initctl status" + #texec sh -c "ps" + #texec sh -c "initctl status serv" -# Wait for process to fork, create its PID file so Finit can register -# its new PID -- this is the major difference from regular services. -sleep 2 + retry 'assert_num_children 1 serv' + retry "assert_pidfile $pidfn" 1 -#texec sh -c "initctl status" -#texec sh -c "ps" -#texec sh -c "initctl status serv" + say 'Stop the service' + texec sh -c "initctl stop serv" -retry 'assert_num_children 1 serv' + retry 'assert_num_children 0 serv' -say 'Stop the service' -texec sh -c "initctl stop serv" + say 'Start the service again' + texec sh -c "initctl start serv" -retry 'assert_num_children 0 serv' + retry 'assert_num_children 1 serv' -say 'Start the service again' -texec sh -c "initctl start serv" + say "Done, drop service from $FINIT_CONF ..." + texec sh -c "rm $FINIT_CONF" + texec sh -c "initctl reload" +} -retry 'assert_num_children 1 serv' +# shellcheck source=/dev/null +. "$TEST_DIR/tenv/lib.sh" + +test_one "/run/serv.pid" "service pid:!/run/serv.pid /test_assets/serv -- Forking service" +# This one could never be started by and monitored by Finit: it forks to +# background and does not create a PID file. Essentially it's lost to +# Finit, and any other sane process monitor. +#test_one "/run/serv.pid" "service pid:/run/serv.pid /test_assets/serv -p -- Forking service w/o PID file" +test_one "/run/serv.pid" "service pid:/run/serv.pid /test_assets/serv -n -- Foreground service w/o PID file" +test_one "/run/serv.pid" "service /test_assets/serv -n -p -- Foreground service w/ PID file" +test_one "/run/servy.pid" "service pid:/run/servy.pid /test_assets/serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file" diff --git a/test/tenv/lib.sh b/test/tenv/lib.sh index ae25f41d..4e066fbf 100755 --- a/test/tenv/lib.sh +++ b/test/tenv/lib.sh @@ -32,6 +32,12 @@ assert_new_pid() assert "Finit has registered new PID" "$(texec initctl |grep $1 |awk '{print $1}')" -eq "$(texec cat $2)" } +# shellcheck disable=SC2086 +assert_pidfile() +{ + assert "Process has PID file" "$(texec find $1 2>/dev/null)" +} + # shellcheck disable=SC2154 texec() { @@ -157,6 +163,10 @@ log "$color_reset" 'Setup of test environment done' '' finit_pid=$(retry "pgrep -P $finit_ppid") +if type test_setup > /dev/null 2>&1 ; then + test_setup +fi + #tty=/dev/$(texec cat /sys/class/tty/console/active) #texec cat "$tty" & #sleep 1