+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)) {
+ fprintf(stderr,"%s not a directory, falling back to ~\n", try);
+ return 0;
+ }
+ if (stab.st_uid != us) {
+ fprintf(stderr,"%s not owned by uid %lu, falling back to ~\n",
+ try, (unsigned long)us);
+ return 0;
+ }
+ if (stab.st_mode & 0077) {
+ fprintf(stderr,"%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;
+
+ 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) {
+ fprintf(stderr,"cgi-fcgi-perl: base directory `%s'"
+ " leaves only %d characters for command name hash"
+ " which is too little (<%d)\n",
+ run_base, maxidentlen, MINHEXHASH);
+ exit(127);
+ }
+
+ 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) {
+ fprintf(stderr,"cgi-fgci-perl: base directory `%s'"
+ " plus ident `%s' too long (with spare) for socket\n",
+ run_base, ident);
+ exit(127);
+ }
+
+ socket_path = m_asprintf("%s/g%s",run_base,ident);
+}
+