X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-utils.git;a=blobdiff_plain;f=cprogs%2Fcgi-fcgi-interp.c;h=f59640f4305eb86342d135462f7aa02e3a44e2c5;hp=fb6dfe3ba04f3c66b0fdf9f937c918392c96a20e;hb=fa842b6dae3eeda6067a3cb5c774d311e4f1b3fc;hpb=0bf8743de38627f4ab31f9f938ccfa7c6d4628e8 diff --git a/cprogs/cgi-fcgi-interp.c b/cprogs/cgi-fcgi-interp.c index fb6dfe3..f59640f 100644 --- a/cprogs/cgi-fcgi-interp.c +++ b/cprogs/cgi-fcgi-interp.c @@ -138,6 +138,9 @@ #include #include #include +#include +#include +#include #include @@ -191,6 +194,7 @@ static const struct cmdinfo cmdinfos[]= { static uid_t us; static const char *run_base, *script, *socket_path; +static int stderr_copy; static bool find_run_base_var_run(void) { struct stat stab; @@ -408,6 +412,11 @@ static void tidy_garbage(void) { if (r) errx(127,"close lock (%s)", lock_path); } +static void make_stderr_copy(void) { + stderr_copy = dup(2); + if (stderr_copy < 0) err(127,"dup stderr (for copy for stage2)"); +} + static void shbang_opts(const char *const **argv_io, const struct cmdinfo *cmdinfos) { myopt(argv_io, cmdinfos); @@ -416,12 +425,21 @@ static void shbang_opts(const char *const **argv_io, if (!interp) errx(127,"need interpreter argument"); } +/* stage2 predeclarations */ +static void record_baseline_time(void); +static void become_pgrp(void); +static void setup_handlers(void); +static void spawn_script(void); +static void queue_alarm(void); +static void await_something(void); + int main(int argc, const char *const *argv) { const char *smashedopt, *us; + int r; us = argv[0]; - if (argv>=4 && !strcmp(argv[1],"--stage2")) { + if (argc>=4 && !strcmp(argv[1],"--stage2")) { ++argv; stage2 = 1; @@ -432,9 +450,9 @@ int main(int argc, const char *const *argv) { r = open("/dev/null",O_WRONLY); if (r<0) err(127,"open /dev/null as stdout"); if (r>=3) close(r); - else if (r!=) errx(127,"open /dev/null gave bad fd %d",r); + else if (r!=1) errx(127,"open /dev/null for stdout gave bad fd %d",r); - sock_path = *++argv; + socket_path = *++argv; } if (argc>=2 && @@ -491,18 +509,20 @@ int main(int argc, const char *const *argv) { if (isgarbage) tidy_garbage(); + make_stderr_copy(); + execlp("cgi-fcgi", "cgi-fcti", "-connect", socket_path, us, "--stage2", m_asprintf("-c%d", check_interval), - m_asprintf("%d", copy_stderr), socket_path, + m_asprintf("%d", stderr_copy), socket_path, interp, script, (char*)0); err(127,"exec cgi-fcgi"); } else { /*stage2*/ - check_baseline_time(); + record_baseline_time(); become_pgrp(); setup_handlers(); spawn_script(); @@ -520,13 +540,13 @@ int main(int argc, const char *const *argv) { * and the main program has signals blocked except in sigsuspend, so * we don't need to worry about async-signal-safety, or errno. */ -static struct stab baseline_time; +static struct stat baseline_time; static pid_t script_child, stage2_pgrp; static bool out_of_date; -void check_baseline_time(void) { +static void record_baseline_time(void) { #ifdef st_mtime - int r = clock_gettime(CLOCK_REALTIME, &baselime_time.st_mtim); + int r = clock_gettime(CLOCK_REALTIME, &baseline_time.st_mtim); if (r) err(127,"(stage2) clock_gettime"); #else baseline_time.st_mtime = time(NULL); @@ -543,6 +563,50 @@ static void become_pgrp(void) { if (r) err(127,"(stage2) setpgid"); } +static void atexit_handler(void) { + int r; + + sighandler_t sigr = signal(SIGTERM,SIG_IGN); + if (sigr == SIG_ERR) warn("(stage2) signal(SIGTERM,SIG_IGN)"); + + r = killpg(stage2_pgrp,SIGTERM); + if (r) warn("(stage) killpg failed"); +} + +static void alarm_handler(int dummy) { + if (out_of_date) + /* second timeout */ + exit(0); /* transfers control to atexit_handler */ + + out_of_date = check_garbage_vs(&baseline_time); + queue_alarm(); +} + +static void child_handler(int dummy) { + for (;;) { + int status; + pid_t got = waitpid(-1, &status, WNOHANG); + if (got == (pid_t)-1) err(127,"(stage2) waitpid"); + if (got != script_child) { + warn("(stage2) waitpid got status %d for unknown child [%lu]", + status, (unsigned long)got); + continue; + } + if (WIFEXITED(status)) { + int v = WEXITSTATUS(status); + if (v) warn("program failed with error exit status %d", v); + exit(status); + } else if (WIFSIGNALED(status)) { + int s = WTERMSIG(status); + err(status & 0xff, "program died due to fatal signal %s%s", + strsignal(s), WCOREDUMP(status) ? " (core dumped" : ""); + } else { + err(127, "program failed with crazy wait status %#x", status); + } + } + exit(127); +} + static void setup_handlers(void) { struct sigaction sa; int r; @@ -568,25 +632,6 @@ static void setup_handlers(void) { if (r) err(127,"(stage2) sigaction SIGCHLD"); } -static void atexit_handler(void) { - int r; - - sighandler_t sigr = signal(SIGTERM,SIG_IGN); - if (sigr == SIG_ERR) warn("(stage2) signal(SIGTERM,SIG_IGN)"); - - r = killpg(stage2_pgrp,SIGTERM); - if (r) warn("(stage) killpg failed"); -} - -static void alarm_handler(int dummy) { - if (out_of_date) - /* second timeout */ - exit(0); /* transfers control to atexit_handler */ - - out_of_date = check_garbage_vs(&baseline_time); - queue_alarm(); -} - static void spawn_script(void) { script_child = fork(); if (script_child == (pid_t)-1) err(127,"(stage2) fork"); @@ -600,3 +645,15 @@ static void spawn_script(void) { static void queue_alarm(void) { alarm(check_interval); } + +static void await_something(void) { + int r; + sigset_t mask; + sigemptyset(&mask); + + for (;;) { + r = sigsuspend(&mask); + assert(r==-1); + if (r != EINTR) err(127,"(stage2) sigsuspend"); + } +}