From c58bd533b721a281cf667d3261d9b1eb38f33cc3 Mon Sep 17 00:00:00 2001 From: Marcello Barnaba Date: Mon, 20 Apr 2026 22:33:13 +0000 Subject: [PATCH] main: add -F flag to stay in foreground MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fork() at initialize() time detaches services from its launcher and exits the parent, which breaks every process supervisor (docker, systemd with Type=simple, tini, ...) that expects the main process to remain on PID 1 and receive signals directly. With -F set, main() parses the flag before initialize() runs and the fork block in initialize() is skipped; stdin/out/err stay wired to whatever the supervisor attached, and signals land on the services process itself instead of being lost to the gone parent. Everything else (setpgid, pidfile write, signal handlers) runs exactly as before — the only behavioural difference is that services doesn't daemonize. Without -F the old behaviour is preserved bit-for-bit. Build clean: gcc -Wall -Wshadow -Wcast-align -Wsign-compare, 0 warnings. --- src/main.c | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/main.c b/src/main.c index d203b7a..35509f1 100644 --- a/src/main.c +++ b/src/main.c @@ -100,6 +100,11 @@ int global_force_backup_count = 0; /* Contains a message as to why services is terminating */ static char QUIT_MESSAGE[BUFSIZE]; +/* Set via -F on the command line — skip the fork() detachment in + * initialize() so services stays on PID 1 under a process supervisor + * (docker, systemd, etc) that expects the main process not to daemonize. */ +static BOOL foreground = FALSE; + /* How many database expirations did we go through? */ static unsigned long int expire_count = 1; @@ -237,17 +242,25 @@ static BOOL initialize() { region_init(); - /* Detach ourselves. */ + /* Detach ourselves — unless -F was given, in which case we stay + * attached so the process supervisor (docker, systemd, ...) sees + * services as the main process and can deliver signals to it. */ + if (!foreground) { - if ((pid = fork()) < 0) { + if ((pid = fork()) < 0) { - perror("fork()"); - return FALSE; + perror("fork()"); + return FALSE; + } + else if (pid != 0) { + + fprintf(stderr, "\nRunning in background (pid: %d)\n\n", pid); + exit(EXIT_SUCCESS); + } } - else if (pid != 0) { + else { - fprintf(stderr, "\nRunning in background (pid: %d)\n\n", pid); - exit(EXIT_SUCCESS); + fprintf(stderr, "\nRunning in foreground (pid: %d)\n\n", (int) getpid()); } if (setpgid(0, 0) < 0) { @@ -579,6 +592,24 @@ int main(int ac, char **av, char **envp) { chdir(buf); } + /* Parse the handful of flags we accept. Keep this trivial: services has + * historically taken no arguments. */ + { + int i; + + for (i = 1; i < ac; i++) { + + if (strcmp(av[i], "-F") == 0) + foreground = TRUE; + else { + + fprintf(stderr, "Usage: %s [-F]\n", av[0]); + fprintf(stderr, " -F run in foreground (do not fork at startup)\n"); + return EXIT_FAILURE; + } + } + } + time(&NOW); /* Initialization stuff. */