From ebd2c4c01aaef67995f538ac75e2ff56e7c7779e Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Wed, 7 Sep 2022 04:45:30 -0400 Subject: [PATCH] scriptd: Wait to notify s6 until script completes. The motivation here is to be safe in cases where the script is setting up firewall rules or tunnels and where subsequent tasks require these to be complete before starting. I expect that this is a common case where a script is used. The implementation behaves almost identically to how ifchd works. --- scriptd.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/scriptd.c b/scriptd.c index a973098..c746fea 100644 --- a/scriptd.c +++ b/scriptd.c @@ -21,22 +21,27 @@ extern char **environ; bool valid_script_file = false; // Runs the 'script_file'-specified script. Called from ndhc process. +// Blocks until the script finishes running. void request_scriptd_run(void) { if (!valid_script_file) return; - static char buf[] = "\n"; - ssize_t r = safe_write(scriptdSock[0], buf, 1); + char nl = '\n'; + ssize_t r = safe_write(scriptdSock[0], &nl, 1); if (r < 0 || (size_t)r != 1) suicide("%s: (%s) write failed: %zd", client_config.interface, __func__, r); -} - -static void run_script(void) -{ - pid_t pid; - int ret = nk_pspawn(&pid, script_file, NULL, NULL, NULL, environ); - if (ret) log_line("posix_spawn failed for '%s': %s\n", script_file, strerror(ret)); + char buf[16]; + r = safe_recv(scriptdSock[0], buf, sizeof buf, 0); + if (r == 0) { + // Remote end hung up. + exit(EXIT_SUCCESS); + } else if (r < 0) { + suicide("%s: (%s) recvmsg failed: %s", client_config.interface, + __func__, strerror(errno)); + } + if (r != 1 || buf[0] != '+') + suicide("%s: Bad response from recv", __func__); } static void process_client_socket(void) @@ -63,7 +68,23 @@ static void process_client_socket(void) if (buflen > 1 || buf[0] != '\n') exit(EXIT_SUCCESS); buflen = 0; - run_script(); + pid_t pid; + int ret = nk_pspawn(&pid, script_file, NULL, NULL, NULL, environ); + if (ret) log_line("posix_spawn failed for '%s': %s\n", script_file, strerror(ret)); + int wstatus; + ret = waitpid(pid, &wstatus, 0); + if (ret == -1) + suicide("%s: (%s) waitpid failed: %s", client_config.interface, + __func__, strerror(errno)); + + char c = '+'; + ssize_t rs = safe_write(scriptdSock[1], &c, 1); + if (rs == 0) { + // Remote end hung up. + exit(EXIT_SUCCESS); + } else if (rs < 0) + suicide("%s: (%s) error writing to scriptd -> ndhc socket: %s", + client_config.interface, __func__, strerror(errno)); } static void do_scriptd_work(void) @@ -93,9 +114,7 @@ static void do_scriptd_work(void) static void signal_handler(int signo) { int serrno = errno; - if (signo == SIGCHLD) { - while (waitpid(-1, NULL, WNOHANG) > 0); - } else if (signo == SIGINT || signo == SIGTERM) { + if (signo == SIGINT || signo == SIGTERM) { _exit(EXIT_FAILURE); } errno = serrno; @@ -104,7 +123,7 @@ static void signal_handler(int signo) static void setup_signals_scriptd(void) { static const int ss[] = { - SIGCHLD, SIGINT, SIGTERM, SIGKILL + SIGINT, SIGTERM, SIGKILL }; sigset_t mask; if (sigprocmask(0, 0, &mask) < 0)