From 72302ebc377079ec656a068145e8ead5851d5b75 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 20 Aug 2022 14:23:58 +0100 Subject: [PATCH] prefork-interp: diagrams Signed-off-by: Ian Jackson --- cprogs/prefork-interp.c | 148 ++++++++++++++++++++++++++++++++++++++-- perl/Prefork.pm | 4 +- 2 files changed, 145 insertions(+), 7 deletions(-) diff --git a/cprogs/prefork-interp.c b/cprogs/prefork-interp.c index b59eed8..f0bc785 100644 --- a/cprogs/prefork-interp.c +++ b/cprogs/prefork-interp.c @@ -13,6 +13,144 @@ * ident covers only env vars specified with -E * ident covers only arguments interpreter and (if present) script */ + +/* + + + + State during service execution, process parentage and key fds + + ---- pipes, sockets + 012 descriptors + -==- fds shared + || process parentage + && session leader (daemon) + & process group leader + + CALLER + || + || + || listen watch-err/in + || call (accept) \ ,------2 + || ,-----------------------------. SERVER -----0 WATCHER(C) + CLIENT 2--=fdpassed>=---------. \ || && | && + (C) 1--=fdpassed>=---------. \ \ || inotify + 0--=fdpassed>=---------. \ \ \ || sockpath + \ \ \ \ || + | | |\ | || + | | | \ | || + | \ | \ \ || + \ \ \ \ MONITOR & + \ \ \ `12 || | + \ \ \ || | + \ \ \ || |execterm + \ \ \ || | + \ \ \ || | + \ \ 2 || | + \ 1 EXECUTOR + 0 + + Control flow and causality + + | - \ / process control flow + ... causes mediated by fds or other IPC etc. + && session leader (daemon) + & process group leader + + CALLER + | + |fork/exec + | + CLIENT(C) + tidy up stale sockets etc. + acquire lock + create listening socket + | + fork/daemonise + | `------------------. + | WATCHER(C) && + | + make "fake" initial call socketpair + | + fork/exec + | `------. + | SCRIPT (setup) + | | + | script initialisation + | | + | identify fds from envirnment + | open syslog + | | + | dzemonize + | ,...../ | + waitpid | + | fork for initial service + | |child |parent + | | | + | | SCRIPT [server] && + | | | + | | ** accept / event loop ** + | | / \ \ \ + | | accepted? \ \ \idle timeout? + | | | \ \ \ + | | fork child \ \ \ + | | _________/ watch | |watch stderr eof? + | |/ stderr| | | + | SCRIPT [monitor] | | | + | | log msg | | + | send greeting | | | + read greeting | | | | + | | exit + release lock | + | | + send fds.... | + | receive fds + | | + | fork for executor + | | \ + | | \child + | | \ + | | setpgrp & + | | execute service + | | | + | wait for read | + | (select) | + | | | | + | | exits + | | kernel closes execterm + | | ,......./| + | execterm? | + | | zombie + | | ,....../ + | waitpid + | | + | send exit status + read exit status + + + Or, if client is killed + + | | | + | wait for read | + | (select) | + | | | | + exits | | + | | | + kernel closes | | + \....| | + call? | + | | + kill whole pgrp... | + | killled + | zombie + | ,....../ + waitpid + | + send exit status + die due to SIGPIPE + + + */ /* * Process structure: * client (C wrapper) connects to server @@ -59,7 +197,7 @@ * runs in loop accepting and forking, * reaping and limiting children (incl init monitor) * reports failures of monitors to syslog - * + * * [client (C wrapper)] if client connect succeeds: * now fd: call(client-end) * sends message with: cmdline, env @@ -156,7 +294,7 @@ static void propagate_exit_status(int status, const char *what) { r = sigaction(sig, &sa, 0); if (r) diee("failed to reset signal handler while propagating %s", signame); - + sigset_t sset; sigemptyset(&sset); sigaddset(&sset, sig); @@ -297,7 +435,7 @@ static void prepare_data(size_t *len, char **buf, *buf += dl; } } - + static void prepare_length(size_t *len, char **buf, size_t dl_sz) { if (dl_sz > UINT32_MAX) die_data_overflow(); uint32_t dl = htonl(dl_sz); @@ -475,7 +613,7 @@ static FILE *connect_existing(void) { static void watcher_cb_stdin(uv_poll_t *handle, int status, int events) { char c; int r; - + if ((errno = -status)) diee("watcher: poll stdin"); for (;;) { r= read(0, &c, 1); @@ -685,7 +823,7 @@ static void make_executor_argv(const char *const *argv) { EACH_NEW_ARG( *out++ = arg; ); *out++ = 0; -} +} int main(int argc_unused, const char *const *argv) { process_opts(&argv); diff --git a/perl/Prefork.pm b/perl/Prefork.pm index f70edd4..2ee8e57 100644 --- a/perl/Prefork.pm +++ b/perl/Prefork.pm @@ -9,7 +9,7 @@ use strict; use Carp; use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); use IO::FDPass; -use POSIX qw(_exit setsid :sys_wait_h :errno_h); +use POSIX qw(_exit setsid :sys_wait_h :errno_h :signal_h); use Sys::Syslog qw(openlog syslog LOG_INFO LOG_ERR LOG_WARNING); our $logger; @@ -224,7 +224,7 @@ sub initialisation_complete { my $got = waitpid -1, ($full ? 0 : WNOHANG); $got >= 0 or fail_log("failed to wait for monitor(s): $!"); if ($got) { - if ($?) { + if ($? && $? != SIGPIPE) { syslog(LOG_WARNING, "$0 prefork [$$]: monitor process [$got] failed with wait status $?"); } -- 2.30.2