From 84351242462d8d501402ee63536b4f56be03e1c7 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 30 Mar 2016 02:25:51 +0100 Subject: [PATCH] cgi-fcgi-perl: wip new stderr logging, does not work properly right now --- cprogs/cgi-fcgi-interp.c | 77 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/cprogs/cgi-fcgi-interp.c b/cprogs/cgi-fcgi-interp.c index 1612e4f..2c157d2 100644 --- a/cprogs/cgi-fcgi-interp.c +++ b/cprogs/cgi-fcgi-interp.c @@ -637,10 +637,10 @@ int main(int argc, const char *const *argv) { record_baseline_time(); become_pgrp(); - start_logging(); setup_handlers(); spawn_script(); queue_alarm(); + start_logging(); await_something(); abort(); @@ -657,6 +657,7 @@ int main(int argc, const char *const *argv) { static struct stat baseline_time; static pid_t script_child, stage2_pgrp; static bool out_of_date; +static int errpipe; static void record_baseline_time(void) { stab_mtimenow(&baseline_time); @@ -743,13 +744,32 @@ static void setup_handlers(void) { } static void spawn_script(void) { + int r; + int errpipes[2]; + + r = pipe(errpipes); + if (r) diee("(stage2) pipe"); + script_child = fork(); if (script_child == (pid_t)-1) diee("(stage2) fork"); if (!script_child) { + r = close(errpipes[0]); + if (r) diee("(stage2 child) close errpipes[0]"); + + r = dup2(errpipes[1], 2); + if (r != 2) diee("(stage2 child) dup2 stderr"); + execlp(interp, interp, script, (char*)0); diee("(stage2) exec interpreter (`%s', for `%s')\n",interp,script); } + + r = close(errpipes[1]); + if (r) diee("(stage2) close errpipes[1]"); + + errpipe = errpipes[0]; + r = fcntl(errpipe, F_SETFL, O_NONBLOCK); + if (r) diee("(stage2) set errpipe nonblocking"); } static void queue_alarm(void) { @@ -765,14 +785,63 @@ static void start_logging(void) { if (r!=2) diee("dup2 stdout to stderr"); } +static void errpipe_readable(void) { + static char buf[1024]; + static int pending; + + for (;;) { + int avail = sizeof(buf) - pending; + ssize_t got = read(errpipe, buf+pending, avail); + if (got==-1) { + if (errno==EINTR) continue; + else if (errno==EWOULDBLOCK || errno==EAGAIN) /*ok*/; + else diee("(stage2) errpipe read"); + got = 0; + } else if (got==0) { + warning("program closed its stderr fd"); + errpipe = -1; + return; + } + int scanned = pending; + pending += got; + int eaten = 0; + for (;;) { + const char *newline = memchr(buf+scanned, '\n', pending-scanned); + int printupto, eat; + if (newline) { + printupto = newline-buf; + eat = printupto + 1; + } else if (!eaten && pending==sizeof(buf)) { /* overflow */ + printupto = pending; + eat = printupto; + } else { + break; + } + syslog(LOG_ERR,"stderr: %.*s", printupto-eaten, buf+eaten); + eaten += eat; + } + pending -= eaten; + memmove(buf, buf+eaten, pending); + } +} + static void await_something(void) { int r; sigset_t mask; sigemptyset(&mask); for (;;) { - r = sigsuspend(&mask); - assert(r==-1); - if (errno != EINTR) diee("(stage2) sigsuspend"); + fd_set rfds; + FD_ZERO(&rfds); + if (errpipe >= 0) + FD_SET(errpipe, &rfds); + r = pselect(errpipe+1, &rfds,0,0, 0, &mask); + if (r==-1) { + if (errno != EINTR) diee("(stage2) sigsuspend"); + continue; + } + assert(r>0); + assert(FD_ISSET(errpipe, &rfds)); + errpipe_readable(); } } -- 2.30.2