/* We need this helper to ensure that the fork/exec is atomic because, unlike * pthreads, srfi-18 threads are not killed off in the child. * * based on mod_fastcgi.c from lighttpd-1.4.31 */ #include #include #include #include #include #include #include #include "fastcgi.h" #include "fork-exec.h" void* create_string_list(int n) { if (n > 0) { return calloc(n+1, sizeof(char*)); /* Extra one for NULL */ } else { return NULL; } } void free_string_list(void* pv, int n) { int i; char** p = (char**)(pv); for (i = 0; i <= n; i++) { /* Free the extra one incase it got used. */ if (p[i]) free(p[i]); } free(p); } void insert_string(void* lv, int n, char* s) { char** l = (char**)(lv); l[n] = strdup((const char*)(s)); } void inspect_string_list(void* lv, int n) { int i; char** l = (char**)(lv); for (i = 0; i < n; i++) { printf("%d: <%s>\n", i, l[i]); } if (l[n]) printf("Not NULL terminated!\n"); else printf("NULL terminated!\n"); } int fork_exec (int fcgi_fd, void* argsv, void* envv) { pid_t child; char** args = (char**)(argsv); char** env = (char**)(envv); switch ((child = fork())) { case 0: { /* Child */ size_t i = 0; int val = 0; /* Ensure the socket is in blocking mode. */ #ifdef _WIN32 #error We don't have code to set the socket to blocking mode for Windows. #else errno = 0; val = fcntl(fcgi_fd, F_GETFL, 0); if (val == -1) { perror("fcntl F_GETFL"); exit(errno); } errno = 0; val = fcntl(fcgi_fd, F_SETFL, val & ~O_NONBLOCK); if (val == -1) { perror("fcntl F_SETFL"); exit(errno); } #endif if (fcgi_fd != FCGI_LISTENSOCK_FILENO) { close(FCGI_LISTENSOCK_FILENO); dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); close(fcgi_fd); } for (i = 3; i < 256; i++) { close(i); } /* reset signals */ #ifdef SIGTTOU signal(SIGTTOU, SIG_DFL); #endif #ifdef SIGTTIN signal(SIGTTIN, SIG_DFL); #endif #ifdef SIGTSTP signal(SIGTSTP, SIG_DFL); #endif signal(SIGHUP, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGUSR1, SIG_DFL); errno = 0; execve(args[0], args, env); /* args[0] might not be a basename! */ exit(errno); break; } case -1: { /* Error */ return 0; } default: { /* Parent */ return child; } } }