progs/pixie.c: Rewrite list hacking to avoid strict-aliasing badness.
[u/mdw/catacomb] / progs / pixie.c
index 4a5e9ab..667a588 100644 (file)
@@ -86,7 +86,7 @@ static unsigned flags = 0;
 
 /*----- Event logging -----------------------------------------------------*/
 
-/* --- @log@ --- *
+/* --- @pxlog@ --- *
  *
  * Arguments:  @const char *p@ = @printf@-style format string
  *             @...@ = extra arguments to fill in
@@ -96,7 +96,7 @@ static unsigned flags = 0;
  * Use:                Writes out a timestamped log message.
  */
 
-static void log(const char *p, ...)
+static void pxlog(const char *p, ...)
 {
   dstr d = DSTR_INIT;
   va_list ap;
@@ -125,8 +125,7 @@ static void log(const char *p, ...)
 /* --- Data structures --- */
 
 typedef struct phrase {
-  struct phrase *next;
-  struct phrase *prev;
+  struct phrase *next, *prev;
   char *tag;
   char *p;
   unsigned long t;
@@ -136,8 +135,21 @@ typedef struct phrase {
 
 /* --- Variables --- */
 
-#define P_ROOT ((phrase *)&p_root)
-static struct { phrase *next; phrase *prev; } p_root = { P_ROOT, P_ROOT };
+static phrase *p_head = 0, *p_tail = 0;
+
+/* --- Utility macros --- */
+
+#define P_LINKTAIL(p) do {                                             \
+  (p)->next = 0;                                                       \
+  (p)->prev = p_tail;                                                  \
+  *(p_tail ? &p_tail->next : &p_head) = (p);                           \
+  p_tail = (p);                                                                \
+} while (0)
+
+#define P_UNLINK(p) do {                                               \
+  *((p)->next ? &(p)->next->prev : &p_tail) = (p)->prev;               \
+  *((p)->prev ? &(p)->prev->next : &p_head) = (p)->next;               \
+} while (0)
 
 /* --- @p_free@ --- *
  *
@@ -154,8 +166,7 @@ static void p_free(phrase *p)
     sel_rmtimer(&p->timer);
   xfree(p->tag);
   l_free(&lm, p->p);
-  p->next->prev = p->prev;
-  p->prev->next = p->next;
+  P_UNLINK(p);
   DESTROY(p);
 }
 
@@ -173,7 +184,7 @@ static void p_timer(struct timeval *tv, void *p)
 {
   phrase *pp = p;
   if (verbose)
-    log("expiring passphrase `%s'", pp->tag);
+    pxlog("expiring passphrase `%s'", pp->tag);
   p_free(pp);
 }
 
@@ -193,13 +204,13 @@ static void *p_alloc(size_t sz)
     char *p;
     if ((p = l_alloc(&lm, sz)) != 0)
       return (p);
-    if (P_ROOT->next == P_ROOT)
+    if (!p_head)
       return (0);
     if (verbose) {
-      log("flushing passphrase `%s' to free up needed space",
-         P_ROOT->next->tag);
+      pxlog("flushing passphrase `%s' to free up needed space",
+           p_head->tag);
     }
-    p_free(P_ROOT->next);
+    p_free(p_head);
   }
 }
 
@@ -216,7 +227,7 @@ static phrase *p_find(const char *tag)
 {
   phrase *p;
 
-  for (p = P_ROOT->next; p != P_ROOT; p = p->next) {
+  for (p = p_head; p; p = p->next) {
     if (strcmp(p->tag, tag) == 0) {
       if (p->t) {
        struct timeval tv;
@@ -225,12 +236,8 @@ static phrase *p_find(const char *tag)
        tv.tv_sec += p->t;
        sel_addtimer(&sel, &p->timer, &tv, p_timer, p);
       }
-      p->next->prev = p->prev;
-      p->prev->next = p->next;
-      p->next = P_ROOT;
-      p->prev = P_ROOT->prev;
-      P_ROOT->prev->next = p;
-      P_ROOT->prev = p;
+      P_UNLINK(p);
+      P_LINKTAIL(p);
       return (p);
     }
   }
@@ -279,10 +286,7 @@ static phrase *p_add(const char *tag, const char *p, unsigned long t)
 
   /* --- Link the block into the chain --- */
 
-  pp->next = P_ROOT;
-  pp->prev = P_ROOT->prev;
-  P_ROOT->prev->next = pp;
-  P_ROOT->prev = pp;
+  P_LINKTAIL(pp);
   return (pp);
 }
 
@@ -300,15 +304,15 @@ static void p_flush(const char *tag)
   phrase *p;
 
   if (!tag && verbose > 1)
-    log("flushing all passphrases");
-  p = P_ROOT->next;
-  while (p != P_ROOT) {
+    pxlog("flushing all passphrases");
+  p = p_head;
+  while (p) {
     phrase *pp = p->next;
     if (!tag)
       p_free(p);
     else if (strcmp(p->tag, tag) == 0) {
       if (verbose > 1)
-       log("flushing passphrase `%s'", tag);
+       pxlog("flushing passphrase `%s'", tag);
       p_free(p);
       break;
     }
@@ -477,7 +481,7 @@ static int p_get(const char **q, const char *tag, unsigned mode, time_t exp)
   /* --- Write a log message --- */
 
   if (verbose > 1)
-    log("passphrase `%s' requested", tag);
+    pxlog("passphrase `%s' requested", tag);
 
   /* --- If there is no fetcher, life is simpler --- */
 
@@ -514,7 +518,7 @@ static int p_get(const char **q, const char *tag, unsigned mode, time_t exp)
       goto fail;
     if (strcmp(pp, p->p) != 0) {
       if (verbose)
-       log("passphrases for `%s' don't match", tag);
+       pxlog("passphrases for `%s' don't match", tag);
       p_free(p);
       goto fail;
     }
@@ -695,7 +699,7 @@ OK\n\
   else if (strcmp(q, "list") == 0) {
     phrase *p;
 
-    for (p = P_ROOT->next; p != P_ROOT; p = p->next) {
+    for (p = p_head; p; p = p->next) {
       if (!p->t)
        pixserv_write(px, "ITEM %s no-expire\n", p->tag);
       else {
@@ -775,8 +779,8 @@ OK\n\
 
   else if (strcmp(q, "quit") == 0) {
     if (verbose)
-      log("%s client requested shutdown",
-         px->f & px_stdin ? "local" : "remote");
+      pxlog("%s client requested shutdown",
+           px->f & px_stdin ? "local" : "remote");
     pixserv_write(px, "OK\n");
     exit(0);
   }
@@ -837,7 +841,7 @@ static void pixserv_accept(int fd, unsigned mode, void *p)
   if ((nfd = accept(fd, (struct sockaddr *)&sun, &sunsz)) < 0) {
     if (verbose && errno != EAGAIN && errno != EWOULDBLOCK &&
        errno != ECONNABORTED && errno != EPROTO && errno != EINTR)
-      log("new connection failed: %s", strerror(errno));
+      pxlog("new connection failed: %s", strerror(errno));
     return;
   }
   pixserv_create(nfd, nfd);
@@ -886,7 +890,7 @@ static void pix_sigdie(int sig, void *p)
        p = buf;
        break;
     }
-    log("shutting down on %s", p);
+    pxlog("shutting down on %s", p);
   }
   exit(0);
 }
@@ -915,7 +919,7 @@ static void pix_sigflush(int sig, void *p)
        p = buf;
        break;
     }
-    log("received %s; flushing passphrases", p);
+    pxlog("received %s; flushing passphrases", p);
   }
   p_flush(0);
 }
@@ -984,12 +988,12 @@ static void pix_setup(struct sockaddr_un *sun, size_t sz)
        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");
+         pxlog("stale socket found; removing it");
        unlink(sun->sun_path);
        close(fd);
       } else {
        if (verbose)
-         log("server already running; shutting it down");
+         pxlog("server already running; shutting it down");
        write(fd, "QUIT\n", 5);
        sleep(1);
        close(fd);
@@ -1376,8 +1380,8 @@ int main(int argc, char *argv[])
     if (rc < 0)
       die(EXIT_FAILURE, d.buf);
     else if (rc && verbose) {
-      log(d.buf);
-      log("couldn't lock passphrase buffer");
+      pxlog(d.buf);
+      pxlog("couldn't lock passphrase buffer");
     }
     dstr_destroy(&d);
     arena_setsecure(&lm.a);
@@ -1437,7 +1441,7 @@ int main(int argc, char *argv[])
   }
 
   if (verbose)
-    log("initialized ok");
+    pxlog("initialized ok");
 
   {
     int selerr = 0;
@@ -1445,10 +1449,10 @@ int main(int argc, char *argv[])
       if (!sel_select(&sel))
        selerr = 0;
       else if (errno != EINTR && errno != EAGAIN) {
-       log("error from select: %s", strerror(errno));
+       pxlog("error from select: %s", strerror(errno));
        selerr++;
        if (selerr > 8) {
-         log("too many consecutive select errors: bailing out");
+         pxlog("too many consecutive select errors: bailing out");
          exit(EXIT_FAILURE);
        }
       }