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.
This commit is contained in:
Nicholas J. Kain 2022-09-07 04:45:30 -04:00
parent 4d739acbdd
commit ebd2c4c01a
No known key found for this signature in database

View File

@ -21,22 +21,27 @@ extern char **environ;
bool valid_script_file = false; bool valid_script_file = false;
// Runs the 'script_file'-specified script. Called from ndhc process. // Runs the 'script_file'-specified script. Called from ndhc process.
// Blocks until the script finishes running.
void request_scriptd_run(void) void request_scriptd_run(void)
{ {
if (!valid_script_file) return; if (!valid_script_file) return;
static char buf[] = "\n"; char nl = '\n';
ssize_t r = safe_write(scriptdSock[0], buf, 1); ssize_t r = safe_write(scriptdSock[0], &nl, 1);
if (r < 0 || (size_t)r != 1) if (r < 0 || (size_t)r != 1)
suicide("%s: (%s) write failed: %zd", client_config.interface, suicide("%s: (%s) write failed: %zd", client_config.interface,
__func__, r); __func__, r);
} char buf[16];
r = safe_recv(scriptdSock[0], buf, sizeof buf, 0);
static void run_script(void) if (r == 0) {
{ // Remote end hung up.
pid_t pid; exit(EXIT_SUCCESS);
int ret = nk_pspawn(&pid, script_file, NULL, NULL, NULL, environ); } else if (r < 0) {
if (ret) log_line("posix_spawn failed for '%s': %s\n", script_file, strerror(ret)); 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) 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); if (buflen > 1 || buf[0] != '\n') exit(EXIT_SUCCESS);
buflen = 0; 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) static void do_scriptd_work(void)
@ -93,9 +114,7 @@ static void do_scriptd_work(void)
static void signal_handler(int signo) static void signal_handler(int signo)
{ {
int serrno = errno; int serrno = errno;
if (signo == SIGCHLD) { if (signo == SIGINT || signo == SIGTERM) {
while (waitpid(-1, NULL, WNOHANG) > 0);
} else if (signo == SIGINT || signo == SIGTERM) {
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
errno = serrno; errno = serrno;
@ -104,7 +123,7 @@ static void signal_handler(int signo)
static void setup_signals_scriptd(void) static void setup_signals_scriptd(void)
{ {
static const int ss[] = { static const int ss[] = {
SIGCHLD, SIGINT, SIGTERM, SIGKILL SIGINT, SIGTERM, SIGKILL
}; };
sigset_t mask; sigset_t mask;
if (sigprocmask(0, 0, &mask) < 0) if (sigprocmask(0, 0, &mask) < 0)