chiark / gitweb /
Provide MGF macros.
[tripe] / client.c
index e78f86e7829fae3e5593c34b38d1b750746506a5..8890f6c0682b3081b63c2146464f626793e73fac 100644 (file)
--- a/client.c
+++ b/client.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: client.c,v 1.2 2001/02/04 01:17:54 mdw Exp $
+ * $Id: client.c,v 1.8 2001/06/19 22:09:37 mdw Exp $
  *
  * Client for TrIPE
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: client.c,v $
+ * Revision 1.8  2001/06/19 22:09:37  mdw
+ * Move the program name to the right place when constructing the arguments
+ * to pass to a new server.
+ *
+ * Revision 1.7  2001/02/22 09:07:54  mdw
+ * Write a pidfile on request, and delete it when finished.
+ *
+ * Revision 1.6  2001/02/22 09:06:08  mdw
+ * Fix logfile rotation to avoid program collapse.
+ *
+ * Revision 1.5  2001/02/16 21:23:39  mdw
+ * Use reliable signal handling for reopening logs.
+ *
+ * Revision 1.4  2001/02/06 09:34:53  mdw
+ * Change ERR response to FAIL for consistency with other programs.
+ *
+ * Revision 1.3  2001/02/04 17:10:15  mdw
+ * Reopen logfiles on receipt of @SIGHUP@ (not done very well).  Don't
+ * change directory -- just mangle pathnames instead.
+ *
  * Revision 1.2  2001/02/04 01:17:54  mdw
  * Create a configuration header file to tidy up command lines.
  *
 #include <mLib/alloc.h>
 #include <mLib/darray.h>
 #include <mLib/dstr.h>
-#include <mLib/lbuf.h>
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
 #include <mLib/report.h>
 #include <mLib/sel.h>
 #include <mLib/selbuf.h>
+#include <mLib/sig.h>
 #include <mLib/str.h>
 
 #include "util.h"
 
 /*----- Static variables --------------------------------------------------*/
 
+static const char *pidfile = 0;
+static const char *logname = 0;
 static FILE *logfp = 0;
 static unsigned f = 0;
 static int fd;
@@ -103,9 +125,8 @@ static int fd;
 
 static void reap(int sig)
 {
-  int s;
   int e = errno;
-  while (waitpid(-1, &s, WNOHANG) > 0)
+  while (waitpid(-1, 0, WNOHANG) > 0)
     ;
   errno = e;
 }
@@ -151,7 +172,7 @@ static void cline(char *p, void *b)
       writelog("error", d.buf);
       dstr_destroy(&d);
     }
-  } else if (strcmp(q, "ERR") == 0)
+  } else if (strcmp(q, "FAIL") == 0)
     die(EXIT_FAILURE, "%s", p);
   else if (strcmp(q, "INFO") == 0)
     puts(p);
@@ -185,6 +206,46 @@ static void uline(char *p, void *b)
   }
 }
 
+static void logfile(const char *name)
+{
+  FILE *fp;
+
+  if ((fp = fopen(name, "a")) != 0) {
+    if (logfp)
+      fclose(logfp);
+    logfp =  fp;
+    setvbuf(logfp, 0, _IOLBF, BUFSIZ);
+  } else {
+    dstr d = DSTR_INIT;
+    dstr_putf(&d, "error opening logfile `%s': %s", name, strerror(errno));
+    if (logfp)
+      writelog("error", d.buf);
+    else if (logname)
+      die(EXIT_FAILURE, d.buf);
+    if (f & f_syslog)
+      syslog(LOG_ERR, d.buf);
+    dstr_destroy(&d);
+  }
+}
+
+static void sighup(int sig, void *v)
+{
+  logfile(logname);
+}
+
+static void cleanup(void)
+{
+  if (pidfile)
+    unlink(pidfile);
+}
+
+static void sigdie(int sig)
+{
+  cleanup();
+  signal(sig, SIG_DFL);
+  raise(sig);
+}
+
 static void version(FILE *fp)
 {
   pquis(fp, "$, TrIPE version " VERSION "\n");
@@ -197,7 +258,8 @@ Usage:\n\
        $ [-w] [-options] [command [args]...]\n\
        $ [-Dl] [-f file] [-options]\n\
 Options:\n\
-       [-s] [-d directory] [-a socket] [-p program] [-S arg,arg,...]\n\
+       [-s] [-d directory] [-a socket] [-P pidfile]\n\
+       [-p program] [-S arg,arg,...]\n\
 ");
 }
 
@@ -217,6 +279,7 @@ Options in full:\n\
 -D, --daemon           Become a background task after connecting.\n\
 -d, --directory=DIR    Select current directory [default /var/lib/tripe]\n\
 -a, --admin-socket=FILE        Select socket to connect to.\n\
+-P, --pidfile=FILE     Write process-id to FILE.\n\
 \n\
 -s, --spawn            Start server rather than connecting.\n\
 -p, --spawn-path=PATH  Specify path to executable.\n\
@@ -235,6 +298,7 @@ int main(int argc, char *argv[])
   const char *spawnpath = "tripe";
   string_v spawnopts = DA_INIT;
   char *p;
+  FILE *pidfp = 0;
 
   ego(argv[0]);
 
@@ -257,10 +321,11 @@ int main(int argc, char *argv[])
       { "syslog",      0,              0,      'l' },
       { "logfile",     OPTF_ARGREQ,    0,      'f' },
       { "warnings",    0,              0,      'w' },
+      { "pidfile",     OPTF_ARGREQ,    0,      'P' },
       { 0,             0,              0,      0 }
     };
 
-    int i = mdwopt(argc, argv, "hvuDd:a:sp:S:lwf:n", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+hvuDd:a:sp:S:lwf:nP:", opts, 0, 0, 0);
     if (i < 0)
       break;
     switch (i) {
@@ -301,14 +366,12 @@ int main(int argc, char *argv[])
        f |= f_warn;
        break;
       case 'f':
-       if (logfp)
-         fclose(logfp);
-       if ((logfp = fopen(optarg, "a")) == 0) {
-         die(EXIT_FAILURE, "error opening logfile `%s': %s",
-             optarg, strerror(errno));
-       }
+       logname = optarg;
        f |= f_noinput;
        break;
+      case 'P':
+       pidfile = optarg;
+       break;
       default:
        f |= f_bogus;
        break;
@@ -319,12 +382,24 @@ int main(int argc, char *argv[])
     exit(EXIT_FAILURE);
   }
 
-  /* --- Set the world up --- */
+  /* --- Set various things up --- */
 
   if (chdir(dir)) {
-    die(EXIT_FAILURE, "couldn't set current directory to `%s': %s",
+    die(EXIT_FAILURE, "couldn't set `%s' as current directory: %s",
        dir, strerror(errno));
   }
+  if (logname)
+    logfile(logname);
+  if (!pidfile && (f & f_daemon) && ((f & f_syslog) || logname))
+    pidfile = "tripectl.pid";
+  if (pidfile && (pidfp = fopen(pidfile, "w")) == 0) {
+    die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
+       pidfile, strerror(errno));
+  }
+  signal(SIGINT, sigdie);
+  signal(SIGQUIT, sigdie);
+  signal(SIGTERM, sigdie);
+  atexit(cleanup);
 
   /* --- Connect to the server --- */
 
@@ -342,12 +417,10 @@ int main(int argc, char *argv[])
 #endif
     sigaction(SIGCHLD, &sa, 0);
 
+    DA_UNSHIFT(&spawnopts, (char *)sock);
+    DA_UNSHIFT(&spawnopts, "-a");
+    DA_UNSHIFT(&spawnopts, "-d.");
     DA_UNSHIFT(&spawnopts, (char *)spawnpath);
-    if (!(f & f_spawnopts)) {
-      DA_PUSH(&spawnopts, "-d.");
-      DA_PUSH(&spawnopts, "-a");
-      DA_PUSH(&spawnopts, (char *)sock);
-    }
     DA_PUSH(&spawnopts, 0);
     if (socketpair(PF_UNIX, SOCK_STREAM, 0, pfd))
       die(EXIT_FAILURE, "error from socketpair: %s", strerror(errno));
@@ -361,6 +434,11 @@ int main(int argc, char *argv[])
       dup2(pfd[1], STDOUT_FILENO);
       close(pfd[1]);
       close(pfd[0]);
+      if (logfp)
+       fclose(logfp);
+      closelog();
+      if (f & f_daemon)
+       u_detach();
       execvp(DA(&spawnopts)[0], DA(&spawnopts));
       die(127, "couldn't exec `%s': %s", spawnpath, strerror(errno));
     }
@@ -375,12 +453,12 @@ int main(int argc, char *argv[])
     memset(&sun, 0, sizeof(sun));
     sun.sun_family = AF_UNIX;
     memcpy(sun.sun_path, sock, sz);
-    sz += offsetof(struct sockaddr_un, sun_path);
+    sz = sz + offsetof(struct sockaddr_un, sun_path);
     if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
       die(EXIT_FAILURE, "error making socket: %s", strerror(errno));
     if (connect(fd, (struct sockaddr *)&sun, sz)) {
       die(EXIT_FAILURE, "error connecting to `%s': %s",
-         sock, strerror(errno));
+         sun.sun_path, strerror(errno));
     }
   }
 
@@ -388,6 +466,10 @@ int main(int argc, char *argv[])
     if (u_daemon())
       die(EXIT_FAILURE, "error becoming daemon: %s", strerror(errno));
   }
+  if (pidfp) {
+    fprintf(pidfp, "%li", (long)getpid());
+    fclose(pidfp);
+  }
 
   /* --- If we're meant to be interactive, do that --- */
 
@@ -399,7 +481,7 @@ int main(int argc, char *argv[])
     selbuf_init(&bu, &sel, STDIN_FILENO, uline, &bu);
     selbuf_init(&bs, &sel, fd, sline, &bs);
     for (;;) {
-      if (sel_select(&sel))
+      if (sel_select(&sel) && errno != EINTR && errno != EAGAIN)
        die(EXIT_FAILURE, "select failed: %s", strerror(errno));
     }
   }
@@ -423,20 +505,23 @@ int main(int argc, char *argv[])
   /* --- Pull everything else out of the box --- */
 
   {
-    lbuf b;
-    lbuf_init(&b, cline, 0);
+    sel_state sel;
+    selbuf b;
+    sig hup;
+
+    sel_init(&sel);
+    selbuf_init(&b, &sel, fd, cline, 0);
+
     if (f & f_syslog)
       openlog(QUIS, 0, LOG_DAEMON);
+    if (logfp) {
+      sig_init(&sel);
+      sig_add(&hup, SIGHUP, sighup, 0);
+    }
     for (;;) {
-      size_t sz = lbuf_free(&b, &p);
-      ssize_t n = read(fd, p, sz);
-      if (n < 0)
-       die(EXIT_FAILURE, "read failed: %s", strerror(errno));
-      if (n == 0)
-       break;
-      lbuf_flush(&b, p, n);
+      if (sel_select(&sel) && errno != EINTR && errno != EAGAIN)
+       die(EXIT_FAILURE, "select failed: %s", strerror(errno));
     }
-    lbuf_close(&b);
   }
 
   return (0);