chiark / gitweb /
cgi-fcgi-interp: Rename from cgi-fcgi-perl, and adjust arg handling
[chiark-utils.git] / cprogs / cgi-fcgi-perl.c
diff --git a/cprogs/cgi-fcgi-perl.c b/cprogs/cgi-fcgi-perl.c
deleted file mode 100644 (file)
index 83bd962..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * "Interpreter" that you can put in #! like this
- *   #!/usr/bin/cgi-fcgi-perl [<options>]
- *
- * The result is a program which looks, when executed via the #!
- * line, like a CGI program.  But the perl script inside will
- * be executed via /usr/bin/perl in fcgi.
- *
- * Options:
- *
- *  -g<ident>
- *          Use <ident> rather than hex(sha256(<script>))
- *          as the basename of the leafname of the fcgi rendezvous
- *          socket.  If <ident> contains only hex digit characters it
- *          ought to be no more than 32 characters.
- *
- *  -M<numservers>
- *         Start <numservers> instances of the program.  This
- *         determines the maximum concurrency.  (Note that unlike
- *         speedy, the specified number of servers is started
- *         right away.)  The default is 4.
- *
- * cgi-fcgi-perl automatically expires old sockets, including
- * ones where the named perl script is out of date.
- */
-
-/*
- * Uses one of two directories
- *   /var/run/user/<UID>/cgi-fcgi-perl/
- *   ~/.cgi-fcgi-perl/<node>/
- * and inside there uses these paths
- *   s<ident>
- *   g<inum>
- *
- * If -M<ident> is not specified then an initial substricg of the
- * lowercase hex of the sha256 of the <script> (ie, our argv[1]) is
- * used.  The substring is chosen so that the whole path is 10 bytes
- * shorter than sizeof(sun_path).  But always at least 33 characters.
- *
- * <node> is truncated at the first `.' and after the first 32
- * characters.
- *
- * Algorithm:
- *  - see if /var/run/user exists
- *       if so, lstat /var/run/user/<UID> and check that
- *         we own it and it's X700; if not, fail
- *         if it's ok then <base> is /var/run/user/<UID>
- *       otherwise, look for and maybe create ~/.cgi-fcgi-perl
- *         (where ~ is HOME or from getpwuid)
- *         and then <base> is ~/.cgi-fcgi-perl/<node>
- *  - calculate pathname (checking <ident> length is OK)
- *  - check for and maybe create <base>
- *  - stat and lstat the <script>
- *  - stat the socket and check its timestamp
- *       if it is too hold, rename it to g<inum> (where
- *       <inum> is in decimal)
- *       and run garbage collection
- *  - run  cgi-fcgi -connect SOCKET SCRIPT
- */
-
-#include "common.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdbool.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <err.h>
-
-#include <nettle/sha.h>
-
-#include "myopt.h"
-
-#define die  common_die
-#define diee common_diee
-
-#define MINHEXHASH 33
-
-static const char *ident;
-static int numservers;
-
-void diee(const char *m) {
-  err(127, "error: %s failed", m);
-}
-
-static void fusagemessage(FILE *f) {
-  fprintf(f, "usage: #!/usr/bin/cgi-fcgi-perl [<options>]\n");
-}
-
-void usagemessage(void) { fusagemessage(stderr); }
-
-static void of_help(const struct cmdinfo *ci, const char *val) {
-  fusagemessage(stdout);
-  if (ferror(stdout)) diee("write usage message to stdout");
-  exit(0);
-}
-
-static const struct cmdinfo cmdinfos[]= {
-  { "help",   0, .call= of_help               },
-  { 0, 'g',   1, .sassignto= &ident           },
-  { 0, 'M',   1, .iassignto= &numservers      },
-  { 0 }
-};
-
-static uid_t us;
-static const char *run_base, *command, *socket_path;
-
-static bool find_run_base_var_run(void) {
-  struct stat stab;
-  char *try;
-  int r;
-
-  try = m_asprintf("%s/%lu", "/var/run/user", us);
-  r = lstat(try, &stab);
-  if (r<0) {
-    if (errno == ENOENT ||
-       errno == ENOTDIR ||
-       errno == EACCES ||
-       errno == EPERM)
-      return 0; /* oh well */
-    diee("stat /var/run/user/UID");
-  }
-  if (!S_ISDIR(stab.st_mode)) {
-    warnx("%s not a directory, falling back to ~\n", try);
-    return 0;
-  }
-  if (stab.st_uid != us) {
-    warnx("%s not owned by uid %lu, falling back to ~\n", try,
-         (unsigned long)us);
-    return 0;
-  }
-  if (stab.st_mode & 0077) {
-    warnx("%s writeable by group or other, falling back to ~\n", try);
-    return 0;
-  }
-  run_base = m_asprintf("%s/%s", try, "cgi-fcgi-perl");
-  return 1;
-}
-
-static bool find_run_base_home(void) {
-  struct passwd *pw;
-  struct utsname ut;
-  char *dot, *try;
-  int r;
-
-  pw = getpwuid(us);  if (!pw) diee("getpwent(uid)");
-
-  r = uname(&ut);   if (r) diee("uname(2)");
-  dot = strchr(ut.nodename, '.');
-  if (dot) *dot = 0;
-  if (sizeof(ut.nodename) > 32)
-    ut.nodename[32] = 0;
-
-  try = m_asprintf("%s/%s/%s", pw->pw_dir, ".cgi-fcgi-perl", ut.nodename);
-  run_base = try;
-  return 1;
-}
-
-static void find_socket_path(void) {
-  struct sockaddr_un sun;
-  int r;
-
-  us = getuid();  if (us==(uid_t)-1) diee("getuid");
-
-  find_run_base_var_run() ||
-    find_run_base_home() ||
-    (abort(),0);
-
-  int maxidentlen = sizeof(sun.sun_path) - strlen(run_base) - 10 - 2;
-
-  if (!ident) {
-    if (maxidentlen < MINHEXHASH)
-      errx(127,"cgi-fcgi-perl: base directory `%s'"
-          " leaves only %d characters for command name hash"
-          " which is too little (<%d)",
-          run_base, maxidentlen, MINHEXHASH);
-
-    int identlen = maxidentlen > 64 ? 64 : maxidentlen;
-    char *hexident = xmalloc(identlen + 2);
-    struct sha256_ctx sc;
-    unsigned char bbuf[32];
-    int i;
-
-    sha256_init(&sc);
-    sha256_update(&sc,strlen(command)+1,command);
-    sha256_digest(&sc,sizeof(bbuf),bbuf);
-
-    for (i=0; i<identlen; i += 2)
-      sprintf(hexident+i, "%02x", bbuf[i/2]);
-
-    hexident[identlen] = 0;
-    ident = hexident;
-  }
-
-  if (strlen(ident) > maxidentlen)
-    errx(127, "base directory `%s' plus ident `%s' too long"
-        " (with spare) for socket (max ident %d)\n",
-        run_base, ident, maxidentlen);
-
-  r = mkdir(run_base, 0700);
-  if (r) {
-    if (!(errno == EEXIST))
-      err(127,"mkdir %s",run_base);
-  }
-
-  socket_path = m_asprintf("%s/g%s",run_base,ident);
-}  
-
-static bool check_garbage(void) {
-  struct stat sock_stab, cmd_stab;
-  int r;
-
-  r = lstat(socket_path, &sock_stab);
-  if (r) {
-    if ((errno == ENOENT))
-      return 0; /* well, no garbage then */
-    err(127,"stat socket (%s)",socket_path);
-  }
-
-  r = lstat(command, &cmd_stab);
-  if (r) err(127,"lstat command (%s)",command);
-
-  return 0;
-}
-
-int main(int argc, const char *const *argv) {
-  myopt(&argv, cmdinfos);
-
-  command = *argv++;
-  if (!command) errx(127,"need command argument");
-  if (*argv) errx(127,"too many arguments");
-
-  find_socket_path();
-
-  check_garbage();
-
-  printf(">%s<\n",socket_path);
-
-  exit(0);
-}