#include #include #include #include #include #include #include #include #include extern char **environ; const char* STDIN_FN_KEY = "STDIN_FILENAME="; int copyfds(int ind, int outd) { size_t read, written; char scratch[4096]; FILE* in; FILE* out; int rv = 0; in = fdopen(ind, "r"); out = fdopen(outd, "w"); for (;;) { read = fread(scratch, 1, sizeof scratch, in); if (read != sizeof scratch && ferror(in)) goto cleanup; if (read == 0) break; written = fwrite(scratch, 1, read, out); if (written != read) goto cleanup; } rv = 1; cleanup: fclose(in); fclose(out); return rv; } int err_die(char* argv) { printf("Content-Type: text/plain\r\n\r\n"); printf(argv); printf("\r\n"); return 1; } int get_config(char* whatdir, char* whatfile, char* whatbuffer, int die) { char scratch[MAXPATHLEN+1024]; FILE *handle; struct stat st; if (whatdir) chdir(whatdir); handle = fopen(whatfile, "r"); if (!handle) { if (die) { sprintf(scratch, "Could not open file '%s' in directory '%s'. errno = %d.\n", whatfile, whatdir, errno); return err_die(scratch); } return 1; } fread(whatbuffer, 1, MAXPATHLEN, handle); fclose(handle); return 0; } int start_twistd(char* basedir) { char scratch[MAXPATHLEN]; char env_value[MAXPATHLEN]; char tacfile[MAXPATHLEN]; FILE* handle; DIR* environ_dir; struct dirent *fl; int err, startup_complete_sock, startup_complete_accepted; struct sockaddr_un server; sprintf(tacfile, "%s/%s", basedir, "zomne.tac"); handle = fopen(tacfile, "r"); if (!handle) return err_die("Could not open tacfile zomne.tac"); fclose(handle); // We have an "environment" directory, which is full of files // which are named with environment keys and who contain environment values. // Iterate all the files, and set keys in the environment so the child sees // them. if (!((environ_dir = opendir("zomne_environ")) == NULL)) { chdir("zomne_environ"); while ((fl = readdir(environ_dir)) != NULL) { if (err = get_config("", fl->d_name, env_value, 1)) return err; if (setenv(fl->d_name, env_value, 1)) return err_die("Unknown error setting environment"); } } chdir(basedir); startup_complete_sock = socket(AF_UNIX, SOCK_STREAM, 0); if (startup_complete_sock < 0) return err_die("Error creating socket for startup completion notification"); server.sun_family = AF_UNIX; strcpy(server.sun_path, "zomne_startup_complete.socket"); if (bind(startup_complete_sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) return err_die("Error binding zomne_startup_complete.socket"); listen(startup_complete_sock, 1); sprintf(scratch, "twistd -oy %s", tacfile); system(scratch); // This blocks until the twisted process calls connectUNIX('zomne_startup_complete.socket') startup_complete_accepted = accept(startup_complete_sock, 0, 0); close(startup_complete_accepted); close(startup_complete_sock); unlink("zomne_startup_complete.socket"); return 0; } int main(int argc, char* argv[]) { struct sockaddr_un addr; int s, tempfd, bytesread, err, pid; char scratch[MAXPATHLEN]; char basedir[MAXPATHLEN]; char stdin_temp[MAXPATHLEN]; char **enviter = environ; FILE* config_file; char *program_name; program_name = (char*)getenv("SCRIPT_NAME"); if (!program_name) // If argv[0] contains any slashes, we just want the bit after the slash // aka argv[0].split('/')[-1] program_name = argv[0]; while (*program_name++); // Move the pointer to the end of the string while (*(program_name-1) != '/') program_name--; // Move the pointer back to the slash sprintf(scratch, ".%s.dir", program_name); if (err = get_config("", scratch, basedir, 1)) return err; chdir(basedir); if (get_config(basedir, "twistd.pid", scratch, 0)) { // No pidfile, got to start twisted if (err = start_twistd(basedir)) return err; } else { // TODO Send a signal to the pid to see if it is alive. // Got an error? // It is dead, start it up } s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { return err_die("Error creating socket"); } sprintf(addr.sun_path, "%s%s", basedir, "zomne.socket"); addr.sun_family = AF_UNIX; if (connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un))) { return err_die("Couldn't connect to server"); } else { while (*enviter != 0) { sprintf(scratch, "%u:", strlen(*enviter)); send(s, scratch, strlen(scratch), 0); send(s, *enviter, strlen(*enviter), 0); send(s, ",", strlen(","), 0); enviter += 1; } getcwd(scratch, MAXPATHLEN); sprintf(stdin_temp, "%s/%s", scratch, "tmp.zomneXXXXXX"); tempfd = mkstemp(stdin_temp); copyfds(STDIN_FILENO, tempfd); sprintf(scratch, "%u:%s%s", strlen(STDIN_FN_KEY) + strlen(stdin_temp), STDIN_FN_KEY, stdin_temp); send(s, scratch, strlen(scratch), 0); while (bytesread = recv(s, scratch, 1024, 0)) { fwrite(scratch, 1, bytesread, stdout); } unlink(stdin_temp); } close(s); }