chiark / gitweb /
admin-initiated flush
[inn-innduct.git] / backends / innduct.c
index a1c749196099fd480acaf76c822234139a72d4bd..3da59e101c02dfc3134e71857d4e4ca8b6b71af9 100644 (file)
@@ -1,9 +1,6 @@
 /*
  * todo
- *  - reset signals TERM and INT (and HUP) in children
- *
  *  - manpage: document control master stuff
- *  - admin-initiated flush
  *
  * debugging rune:
  *  build-lfs/backends/innduct --connection-timeout=30 --no-daemon -C ../inn.conf -f `pwd`/fee sit localhost
@@ -208,6 +205,7 @@ perl -ne 'print if m/-8\<-/..m/-\>8-/; print "\f" if m/-\^L-/' backends/innduct.
 #define VA                va_list al;  va_start(al,fmt)
 #define PRINTF(f,a)       __attribute__((__format__(printf,f,a)))
 #define NORET_PRINTF(f,a) __attribute__((__noreturn__,__format__(printf,f,a)))
+#define NORET             __attribute__((__noreturn__))
 
 #define NEW(ptr)              ((ptr)= zxmalloc(sizeof(*(ptr))))
 #define NEW_DECL(type,ptr) type ptr = zxmalloc(sizeof(*(ptr)))
@@ -298,6 +296,7 @@ static void statemc_setstate(StateMachineState newsms, int periods,
 
 static void statemc_start_flush(const char *why); /* Normal => Flushing */
 static void spawn_inndcomm_flush(const char *why); /* Moved => Flushing */
+static int trigger_flush_ok(void); /* => Flushing,FLUSHING, ret 1; or ret 0 */
 
 static void article_done(Conn *conn, Article *art, int whichcount);
 
@@ -314,7 +313,7 @@ static void open_defer(void);
 static void close_defer(void);
 static void search_backlog_file(void);
 static void preterminate(void);
-static void raise_default(int signo);
+static void raise_default(int signo) NORET;
 static char *debug_report_ipf(InputFile *ipf);
 
 static void inputfile_reading_start(InputFile *ipf);
@@ -678,9 +677,16 @@ static time_t xtime(void) {
   return now;
 }
 
-static void xsigaction(int s, const struct sigaction *sa) {
-  int r= sigaction(s,sa,0);
-  if (r) sysdie("sigaction failed for \"%s\"", strsignal(s));
+static void xsigaction(int signo, const struct sigaction *sa) {
+  int r= sigaction(signo,sa,0);
+  if (r) sysdie("sigaction failed for \"%s\"", strsignal(signo));
+}
+
+static void xsigsetdefault(int signo) {
+  struct sigaction sa;
+  memset(&sa,0,sizeof(sa));
+  sa.sa_handler= SIG_DFL;
+  xsigaction(signo,&sa);
 }
 
 static void xgettimeofday(struct timeval *tv_r) {
@@ -812,11 +818,10 @@ CCMD(help) {
     fprintf(cc->out, " %s\n", ccmd->cmd);
 }
 
-CCMD(period) { period(); }
-CCMD(setintarg) { *(int*)c->xdata= atoi(arg); }
-CCMD(setint) { *(int*)c->xdata= c->xval; }
-CCMD(setint_period) { *(int*)c->xdata= c->xval; period(); }
-CCMD(dump);
+CCMD(flush) {
+  int ok= trigger_flush_ok();
+  if (!ok) fprintf(cc->out,"already flushing (state is %s)\n", sms_names[sms]);
+}
 
 CCMD(stop) {
   preterminate();
@@ -825,13 +830,23 @@ CCMD(stop) {
   abort();
 }
 
+CCMD(dump);
+
+/* messing with our head: */
+CCMD(period) { period(); }
+CCMD(setintarg) { *(int*)c->xdata= atoi(arg); }
+CCMD(setint) { *(int*)c->xdata= c->xval; }
+CCMD(setint_period) { *(int*)c->xdata= c->xval; period(); }
+
 static const ControlCommand control_commands[]= {
   { "h",             ccmd_help      },
-  { "p",             ccmd_period    },
+  { "flush",         ccmd_flush     },
   { "stop",          ccmd_stop      },
   { "dump q",        ccmd_dump, 0,0 },
   { "dump a",        ccmd_dump, 0,1 },
 
+  { "p",             ccmd_period    },
+
 #define POKES(cmd,func)                                                        \
   { cmd "sm",        func,           &sm_period_counter,       1 },    \
   { cmd "conn",      func,           &until_connect,           0 },    \
@@ -2435,24 +2450,29 @@ static void statemc_start_flush(const char *why) { /* Normal => Flushing */
   spawn_inndcomm_flush(why); /* => Flushing FLUSHING */
 }
 
-static void statemc_period_poll(void) {
-  if (!sm_period_counter) return;
-  sm_period_counter--;
-  assert(sm_period_counter>=0);
-
-  if (sm_period_counter) return;
+static int trigger_flush_ok(void) { /* => Flushing,FLUSHING, ret 1; or ret 0 */
   switch (sms) {
   case sm_NORMAL:
     statemc_start_flush("periodic"); /* Normal => Flushing; => FLUSHING */
-    break;
+    return 1;
   case sm_FLUSHFAILED:
     spawn_inndcomm_flush("retry"); /* Moved => Flushing; => FLUSHING */
-    break;
+    return 1;
   default:
-    abort();
+    return 0;
   }
 }
 
+static void statemc_period_poll(void) {
+  if (!sm_period_counter) return;
+  sm_period_counter--;
+  assert(sm_period_counter>=0);
+
+  if (sm_period_counter) return;
+  int ok= trigger_flush_ok();
+  assert(ok);
+}
+
 static int inputfile_is_done(InputFile *ipf) {
   if (!ipf) return 0;
   if (ipf->inprogress) return 0; /* new article in the meantime */
@@ -2786,11 +2806,9 @@ static int signal_self_pipe[2];
 static sig_atomic_t terminate_sig_flag;
 
 static void raise_default(int signo) {
-  struct sigaction sa;
-  memset(&sa,0,sizeof(sa));
-  sa.sa_handler= SIG_DFL;
-  xsigaction(signo,&sa);
+  xsigsetdefault(signo);
   raise(signo);
+  abort();
 }
 
 static void *sigarrived_event(oop_source *lp, int fd, oop_event e, void *u) {
@@ -2803,7 +2821,6 @@ static void *sigarrived_event(oop_source *lp, int fd, oop_event e, void *u) {
     preterminate();
     notice("terminating (%s)", strsignal(terminate_sig_flag));
     raise_default(terminate_sig_flag);
-    abort();
   }
   return OOP_CONTINUE;
 }
@@ -2811,7 +2828,8 @@ static void *sigarrived_event(oop_source *lp, int fd, oop_event e, void *u) {
 static void sigarrived_handler(int signum) {
   static char x;
   switch (signum) {
-  case SIGINT: case SIGTERM:
+  case SIGTERM:
+  case SIGINT:
     if (!terminate_sig_flag) terminate_sig_flag= signum;
     break;
   default:
@@ -2983,8 +3001,10 @@ static void postfork_stdio(FILE *f, const char *what, const char *what2) {
 static void postfork(void) {
   in_child= 1;
 
-  if (signal(SIGPIPE, SIG_DFL) == SIG_ERR)
-    sysdie("(in child) failed to reset SIGPIPE");
+  xsigsetdefault(SIGTERM);
+  xsigsetdefault(SIGINT);
+  xsigsetdefault(SIGPIPE);
+  if (terminate_sig_flag) raise(terminate_sig_flag);
 
   postfork_inputfile(main_input_file);
   postfork_inputfile(flushing_input_file);