Add an internal-representation no-op function.
[u/mdw/catacomb] / pixie.c
diff --git a/pixie.c b/pixie.c
index 1ee1bab..363f833 100644 (file)
--- a/pixie.c
+++ b/pixie.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: pixie.c,v 1.4 2000/06/17 11:50:53 mdw Exp $
+ * $Id: pixie.c,v 1.10 2001/02/21 20:03:54 mdw Exp $
  *
  * Passphrase pixie for Catacomb
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: pixie.c,v $
+ * Revision 1.10  2001/02/21 20:03:54  mdw
+ * Handle select errors (by bombing out).  Cosmetic tweak.
+ *
+ * Revision 1.9  2001/02/03 16:06:44  mdw
+ * Don't set a handler for @SIGINT@ if it's ignored at startup.  Add some
+ * error handling for the @select@ loop.
+ *
+ * Revision 1.8  2001/01/25 22:19:31  mdw
+ * Make flags be unsigned.
+ *
+ * Revision 1.7  2000/12/06 20:33:27  mdw
+ * Make flags be macros rather than enumerations, to ensure that they're
+ * unsigned.
+ *
+ * Revision 1.6  2000/10/08 12:06:46  mdw
+ * Change size passed to socket function to be a @size_t@.  Insert missing
+ * type name for flag declaration.
+ *
+ * Revision 1.5  2000/07/29 22:05:22  mdw
+ * Miscellaneous tidyings:
+ *
+ *   * Change the timeout to something more appropriate for real use.
+ *
+ *   * Check assumptions about object types when binding the socket.  In
+ *     particular, don't zap the socket if it's really something else.
+ *
+ *   * In @p_request@, return a failure if the shell command returned
+ *     nonzero.  Fix a bug in @p_get@ which incorrectly passes on a success
+ *     code when this happens.
+ *
+ *   * Dispose of the locked memory in client mode to avoid being
+ *     antisocial.
+ *
+ *   * Also in client mode, don't report closure from the server if we're
+ *     running noninteractively.
+ *
+ *   * Insert a missing option letter into the usage string.
+ *
+ *   * Change to the root directory after forking in daemon mode.
+ *
  * Revision 1.4  2000/06/17 11:50:53  mdw
  * New pixie protocol allowing application to request passphrases and send
  * them to the pixie.  Use the secure arena interface for the input
 
 /*----- Static variables --------------------------------------------------*/
 
-static unsigned long timeout = 300;
+static unsigned long timeout = 900;
 static sel_state sel;
 static unsigned verbose = 1;
 static const char *command = 0;
 static lmem lm;
 static unsigned flags = 0;
 
-enum {
-  F_SYSLOG = 1,
-  F_FETCH = 2
-};
+#define F_SYSLOG 1u
+#define F_FETCH 2u
 
 /*----- Event logging -----------------------------------------------------*/
 
@@ -363,6 +401,7 @@ static int p_request(const char *msg, const char *tag, char *buf, size_t sz)
     int fd[2];
     pid_t kid;
     int r;
+    int rc;
 
     /* --- Substitute the prompt string into the command --- */
 
@@ -419,9 +458,9 @@ static int p_request(const char *msg, const char *tag, char *buf, size_t sz)
       *q = 0;
     }
     close(fd[0]);
-    waitpid(kid, 0, 0);
+    waitpid(kid, &rc, 0);
     dstr_destroy(&d);
-    if (r < 0)
+    if (r < 0 || rc != 0)
       goto fail_0;
     goto ok;
 
@@ -558,7 +597,7 @@ fail:
     memset(pp, 0, LBUFSZ);
     l_free(&lm, pp);
   }
-  return (0);
+  return (-1);
 
 #undef LBUFSZ
 }
@@ -574,7 +613,7 @@ typedef struct pixserv {
   unsigned f;
 } pixserv;
 
-enum { px_stdin = 1 };
+#define px_stdin 1u
 
 #define PIXSERV_TIMEOUT 30
 
@@ -851,7 +890,7 @@ static void pixserv_accept(int fd, unsigned mode, void *p)
 {
   int nfd;
   struct sockaddr_un sun;
-  int sunsz = sizeof(sun);
+  size_t sunsz = sizeof(sun);
 
   if (mode != SEL_READ)
     return;
@@ -957,11 +996,11 @@ static void pix_setup(struct sockaddr_un *sun, size_t sz)
   /* --- Set up the parent directory --- */
 
   {
-    dstr d = DSTR_INIT;
     char *p = sun->sun_path;
     char *q = strrchr(p, '/');
 
     if (q) {
+      dstr d = DSTR_INIT;
       struct stat st;
 
       DPUTM(&d, p, q - p);
@@ -970,8 +1009,11 @@ static void pix_setup(struct sockaddr_un *sun, size_t sz)
       mkdir(d.buf, 0700);
       if (stat(d.buf, &st))
        die(1, "couldn't stat `%s': %s", d.buf, strerror(errno));
+      if (!S_ISDIR(st.st_mode))
+       die(1, "object `%s' isn't a directory", d.buf);
       if (st.st_mode & 0077)
        die(1, "parent directory `%s' has group or world access", d.buf);
+      dstr_destroy(&d);
     }
   }
 
@@ -993,8 +1035,13 @@ static void pix_setup(struct sockaddr_un *sun, size_t sz)
        die(1, "too many retries; giving up");
       n--;
       if (connect(fd, (struct sockaddr *)sun, sz)) {
+       struct stat st;
        if (errno != ECONNREFUSED)
          die(1, "couldn't bind to address: %s", strerror(e));
+       if (stat(sun->sun_path, &st))
+         die(1, "couldn't stat `%s': %s", sun->sun_path, strerror(errno));
+       if (!S_ISSOCK(st.st_mode))
+         die(1, "object `%s' isn't a socket", sun->sun_path);
        if (verbose)
          log("stale socket found; removing it");
        unlink(sun->sun_path);
@@ -1030,8 +1077,10 @@ static void pix_setup(struct sockaddr_un *sun, size_t sz)
 /* --- Variables --- */
 
 static selbuf c_server, c_client;
-static c_flags = 0;
-enum { cf_uclose = 1, cf_sclose = 2 };
+static unsigned c_flags = 0;
+
+#define cf_uclose 1u
+#define cf_sclose 2u
 
 /* --- Line handler functions --- */
 
@@ -1058,8 +1107,8 @@ static void c_sline(char *s, void *p)
       selbuf_destroy(&c_client);
     }
     exit(0);
-  } else 
-    puts(s);
+  }
+  puts(s);
 }
 
 /* --- @pix_client@ --- *
@@ -1077,6 +1126,10 @@ static void pix_client(struct sockaddr_un *sun, size_t sz, char *argv[])
 {
   int fd;
 
+  /* --- Dispose of locked memory --- */
+
+  l_destroy(&lm);
+
   /* --- Open the socket --- */
 
   if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
@@ -1099,13 +1152,16 @@ static void pix_client(struct sockaddr_un *sun, size_t sz, char *argv[])
     DPUTC(&d, '\n');
     write(fd, d.buf, d.len);
     shutdown(fd, 1);
+    c_flags |= cf_uclose;
     dstr_destroy(&d);
   } 
 
   /* --- And repeat --- */
 
-  for (;;)
-    sel_select(&sel);
+  for (;;) {
+    if (sel_select(&sel))
+      die(EXIT_FAILURE, "select error: %s", strerror(errno));
+  }
 }
 
 /*----- Main code ---------------------------------------------------------*/
@@ -1123,7 +1179,7 @@ static void usage(FILE *fp)
 {
   pquis(fp, "\
 Usage:\n\
-       $ [-qvidl] [-c command] [-t timeout] [-s socket]\n\
+       $ [-qvfidl] [-c command] [-t timeout] [-s socket]\n\
        $ [-s socket] -C [command args...]\n\
 ");
 }
@@ -1188,13 +1244,11 @@ int main(int argc, char *argv[])
   size_t sz;
   unsigned f = 0;
 
-  enum {
-    f_bogus = 1,
-    f_client = 2,
-    f_stdin = 4,
-    f_daemon = 8,
-    f_syslog = 16
-  };
+#define f_bogus 1u
+#define f_client 2u
+#define f_stdin 4u
+#define f_daemon 8u
+#define f_syslog 16u
 
   /* --- Initialize libraries --- */
 
@@ -1344,8 +1398,11 @@ int main(int argc, char *argv[])
 
   {
     static sig sigint, sigterm, sigquit, sighup;
+    struct sigaction sa;
     sig_init(&sel);
-    sig_add(&sigint, SIGINT, pix_sigdie, 0);
+    sigaction(SIGINT, 0, &sa);
+    if (sa.sa_handler != SIG_IGN)
+      sig_add(&sigint, SIGINT, pix_sigdie, 0);
     sig_add(&sigterm, SIGTERM, pix_sigdie, 0);
     sig_add(&sigquit, SIGQUIT, pix_sigflush, 0);
     sig_add(&sighup, SIGHUP, pix_sigflush, 0);
@@ -1383,16 +1440,31 @@ int main(int argc, char *argv[])
       }
     }
 #endif
+    chdir("/");
     setsid();
 
-    if (fork() > 0)
+    if (fork() >= 0)
       _exit(0);
   }
 
   if (verbose)
     log("initialized ok");
-  for (;;)
-    sel_select(&sel);
+
+  {
+    int selerr = 0;
+    for (;;) {
+      if (!sel_select(&sel))
+       selerr = 0;
+      else if (errno != EINTR && errno != EAGAIN) {
+       log("error from select: %s", strerror(errno));
+       selerr++;
+       if (selerr > 8) {
+         log("too many consecutive select errors: bailing out");
+         exit(EXIT_FAILURE);
+       }
+      }
+    }
+  }
   return (0);
 }