From a6d66bfe247cdc73413d032fde3cbecf4e00ca26 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Sun, 5 Jan 2025 02:36:06 +0100 Subject: [PATCH] supervise-daemon: add s6-style readiness notification. --- sh/supervise-daemon.sh | 1 + src/supervise-daemon/supervise-daemon.c | 45 +++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/sh/supervise-daemon.sh b/sh/supervise-daemon.sh index a2881f3a9..8cdde18b5 100644 --- a/sh/supervise-daemon.sh +++ b/sh/supervise-daemon.sh @@ -43,6 +43,7 @@ supervise_start() ${no_new_privs:+--no-new-privs} \ ${command_user+--user} $command_user \ ${umask+--umask} $umask \ + ${ready+--ready} $ready \ ${supervise_daemon_args-${start_stop_daemon_args}} \ $command \ -- $command_args $command_args_foreground diff --git a/src/supervise-daemon/supervise-daemon.c b/src/supervise-daemon/supervise-daemon.c index ed60f5e46..03d6a42c9 100644 --- a/src/supervise-daemon/supervise-daemon.c +++ b/src/supervise-daemon/supervise-daemon.c @@ -82,6 +82,7 @@ enum { LONGOPT_SECBITS, LONGOPT_STDERR_LOGGER, LONGOPT_STDOUT_LOGGER, + LONGOPT_READY, }; const char *applet = NULL; @@ -115,6 +116,7 @@ const struct option longopts[] = { { "stderr", 1, NULL, '2'}, { "stdout-logger",1, NULL, LONGOPT_STDOUT_LOGGER}, { "stderr-logger",1, NULL, LONGOPT_STDERR_LOGGER}, + { "ready", 1, NULL, LONGOPT_READY}, { "reexec", 0, NULL, '3'}, longopts_COMMON }; @@ -165,6 +167,8 @@ static int devnull_fd = -1; static int stdin_fd; static int stdout_fd; static int stderr_fd; +static int ready_fd = -1; +static int ready_pipe[2]; static char *redirect_stderr = NULL; static char *redirect_stdout = NULL; static char *stderr_process = NULL; @@ -588,6 +592,9 @@ RC_NORETURN static void child_process(char *exec, char **argv) cloexec_fds_from(3); + if (ready_fd != -1) + dup2(ready_pipe[1], ready_fd); + cmdline = make_cmdline(argv); syslog(LOG_INFO, "Child command line: %s", cmdline); free(cmdline); @@ -786,6 +793,28 @@ RC_NORETURN static void supervisor(char *exec, char **argv) exit(EXIT_SUCCESS); } +static void wait_ready(void) +{ + if (ready_fd == -1) + exit(EXIT_SUCCESS); + + close(ready_pipe[1]); + /* TODO: add timeout failure and stop child supervisor */ + for (;;) { + char buf[BUFSIZ]; + int bytes = read(ready_pipe[0], buf, BUFSIZ); + if (bytes == -1 && errno != EINTR) { + eerror("%s: read failed '%s'\n", applet, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (memchr(buf, '\n', bytes)) + break; + } + + exit(EXIT_SUCCESS); +} + int main(int argc, char **argv) { int opt; @@ -1068,6 +1097,12 @@ int main(int argc, char **argv) stderr_process = optarg; break; + case LONGOPT_READY: + if (sscanf(optarg, "fd:%d", &ready_fd) != 1) + eerrorx("%s: invalid ready '%s'.", applet, optarg); + pipe(ready_pipe); + break; + case_RC_COMMON_GETOPT } @@ -1205,8 +1240,8 @@ int main(int argc, char **argv) if (child_pid == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); if (child_pid != 0) - /* first parent process, do nothing. */ - exit(EXIT_SUCCESS); + wait_ready(); + #ifdef TIOCNOTTY tty_fd = open("/dev/tty", O_RDWR); #endif @@ -1214,10 +1249,16 @@ int main(int argc, char **argv) dup2(devnull_fd, STDIN_FILENO); dup2(devnull_fd, STDOUT_FILENO); dup2(devnull_fd, STDERR_FILENO); + + if (ready_fd != -1) + close(ready_pipe[0]); + child_pid = fork(); if (child_pid == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); else if (child_pid != 0) { + if (ready_fd != -1) + close(ready_pipe[1]); c = argv; x = 0; while (c && *c) {