X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=cprogs%2Fcgi-fcgi-interp.c;h=63db94b35fed7a1d3afb3f11c96858a31d3c70d7;hb=79dffd67db788e73c39722842097a3f98b2bee83;hp=5c32efe7e68871332a449376c1e8744074e15d99;hpb=d6b2996d3ff923a8374f9b1ef8936b90843fcdb8;p=chiark-utils.git diff --git a/cprogs/cgi-fcgi-interp.c b/cprogs/cgi-fcgi-interp.c index 5c32efe..63db94b 100644 --- a/cprogs/cgi-fcgi-interp.c +++ b/cprogs/cgi-fcgi-interp.c @@ -4,7 +4,7 @@ * #!/usr/bin/cgi-fcgi-interp [], */ /* - * cgi-fcgi-interp.[ch] - C helpers common to the whole of chiark-utils + * cgi-fcgi-interp.[ch] - Convenience wrapper for cgi-fcgi * * Copyright 2016 Ian Jackson * Copyright 1982,1986,1993 The Regents of the University of California @@ -145,6 +145,7 @@ #include #include #include +#include #include @@ -159,13 +160,31 @@ static int check_interval=300; static struct sha256_ctx identsc; +static bool logging; static const char *stage2; static void vmsgcore(int estatus, int errnoval, const char *fmt, va_list al) { - fputs("cgi-fcgi-interp: ",stderr); - vfprintf(stderr,fmt,al); - if (errnoval!=-1) fprintf(stderr,": %s",strerror(errnoval)); - fputc('\n',stderr); + int r; + + if (logging) { + const char *fmt_use = fmt; + char *fmt_free = 0; + if (errnoval) { + r = asprintf(&fmt_free, "%s: %%m", fmt); + if (r) { + fmt_free = 0; + } else { + fmt_use = fmt_free; + } + } + vsyslog(LOG_ERR, fmt_use, al); + free(fmt_free); + } else { + fputs("cgi-fcgi-interp: ",stderr); + vfprintf(stderr,fmt,al); + if (errnoval!=-1) fprintf(stderr,": %s",strerror(errnoval)); + fputc('\n',stderr); + } if (estatus) exit(estatus); } @@ -422,12 +441,12 @@ static bool stab_isnewer(const struct stat *a, const struct stat *b) { fprintf(stderr,"stab_isnewer mtime %lu %lu\n", (unsigned long)a->st_mtime, (unsigned long)b->st_mtime); - return a->st_mtime > &b->st_mtime; + return a->st_mtime > b->st_mtime; } static void stab_mtimenow(struct stat *out) { out->st_mtime = time(NULL); - if (baseline_time.st_mtime == (time_t)-1) diee("(stage2) time()"); + if (out->st_mtime == (time_t)-1) diee("(stage2) time()"); if (debugmode) fprintf(stderr,"stab_mtimenow mtime %lu\n", (unsigned long)out->st_mtime); @@ -525,6 +544,7 @@ static void become_pgrp(void); static void setup_handlers(void); static void spawn_script(void); static void queue_alarm(void); +static void start_logging(void); static void await_something(void); int main(int argc, const char *const *argv) { @@ -543,6 +563,9 @@ int main(int argc, const char *const *argv) { if (r<0) diee("open /dev/null as stdout"); if (r>=3) close(r); else if (r!=1) die("open /dev/null for stdout gave bad fd %d",r); + + r = close(stderrfd); + if (r) diee("close saved stderr fd"); } sha256_init(&identsc); @@ -581,7 +604,6 @@ int main(int argc, const char *const *argv) { script = *argv++; if (!script) badusage("need script argument"); - if (*argv) badusage("too many arguments"); if (!stage2) { @@ -617,6 +639,7 @@ int main(int argc, const char *const *argv) { setup_handlers(); spawn_script(); queue_alarm(); + start_logging(); await_something(); abort(); @@ -633,6 +656,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); @@ -719,27 +743,112 @@ 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) { alarm(check_interval); } +static void start_logging(void) { + int r; + + openlog(script, LOG_NOWAIT|LOG_PID, LOG_USER); + logging = 1; + r = dup2(1,2); + if (r!=2) diee("dup2 stdout to stderr"); +} + +static void errpipe_readable(void) { + static char buf[1024]; + static int pending; + + /* %: does not contain newlines + * _: empty (garbage) + */ + + /* %%%%%%%%%%%__________________ */ + /* ^ 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) return; + 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; + scanned = eaten; + } + 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(); } }