chiark / gitweb /
wip control
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Wed, 28 Apr 2010 00:31:02 +0000 (01:31 +0100)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Wed, 28 Apr 2010 00:31:02 +0000 (01:31 +0100)
backends/innduct.c

index 014447e..e9da15b 100644 (file)
@@ -1,4 +1,14 @@
 /*
+ * todo
+ *  - actually do something with readable on control master
+ *  - option for realsockdir
+ *  - manpage: document control master stuff
+ *  - manpage: innconf is used for communicating with innd
+ *  - debug this:
+ *      build-lfs/backends/innduct --no-daemon -f `pwd`/fee sit dom
+ */
+
+/*
  * Newsfeeds file entries should look like this:
  *     host.name.of.site[/exclude,exclude,...]\
  *             :pattern,pattern...[/distribution,distribution...]\
@@ -163,6 +173,7 @@ perl -ne 'print if m/-8\<-/..m/-\>8-/; print "\f" if m/-\^L-/' backends/innduct.
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
@@ -173,6 +184,7 @@ perl -ne 'print if m/-8\<-/..m/-\>8-/; print "\f" if m/-\^L-/' backends/innduct.
 #include <stdarg.h>
 #include <assert.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <glob.h>
 #include <time.h>
 #include <math.h>
@@ -304,7 +316,7 @@ static oop_rd_call peer_rd_err, peer_rd_ok;
 /* when changing defaults, remember to update the manpage */
 
 static const char *sitename, *remote_host;
-static const char *feedfile;
+static const char *feedfile, *realsockdir="/tmp/innduct.control";
 static int quiet_multiple=0;
 static int become_daemon=1;
 static int try_stream=1;
@@ -458,7 +470,9 @@ struct Conn {
 static oop_source *loop;
 static ConnList conns;
 static ArticleList queue;
-static char *path_lock, *path_flushing, *path_defer, *globpat_backlog;
+static char *path_lock, *path_flushing, *path_defer, *path_control;
+static char *globpat_backlog;
+static pid_t self_pid;
 
 /* statemc_init initialises */
 static StateMachineState sms;
@@ -466,6 +480,9 @@ static FILE *defer;
 static InputFile *main_input_file, *flushing_input_file, *backlog_input_file;
 static int sm_period_counter;
 
+/* control_init initialises */
+static int control_master;
+
 /* initialisation to 0 is good */
 static int until_connect, until_backlog_nextscan;
 static double accept_proportion;
@@ -479,6 +496,7 @@ static void logcore(int sysloglevel, const char *fmt, ...) {
   if (become_daemon) {
     vsyslog(sysloglevel,fmt,al);
   } else {
+    if (self_pid) fprintf(stderr,"[%lu] ",(unsigned long)self_pid);
     vfprintf(stderr,fmt,al);
     putc('\n',stderr);
   }
@@ -527,7 +545,7 @@ diewrap(fatal,    " fatal",    LOG_ERR,     -1,    12);
 logwrap(syswarn,  " warning",  LOG_WARNING, errno);
 logwrap(warn,     " warning",  LOG_WARNING, -1);
 
-logwrap(notice,   "",          LOG_NOTICE,  -1);
+logwrap(notice,   " notice",   LOG_NOTICE,  -1);
 logwrap(info,     " info",     LOG_INFO,    -1);
 logwrap(debug,    " debug",    LOG_DEBUG,   -1);
 
@@ -686,6 +704,100 @@ static int isewouldblock(int errnoval) {
   return errnoval==EWOULDBLOCK || errnoval==EAGAIN;
 }
 
+
+/*========== command and control connections ==========*/
+
+#define NOCONTROL(...) do{                                             \
+    syswarn("no control socket, because failed to " __VA_ARGS__);      \
+    goto nocontrol;                                                    \
+  }while(0)
+
+static void control_init(void) {
+  char *real=0;
+  
+  union {
+    struct sockaddr sa;
+    struct sockaddr_un un;
+  } sa;
+
+  memset(&sa,0,sizeof(sa));
+  int maxlen= sizeof(sa.un.sun_path);
+
+  int reallen= readlink(path_control, sa.un.sun_path, maxlen);
+  if (reallen<0) {
+    if (errno != ENOENT)
+      NOCONTROL("readlink control socket symlink path %s", path_control);
+  }
+  if (reallen >= maxlen) {
+    debug("control socket symlink path too long (r=%d)",reallen);
+    xunlink(path_control, "old (overlong) control socket symlink");
+    reallen= -1;
+  }
+  
+  if (reallen<0) {
+    struct stat stab;
+    int r= lstat(realsockdir,&stab);
+    if (r) {
+      if (errno != ENOENT) NOCONTROL("lstat real socket dir %s", realsockdir);
+
+      r= mkdir(realsockdir, 0700);
+      if (r) NOCONTROL("mkdir real socket dir %s", realsockdir);
+
+    } else {
+      uid_t self= geteuid();
+      if (!S_ISDIR(stab.st_mode) ||
+         stab.st_uid != self ||
+         stab.st_mode & 0077) {
+       warn("no control socket, because real socket directory"
+            " is somehow wrong (ISDIR=%d, uid=%lu (exp.%lu), mode %lo)",
+            !!S_ISDIR(stab.st_mode),
+            (unsigned long)stab.st_uid, (unsigned long)self,
+            (unsigned long)stab.st_mode & 0777UL);
+       goto nocontrol;
+      }
+    }
+
+    real= xasprintf("%s/s%lx.%lx", realsockdir,
+                   (unsigned long)xtime(), (unsigned long)self_pid);
+    int reallen= strlen(real);
+
+    if (reallen >= maxlen) {
+      warn("no control socket, because tmpnam gave overly-long path"
+          " %s", real);
+      goto nocontrol;
+    }
+    r= symlink(real, path_control);
+    if (r) NOCONTROL("make control socket path %s a symlink to real"
+                    " socket path %s", path_control, real);
+    memcpy(sa.un.sun_path, real, reallen);
+  }
+
+  int r= unlink(sa.un.sun_path);
+  if (r && errno!=ENOENT)
+    NOCONTROL("remove old real socket %s", sa.un.sun_path);
+
+  control_master= socket(PF_UNIX, SOCK_STREAM, 0);
+  if (control_master<0) NOCONTROL("create new control socket");
+
+  sa.un.sun_family= AF_UNIX;
+  int sl= strlen(sa.un.sun_path) + offsetof(struct sockaddr_un, sun_path);
+  r= bind(control_master, &sa.sa, sl);
+  if (r) NOCONTROL("bind to real socket path %s", sa.un.sun_path);
+
+  r= listen(control_master, 5);
+  if (r) NOCONTROL("listen");
+
+  //loop->on_fd(loop, control_master, OOP_READ, control_master_readable, 0);
+  info("control socket ok, real path %s", sa.un.sun_path);
+
+  return;
+
+ nocontrol:
+  free(real);
+  xclose_perhaps(&control_master, "control master",0);
+  return;
+}
+
 /*========== management of connections ==========*/
 
 static void conn_closefd(Conn *conn, const char *msgprefix) {
@@ -1890,15 +2002,9 @@ static void startup_set_input_file(InputFile *f) {
   inputfile_reading_start(f);
 }
 
-static void statemc_init(void) {
-  struct stat stab, stabf;
-
-  path_lock=        xasprintf("%s_lock",      feedfile);
-  path_flushing=    xasprintf("%s_flushing",  feedfile);
-  path_defer=       xasprintf("%s_defer",     feedfile);
-  globpat_backlog=  xasprintf("%s_backlog*",  feedfile);
-
+static void statemc_lock(void) {
   int lockfd;
+  struct stat stab, stabf;
   
   for (;;) {
     lockfd= open(path_lock, O_CREAT|O_RDWR, 0600);
@@ -1926,8 +2032,6 @@ static void statemc_init(void) {
 
     xclose(lockfd, "stale lockfile ", path_lock);
   }
-  pid_t self= getpid();
-  if (self==-1) sysdie("getpid");
 
   FILE *lockfile= fdopen(lockfd, "w");
   if (!lockfile) sysdie("fdopen lockfile");
@@ -1936,21 +2040,26 @@ static void statemc_init(void) {
   if (r) sysdie("truncate lockfile to write new info");
 
   if (fprintf(lockfile, "pid %ld\nsite %s\nfeedfile %s\nfqdn %s\n",
-             (unsigned long)self, sitename, feedfile, remote_host) == EOF ||
+             (unsigned long)self_pid,
+             sitename, feedfile, remote_host) == EOF ||
       fflush(lockfile))
     sysfatal("write info to lockfile %s", path_lock);
 
   debug("startup: locked");
+}
+
+static void statemc_init(void) {
+  struct stat stabdefer;
 
   search_backlog_file();
 
   int defer_noent;
-  xlstat_isreg(path_defer, &stab, &defer_noent, "defer file");
+  xlstat_isreg(path_defer, &stabdefer, &defer_noent, "defer file");
   if (defer_noent) {
     debug("startup: ductdefer ENOENT");
   } else {
-    debug("startup: ductdefer nlink=%ld", (long)stab.st_nlink);
-    switch (stab.st_nlink==1) {
+    debug("startup: ductdefer nlink=%ld", (long)stabdefer.st_nlink);
+    switch (stabdefer.st_nlink==1) {
     case 1:
       open_defer(); /* so that we will later close it and rename it */
       break;
@@ -1960,7 +2069,7 @@ static void statemc_init(void) {
       break;
     default:
       die("defer file %s has unexpected link count %d",
-         path_defer, stab.st_nlink);
+         path_defer, stabdefer.st_nlink);
     }
   }
 
@@ -2502,7 +2611,7 @@ EVERY(filepoll, 5,0, ({
 }));
 
 static char *debug_report_ipf(InputFile *ipf) {
-  if (!ipf) return xasprintf("-");
+  if (!ipf) return xasprintf("none");
 
   const char *slash= strrchr(ipf->path,'/');
   const char *path= slash ? slash+1 : ipf->path;
@@ -2521,7 +2630,7 @@ EVERY(period, -1,0, ({
   debug("PERIOD"
        " sms=%s[%d] conns=%d queue=%d until_connect=%d"
        " input_files main:%s old:%s flushing:%s"
-       " children connecting=%ld inndcomm_child=%ld"
+       " children connecting=%ld inndcomm=%ld"
        ,
        sms_names[sms], sm_period_counter,
          conns.count, queue.count, until_connect,
@@ -2816,6 +2925,12 @@ int main(int argc, char **argv) {
 
   /* set things up */
 
+  path_lock=        xasprintf("%s_lock",      feedfile);
+  path_flushing=    xasprintf("%s_flushing",  feedfile);
+  path_defer=       xasprintf("%s_defer",     feedfile);
+  path_control=     xasprintf("%s_control",   feedfile);
+  globpat_backlog=  xasprintf("%s_backlog*",  feedfile);
+
   oop_source_sys *sysloop= oop_sys_new();
   if (!sysloop) sysdie("could not create liboop event loop");
   loop= (oop_source*)sysloop;
@@ -2850,8 +2965,15 @@ int main(int argc, char **argv) {
     if (child2) _exit(0);
   }
 
+  self_pid= getpid();
+  if (self_pid==-1) sysdie("getpid");
+
+  statemc_lock();
+
   notice("starting");
 
+  control_init();
+
   if (!filemon_method_init()) {
     warn("no file monitoring available, polling");
     filepoll_schedule();