record_baseline_time();
become_pgrp();
- start_logging();
setup_handlers();
spawn_script();
queue_alarm();
+ start_logging();
await_something();
abort();
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);
}
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) {
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();
}
}