chiark / gitweb /
prefork-interp: fixes and tests
[chiark-utils.git] / cprogs / prefork-interp.c
index fdc5da9db86ce7302402bd1a8b22caa5cbacc218..7e350870f872395aa92c8b9bb215737fc6309da0 100644 (file)
 
 #include "prefork.h"
 
-struct sockaddr_un sun;
+const char our_name[] = "prefork-interp";
+
+struct sockaddr_un sockaddr_sun;
 
 #define ACK_BYTE '\n'
 
-static struct sockaddr_unix socket_sun;
 static const char *const *executor_argv;
 
+void fusagemessage(FILE *f) {
+  fprintf(f, "usage: #!/usr/bin/prefork-interp [<options>]\n");
+}
+
+const struct cmdinfo cmdinfos[]= {
+  PREFORK_CMDINFOS
+  { 0 }
+};
+
 static void propagate_exit_status(int status, const char *what) {
   int r;
 
@@ -130,11 +140,11 @@ static void propagate_exit_status(int status, const char *what) {
          signame);
     }
 
-    die("setup failed due to signal %d %s%s", sig, signame,
+    die("%s failed due to signal %d %s%s", what, sig, signame,
        WCOREDUMP(status) ? " (core dumped)" : "");
   }
 
-  die("setup failed with weird wait status %d 0x%x", status, status);
+  die("%s failed with weird wait status %d 0x%x", what, status, status);
 }
 
 static __attribute((noreturn)) void die_data_overflow(void) {
@@ -256,18 +266,22 @@ static FILE *call_sock_from_fd(int fd) {
   return call_sock;
 }
 
+static bool was_eof(FILE *call_sock) {
+  return feof(call_sock) || errno==ECONNRESET;
+}
+
 // Returns: call(client-end), or 0 to mean "is garbage"
 // find_socket_path must have been called
 static FILE *connect_existing(void) {
   int r;
   int fd = -1;
-  FILE *call_sock;
+  FILE *call_sock = 0;
 
   fd = socket(AF_UNIX, SOCK_STREAM, 0);
   if (fd==-1) diee("socket() for client");
 
-  socklen_t salen = sizeof(sun);
-  r = connect(fd, (const struct sockaddr*)&socket_sun, salen);
+  socklen_t salen = sizeof(sockaddr_sun);
+  r = connect(fd, (const struct sockaddr*)&sockaddr_sun, salen);
   if (r==-1) {
     if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbage;
     diee("connect() %s", socket_path);
@@ -279,7 +293,7 @@ static FILE *connect_existing(void) {
   char ack;
   size_t sr = fread(&ack, sizeof(ack), 1, call_sock);
   if (sr != 1) {
-    if (feof(call_sock) || errno==ECONNRESET) goto x_garbage;
+    if (was_eof(call_sock)) goto x_garbage;
     diee("read() ack byte");
   }
   if (ack != '\n') die("got ack byte 0x%02x, not '\n'", ack);
@@ -336,8 +350,8 @@ static FILE *connect_or_spawn(void) {
   int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
   if (sfd<0) diee("socket() for new listener");
 
-  socklen_t salen = sizeof(sun);
-  r= bind(sfd, (const struct sockaddr*)&socket_sun, salen);
+  socklen_t salen = sizeof(sockaddr_sun);
+  r= bind(sfd, (const struct sockaddr*)&sockaddr_sun, salen);
   if (r<0) diee("bind() on new listener");
 
   // We never want callers to get ECONNREFUSED.  But:
@@ -358,7 +372,7 @@ static FILE *connect_or_spawn(void) {
   if (got == (pid_t)-1) diee("waitpid setup [%ld]", (long)setup_pid);
   if (got != setup_pid) diee("waitpid setup [%ld] gave [%ld]!",
                             (long)setup_pid, (long)got);
-  if (status != 0) propagate_exit_status(status, "invocation");
+  if (status != 0) propagate_exit_status(status, "setup");
 
   close(lockfd);
   return call_sock_from_fd(fake_pair[0]);
@@ -395,10 +409,22 @@ int main(int argc_unused, const char *const *argv) {
   make_executor_argv(argv);
 
   find_socket_path();
-  FILLZERO(sun);
-  sun.sun_family = AF_UNIX;
-  assert(strlen(socket_path) <= sizeof(sun.sun_path));
-  strncpy(sun.sun_path, socket_path, sizeof(sun.sun_path));
+  FILLZERO(sockaddr_sun);
+  sockaddr_sun.sun_family = AF_UNIX;
+  assert(strlen(socket_path) <= sizeof(sockaddr_sun.sun_path));
+  strncpy(sockaddr_sun.sun_path, socket_path, sizeof(sockaddr_sun.sun_path));
 
   FILE *call_sock = connect_or_spawn();
+  uint32_t status;
+  ssize_t sr = fread(&status, sizeof(status), 1, call_sock);
+  if (sr != 1) {
+    if (was_eof(call_sock)) die("per-call server monitor process quit");
+    diee("read status from call socket");
+  }
+
+  status = ntohl(status);
+  if (status > INT_MAX) die("status 0x%lx does not fit in an int",
+                           (unsigned long)status);
+
+  propagate_exit_status(status, "invocation");
 }