summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2021-02-08 10:54:25 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2023-05-03 23:11:34 -0400
commit9b9dd8efafbf74b173f7d79f791b0736c797900f (patch)
tree953c3462e3a864d50a67f78e7709612e7e90d974
parent24c5bc8869288fad7d016f966be269fb31364f09 (diff)
downloadlighttpd-git-9b9dd8efafbf74b173f7d79f791b0736c797900f.tar.gz
[core] _WIN32 fdevent_createprocess()
-rw-r--r--src/fdevent.c4
-rw-r--r--src/fdevent.h11
-rw-r--r--src/fdevent_win32.c413
-rw-r--r--src/gw_backend.c34
-rw-r--r--src/mod_cgi.c23
-rw-r--r--src/server.c8
6 files changed, 483 insertions, 10 deletions
diff --git a/src/fdevent.c b/src/fdevent.c
index c18fac57..e424d982 100644
--- a/src/fdevent.c
+++ b/src/fdevent.c
@@ -458,6 +458,8 @@ int fdevent_rename(const char *oldpath, const char *newpath) {
}
+#ifndef _WIN32
+
pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd) {
#ifdef HAVE_FORK
@@ -529,6 +531,8 @@ int fdevent_waitpid_intr(pid_t pid, int * const status) {
return waitpid(pid, status, 0);
}
+#endif /* !_WIN32 */
+
#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0
diff --git a/src/fdevent.h b/src/fdevent.h
index 94f2e3b6..1848fb6f 100644
--- a/src/fdevent.h
+++ b/src/fdevent.h
@@ -99,11 +99,22 @@ char ** fdevent_environ(void);
int fdevent_open_devnull(void);
int fdevent_open_dirname(char *path, int symlinks);
+#ifndef _WIN32
int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr);
pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd);
+#endif
int fdevent_waitpid(pid_t pid, int *status, int nb);
int fdevent_waitpid_intr(pid_t pid, int *status);
+#ifdef _WIN32
+__attribute_cold__
+void fdevent_win32_cleanup (void);
+
+#define fdevent_fork_execve(name, argv, envp, fdin, fdout, fderr, dfd) \
+ fdevent_createprocess((argv),(envp),(fdin),(fdout),(fderr),(dfd))
+pid_t fdevent_createprocess(char *argv[], char *envp[], intptr_t fdin, intptr_t fdout, int fderr, int dfd);
+#endif /* _WIN32 */
+
ssize_t fdevent_socket_read_discard (int fd, char *buf, size_t sz, int family, int so_type);
int fdevent_ioctl_fionread (int fd, int fdfmt, int *toread);
diff --git a/src/fdevent_win32.c b/src/fdevent_win32.c
index 20c887b2..de3bd85a 100644
--- a/src/fdevent_win32.c
+++ b/src/fdevent_win32.c
@@ -44,9 +44,11 @@ typedef struct sockaddr_un
} SOCKADDR_UN, *PSOCKADDR_UN;
#endif
#include <string.h>
+#include <stdlib.h>
#include <stdio.h>
#include "fdevent.h"
+#include "ck.h" /* ck_calloc() */
int fdevent_socketpair_cloexec (int domain, int typ, int protocol, int sv[2])
@@ -238,6 +240,417 @@ int fdevent_socketpair_nb_cloexec (int domain, int typ, int protocol, int sv[2])
}
+#include <windows.h>
+#include <signal.h> /* sig_atomic_t */
+
+#ifndef INFINITE
+#define INFINITE 0xFFFFFFFF
+#endif
+
+#ifndef WAIT_OBJECT_0
+#define WAIT_OBJECT_0 0x00000000L
+#endif
+
+#ifndef WAIT_TIMEOUT
+#define WAIT_TIMEOUT 0x00000102L
+#endif
+
+static struct pilist {
+ struct pilist *next;
+ HANDLE hProcess;
+ HANDLE hWait;
+ pid_t pid;
+ int ran;
+} *pilist;
+
+static volatile sig_atomic_t *fdevent_sig_child;
+
+void fdevent_win32_init (volatile sig_atomic_t *ptr);
+void fdevent_win32_init (volatile sig_atomic_t *ptr)
+{
+ fdevent_sig_child = ptr;
+}
+
+
+void fdevent_win32_cleanup (void)
+{
+ struct pilist *pi, *next = pilist;
+ while ((pi = next)) {
+ next = pi->next;
+ if (pi->hWait != INVALID_HANDLE_VALUE)
+ /*(could block, but should not; our callback func is simple)*/
+ UnregisterWaitEx(pi->hWait, INVALID_HANDLE_VALUE);
+ if (pi->hProcess != INVALID_HANDLE_VALUE)
+ /*(could check for exit, send Ctrl-Break or TerminateProcess)*/
+ CloseHandle(pi->hProcess);
+ free(pi);
+ }
+}
+
+
+int fdevent_waitpid (pid_t pid, int * const status, int nb)
+{
+
+ #if 0
+
+ if (-1 == pid) {
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
+ if (!hProcess) {
+ errno = ECHILD;
+ return -1;
+ }
+ DWORD dw = WaitForSingleObject(hProcess, nb ? 0 : INFINITE);
+
+ if (WAIT_OBJECT_0 == dw) {
+ /*(GetExitCodeProcess() failure not expected; not handled)*/
+ if (status)
+ *status = GetExitCodeProcess(hProcess,&dw) ? ((dw & 0xff) << 8) : 0;
+ }
+ else if (WAIT_TIMEOUT == dw && nb) {
+ pid = 0;
+ }
+ else {
+ errno = ECHILD;
+ pid = (pid_t)-1;
+ }
+
+ CloseHandle(hProcess);
+ return pid;
+
+ #else
+
+ /* note: not thread-safe; not efficient with many processes (O(n)) */
+
+ struct pilist *pi;
+ struct pilist **next = &pilist;
+ if (-1 == pid) {
+ while ((pi = *next) && !pi->ran)
+ next = &pi->next;
+ if (pi)
+ pid = pi->pid;
+ else if (pilist)
+ return 0;
+ /*(else ECHILD below)*/
+ }
+ else {
+ while ((pi = *next) && pid != pi->pid)
+ next = &pi->next;
+ }
+ if (NULL == pi) {
+ errno = ECHILD;
+ return -1;
+ }
+
+ HANDLE hProcess = pi->hProcess;
+ DWORD dw = pi->ran
+ ? WAIT_OBJECT_0
+ : WaitForSingleObject(hProcess, nb ? 0 : INFINITE);
+
+ if (WAIT_OBJECT_0 == dw) {
+ /*(GetExitCodeProcess() failure not expected; not handled)*/
+ if (status)
+ *status = GetExitCodeProcess(hProcess,&dw) ? ((dw & 0xff) << 8) : 0;
+ }
+ else if (WAIT_TIMEOUT == dw && nb) {
+ return 0;
+ }
+ else {
+ errno = ECHILD;
+ pid = -1;
+ }
+
+ if (pi->hWait != INVALID_HANDLE_VALUE)
+ /*(could block, but should not; our callback func is simple)*/
+ UnregisterWaitEx(pi->hWait, INVALID_HANDLE_VALUE);
+
+ *next = pi->next;
+ free(pi);
+ CloseHandle(hProcess);
+ return pid;
+
+ #endif
+}
+
+
+int fdevent_waitpid_intr (pid_t pid, int * const status)
+{
+ return fdevent_waitpid(pid, status, 0);
+}
+
+
+static void CALLBACK fdevent_WaitOrTimerCallback (PVOID lpParameter, BOOLEAN TimerOrWaitFired)
+{
+ UNUSED(TimerOrWaitFired);
+ struct pilist *pi = lpParameter;
+ #if 0
+ /* (do not make blocking call to UnregisterWaitEx() from within callback) */
+ UnregisterWaitEx(pi->hWait, NULL);/*non-blocking with NULL CompletionEvent*/
+ /* note: safe to ignore UnregisterWaitEx() return value error with
+ * GetLastError() ERROR_IO_PENDING) since we use RegisterWaitForSingleObject
+ * with WT_EXECUTEONLYONCE, and so there can be no other possible queued
+ * events for pi->hWait, other than this currently running func */
+ pi->hWait = INVALID_HANDLE_VALUE;
+ #endif
+ pi->ran = 1;
+ if (fdevent_sig_child) *fdevent_sig_child = 1;
+}
+
+
+/* sorting the environment block
+ * https://learn.microsoft.com/en-us/windows/win32/procthread/changing-environment-variables
+ * https://learn.microsoft.com/en-us/windows/win32/procthread/creating-processes
+ * "All strings in the environment block must be sorted alphabetically by name.
+ * The sort is case-insensitive, Unicode order, without regard to locale."
+ * https://learn.microsoft.com/en-us/windows/win32/intl/handling-sorting-in-your-applications
+ * (could use CompareStringOrdinal() for ordinal sort independent of locale,
+ * but CompareStringOrdinal() takes LPCWCH params, so we use _stricmp())
+ * XXX: technically, sorting env block should be done on env var name (label)
+ * up to the equal sign, and not beyond, but that is not done here.
+ * To be more pedantically correct, caller could temporarily find '=',
+ * reject strings missing '=', and set '=' to '\0' on all envp[]; then call
+ * qsort(); and finally restore '=' on all envp[] after qsort() returns.
+ */
+static int fdevent_envcmpfunc (const void *a, const void *b)
+{
+ return _stricmp(*(const char **)a, *(const char **)b);
+}
+
+
+pid_t fdevent_createprocess (char *argv[], char *envp[], intptr_t fdin, intptr_t fdout, int fderr, int dfd)
+{
+ /*
+ * The Microsoft CreateProcess() interface is criminally broken.
+ * Forcing argument strings to be concatenated into a single string
+ * only to be re-parsed by Windows can lead to security issues.
+ *
+ * NB: callers of fdevent_createprocess() must properly escape and quote
+ * arguments appropriately for target program (argv[0]) so that target
+ * program can safely parse command line after calling GetCommandLine()
+ * NB: potential security exposure from mod_ssi arguments
+ * e.g. constructed path names from user-provided info (url-path)
+ */
+
+ size_t len = 0;
+ char *dirp = NULL;
+ if (0 == strcmp(argv[0],"/bin/sh") && argv[1] && 0 == strcmp(argv[1],"-c")){
+ /* future: consider checking for SHELL variable in environment */
+ #if 1
+ *(const char **)&argv[0] = "C:\\Windows\\System32\\cmd.exe";
+ *(const char **)&argv[1] = "/c";
+ #else
+ *(const char **)&argv[0] =
+ "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
+ #endif
+ }
+ else if (dfd <= -2) { /*(flag to chdir to directory containing argv[x])*/
+ /* dfd == -2 for argv[0], dfd == -3 indicates argv[1] */
+ const char *arg = (-3 == dfd) ? argv[1] : argv[0];
+ if (arg && (arg[0] == '\\' || arg[0] == '/' || arg[1] == ':')) {
+ /* step over "/cygdrive/c/..." (or other drive letter) -> "/..."
+ * (note: below code assumes script is on current volume)
+ * (to honor volume, could copy volume and replace '/' with ':') */
+ if (0 == memcmp(arg, "/cygdrive/", 10)
+ && arg[10] != '\0' && arg[11] == '/')
+ arg += 11;
+
+ char *sl = strrchr(arg, '/');
+ char *bs = strrchr(arg, '\\');
+ if (sl < bs) sl = bs;
+ if (sl && sl != arg) {
+ len = (size_t)(sl - arg);
+ dirp = malloc(len+1);
+ if (NULL == dirp)
+ return -1;
+ memcpy(dirp, arg, len);
+ dirp[len] = '\0';
+ }
+ }
+ } /* else expecting (-1 == dfd); this code does not handle open dirfd */
+
+ char *args = NULL;
+ len = 0;
+ for (int i = 0; argv[i]; ++i)
+ len += strlen(argv[i]) + 1;
+ if (len) {
+ args = malloc(len);
+ if (NULL == args) {
+ free(dirp);
+ return -1;
+ }
+ size_t off = 0;
+ for (int i = 0; argv[i]; ++i) {
+ len = strlen(argv[i]);
+ memcpy(args+off, argv[i], len);
+ off += len;
+ args[off++] = ' ';
+ }
+ args[off-1] = '\0'; /*(remove trailing space)*/
+ }
+
+ char *envs = NULL;
+ if (envp) {
+ int i;
+ len = 0;
+ for (i = 0; envp[i]; ++i)
+ len += strlen(envp[i]) + 1;
+ if (len) { /* MS env block size limit is SHRT_MAX (32767) */
+ qsort(envp, (size_t)i, sizeof(char *), fdevent_envcmpfunc);
+ if (++len > 32767 || NULL == (envs = malloc(len))) {
+ free(dirp);
+ free(args);
+ return -1;
+ }
+ size_t off = 0;
+ for (i = 0; envp[i]; ++i) {
+ len = strlen(envp[i]) + 1; /*(include '\0')*/
+ memcpy(envs+off, envp[i], len);
+ off += len;
+ }
+ envs[off] = '\0';
+ }
+ }
+
+ STARTUPINFOEXA info;
+ memset(&info, 0, sizeof(info));
+ LPSTARTUPINFOA sinfo = &info.StartupInfo;
+ sinfo->cb = sizeof(STARTUPINFOEX);
+ sinfo->lpDesktop = NULL;
+ sinfo->lpTitle = argv[0];
+ sinfo->dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES
+ | STARTF_USESHOWWINDOW | EXTENDED_STARTUPINFO_PRESENT;
+ sinfo->wShowWindow = SW_HIDE;
+
+ /* limit handles inherited by new process to specified stdin,stdout,stderr
+ *
+ * Programmatically controlling which handles are inherited by new processes
+ * in Win32: https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873
+ */
+ size_t sz = 0;
+ InitializeProcThreadAttributeList(NULL, 1, 0, &sz);
+ /* GetLastError() == ERROR_INSUFFICIENT_BUFFER */
+ LPPROC_THREAD_ATTRIBUTE_LIST attrlist = info.lpAttributeList = malloc(sz);
+ if (NULL == attrlist
+ || !InitializeProcThreadAttributeList(attrlist, 1, 0, &sz)
+ /* (reuse part of STARTUPINFOA for (HANDLE) list of three handles) */
+ || (UpdateProcThreadAttribute(attrlist, 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ &sinfo->hStdInput, 3*sizeof(HANDLE),
+ NULL, NULL)
+ ? 0 : (DeleteProcThreadAttributeList(attrlist), 1))) {
+ free(attrlist);
+ free(envs);
+ free(args);
+ free(dirp);
+ return -1;
+ }
+
+ #if 0
+ /* https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
+ * use _fileno() on standard streams with _get_osfhandle();
+ * avoid STD*_FILENO constants here */
+ sinfo->hStdInput =(HANDLE)_get_osfhandle(fdin >=0 ? fdin :_fileno(stdin));
+ sinfo->hStdOutput=(HANDLE)_get_osfhandle(fdout>=0 ? fdout :_fileno(stdout));
+ sinfo->hStdError =(HANDLE)_get_osfhandle(fderr>=0 ? fderr :_fileno(stderr));
+ #endif
+ if (dfd <= -2) { /* overloaded flag means _WIN32 SOCKET on fdin,fdout */
+ sinfo->hStdInput = fdin != -1 ? (HANDLE)fdin
+ : GetStdHandle(STD_INPUT_HANDLE);
+ sinfo->hStdOutput= fdout != -1 ? (HANDLE)fdout
+ : GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+ else {
+ sinfo->hStdInput = fdin >= 0 ? (HANDLE)_get_osfhandle((int)fdin)
+ : GetStdHandle(STD_INPUT_HANDLE);
+ sinfo->hStdOutput= fdout >= 0 ? (HANDLE)_get_osfhandle((int)fdout)
+ : GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+ sinfo->hStdError = fderr >= 0 ? (HANDLE)_get_osfhandle(fderr)
+ : GetStdHandle(STD_ERROR_HANDLE);
+
+ /* paranoia: all handles should be created NOINHERIT
+ * in case third-party code is not careful when calling CreateProcess()
+ * There is still a race condition setting these handles inheritable,
+ * but handles must be inheritable for use with STARTF_USESTDHANDLES */
+ if (sinfo->hStdInput != INVALID_HANDLE_VALUE)
+ SetHandleInformation(sinfo->hStdInput,
+ HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+ if (sinfo->hStdOutput!= INVALID_HANDLE_VALUE)
+ SetHandleInformation(sinfo->hStdOutput,
+ HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+ if (sinfo->hStdError != INVALID_HANDLE_VALUE)
+ SetHandleInformation(sinfo->hStdError,
+ HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+
+ PROCESS_INFORMATION pinfo;
+ memset(&pinfo, 0, sizeof(pinfo));
+ pinfo.hProcess = INVALID_HANDLE_VALUE;
+ pinfo.hThread = INVALID_HANDLE_VALUE;
+ BOOL bInheritHandles = TRUE;
+ DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS
+ | CREATE_NO_WINDOW
+ | CREATE_NEW_PROCESS_GROUP;
+ #ifdef UNICODE
+ dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
+ #endif
+ pid_t pid = (pid_t)-1;
+ if (CreateProcessA(argv[0], args, NULL, NULL, bInheritHandles,
+ dwCreationFlags, envs, dirp, sinfo, &pinfo)) {
+ CloseHandle(pinfo.hThread);
+ struct pilist *pi = ck_calloc(1, sizeof(*pi));
+ pi->hProcess = pinfo.hProcess;
+ pi->pid = pid = (pid_t)pinfo.dwProcessId;
+ pi->hWait = INVALID_HANDLE_VALUE;
+ if (!RegisterWaitForSingleObject(&pi->hWait, pi->hProcess,
+ fdevent_WaitOrTimerCallback, pi,
+ INFINITE, WT_EXECUTEONLYONCE)) {
+ /* TODO: GetLastError(); maybe hit thread pool limit (default 500)*/
+ /* failure consequence is no event received when process exits;
+ * still able to WaitForSingleObject() and signal to terminate */
+ }
+ /* note: not thread-safe */
+ pi->next = pilist;
+ pilist = pi;
+ }
+ else {
+ #if 0
+ TCHAR lpMsgBuf[1024];
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+ 0, /* MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) */
+ (LPTSTR)lpMsgBuf, sizeof(lpMsgBuf)/sizeof(TCHAR), NULL);
+ fprintf(stderr, "CreateProcess() %s: %s", args, lpMsgBuf);
+ #endif
+ /* (quiet VS Analyzer which thinks hProcess might leak w/o this) */
+ if (pinfo.hProcess != INVALID_HANDLE_VALUE)
+ CloseHandle(pinfo.hProcess);
+ if (pinfo.hThread != INVALID_HANDLE_VALUE)
+ CloseHandle(pinfo.hThread);
+ }
+
+ /* paranoia: all handles should be created NOINHERIT
+ * in case third-party code is not careful when calling CreateProcess()
+ * There is still a race condition setting these handles inheritable,
+ * but handles must be inheritable for use with STARTF_USESTDHANDLES */
+ if (sinfo->hStdInput != INVALID_HANDLE_VALUE)
+ SetHandleInformation(sinfo->hStdInput, HANDLE_FLAG_INHERIT, 0);
+ if (sinfo->hStdOutput!= INVALID_HANDLE_VALUE)
+ SetHandleInformation(sinfo->hStdOutput, HANDLE_FLAG_INHERIT, 0);
+ if (sinfo->hStdError != INVALID_HANDLE_VALUE)
+ SetHandleInformation(sinfo->hStdError, HANDLE_FLAG_INHERIT, 0);
+
+ DeleteProcThreadAttributeList(attrlist);
+ free(attrlist);
+ free(envs);
+ free(args);
+ free(dirp);
+
+ return pid;
+}
+
+
#ifdef TEST
int main (void)
{
diff --git a/src/gw_backend.c b/src/gw_backend.c
index 7765774a..2f356b53 100644
--- a/src/gw_backend.c
+++ b/src/gw_backend.c
@@ -602,6 +602,12 @@ static int gw_spawn_connection(gw_host * const host, gw_proc * const proc, log_e
env.ptr[env.used] = NULL;
}
+ #ifdef _WIN32
+ int dfd = -2; /*(flag to chdir to script dir on _WIN32)*/
+ proc->pid =
+ fdevent_createprocess(host->args.ptr,
+ env.ptr, (intptr_t)gw_fd, -1, -1, dfd);
+ #else
int dfd = fdevent_open_dirname(host->args.ptr[0], 1);/*permit symlinks*/
if (-1 == dfd) {
log_perror(errh, __FILE__, __LINE__,
@@ -613,15 +619,17 @@ static int gw_spawn_connection(gw_host * const host, gw_proc * const proc, log_e
? fdevent_fork_execve(host->args.ptr[0], host->args.ptr,
env.ptr, gw_fd, -1, -1, dfd)
: -1;
+ #endif
+ if (-1 == proc->pid)
+ log_perror(errh, __FILE__, __LINE__,
+ "gw-backend failed to start: %s", host->bin_path->ptr);
for (i = 0; i < env.used; ++i) free(env.ptr[i]);
free(env.ptr);
- if (-1 != dfd) close(dfd);
+ if (dfd >= 0) close(dfd);
close(gw_fd);
if (-1 == proc->pid) {
- log_error(errh, __FILE__, __LINE__,
- "gw-backend failed to start: %s", host->bin_path->ptr);
proc->pid = 0;
proc->disabled_until = log_monotonic_secs;
return -1;
@@ -1448,6 +1456,22 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p
break;
case 15:/* bin-copy-environment */
host->bin_env_copy = cpv->v.a;
+ #if defined(__CYGWIN__) || defined(_WIN32)
+ if (host->bin_env_copy->used) {
+ uint32_t k;
+ for (k = 0; k < cpv->v.a->used; ++k) {
+ /* search for SYSTEMROOT */
+ data_string *ds = (data_string *)cpv->v.a->data[k];
+ if (0 == strcmp(ds->value.ptr, "SYSTEMROOT"))
+ break;
+ }
+ if (k == cpv->v.a->used) {
+ array *e;
+ *(const array **)&e = cpv->v.a;
+ array_insert_value(e, CONST_STR_LEN("SYSTEMROOT"));
+ }
+ }
+ #endif
break;
case 16:/* broken-scriptfilename */
host->break_scriptfilename_for_php = (0 != cpv->v.u);
@@ -1605,6 +1629,9 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p
"and is executable by lighttpd)", host->bin_path->ptr);
}
+ #ifdef _WIN32
+ UNUSED(sh_exec); /*(no "exec " in cmd.exe; skip)*/
+ #else
if (sh_exec) {
/*(preserve prior behavior for SCGI exec of command)*/
/*(admin should really prefer to put
@@ -1626,6 +1653,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_p
host->bin_path->ptr, buffer_clen(host->bin_path)+1);
host->args.ptr[3] = NULL;
}
+ #endif
if (host->min_procs > host->max_procs)
host->min_procs = host->max_procs;
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index f7228ce7..936c3a4c 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -33,7 +33,7 @@ typedef struct {
buffer *boffsets;
buffer *ld_preload;
buffer *ld_library_path;
- #ifdef __CYGWIN__
+ #if defined(__CYGWIN__) || defined(_WIN32)
buffer *systemroot;
#endif
} env_accum;
@@ -118,7 +118,7 @@ INIT_FUNC(mod_cgi_init) {
if (s) buffer_copy_string((p->env.ld_preload = buffer_init()), s);
s = getenv("LD_LIBRARY_PATH");
if (s) buffer_copy_string((p->env.ld_library_path = buffer_init()), s);
- #ifdef __CYGWIN__
+ #if defined(__CYGWIN__) || defined(_WIN32)
/* CYGWIN needs SYSTEMROOT */
s = getenv("SYSTEMROOT");
if (s) buffer_copy_string((p->env.systemroot = buffer_init()), s);
@@ -132,7 +132,7 @@ FREE_FUNC(mod_cgi_free) {
plugin_data *p = p_d;
buffer_free(p->env.ld_preload);
buffer_free(p->env.ld_library_path);
- #ifdef __CYGWIN__
+ #if defined(__CYGWIN__) || defined(_WIN32)
buffer_free(p->env.systemroot);
#endif
@@ -900,8 +900,8 @@ static int cgi_create_env(request_st * const r, plugin_data * const p, handler_c
if (p->env.ld_library_path) {
cgi_env_add(env, CONST_STR_LEN("LD_LIBRARY_PATH"), BUF_PTR_LEN(p->env.ld_library_path));
}
- #ifdef __CYGWIN__
- /* CYGWIN needs SYSTEMROOT */
+ #if defined(__CYGWIN__) || defined(_WIN32)
+ /* CYGWIN and _WIN32 need SYSTEMROOT */
if (p->env.systemroot) {
cgi_env_add(env, CONST_STR_LEN("SYSTEMROOT"), BUF_PTR_LEN(p->env.systemroot));
}
@@ -928,6 +928,14 @@ static int cgi_create_env(request_st * const r, plugin_data * const p, handler_c
args[i ] = NULL;
}
+ #ifdef _WIN32
+ /*(flag to chdir to script dir on _WIN32)*/
+ int dfd = !buffer_is_blank(cgi_handler) ? -3 : -2;
+ int serrh_fd = r->conf.serrh ? r->conf.serrh->fd : -1;
+ pid_t pid =
+ fdevent_createprocess(args, envp, (intptr_t)to_cgi_fds[0],
+ (intptr_t)from_cgi_fds[1], serrh_fd, dfd);
+ #else
int dfd = fdevent_open_dirname(r->physical.path.ptr,r->conf.follow_symlink);
if (-1 == dfd) {
log_perror(r->conf.errh, __FILE__, __LINE__, "open dirname %s failed", r->physical.path.ptr);
@@ -938,6 +946,7 @@ static int cgi_create_env(request_st * const r, plugin_data * const p, handler_c
? fdevent_fork_execve(args[0], args, envp,
to_cgi_fds[0], from_cgi_fds[1], serrh_fd, dfd)
: -1;
+ #endif
chunk_buffer_release(env->boffsets);
chunk_buffer_release(env->b);
@@ -947,7 +956,7 @@ static int cgi_create_env(request_st * const r, plugin_data * const p, handler_c
if (-1 == pid) {
/* log error with errno prior to calling close() (might change errno) */
log_perror(r->conf.errh, __FILE__, __LINE__, "fork failed");
- if (-1 != dfd) close(dfd);
+ if (dfd >= 0) close(dfd);
close(from_cgi_fds[0]);
close(from_cgi_fds[1]);
if (0 == r->reqbody_length) {
@@ -959,7 +968,7 @@ static int cgi_create_env(request_st * const r, plugin_data * const p, handler_c
}
return -1;
} else {
- if (-1 != dfd) close(dfd);
+ if (dfd >= 0) close(dfd);
close(from_cgi_fds[1]);
hctx->fd = from_cgi_fds[0];
diff --git a/src/server.c b/src/server.c
index 9c77dc5c..b5cc1c33 100644
--- a/src/server.c
+++ b/src/server.c
@@ -110,6 +110,7 @@ static size_t malloc_top_pad;
/*#define unsetenv(name) SetEnvironmentVariable((name),NULL)*/
#define setenv(name,value,overwrite) _putenv_s((name), strdup(value))
#define unsetenv(name) _putenv_s((name), "")
+void fdevent_win32_init (volatile sig_atomic_t *ptr);
#endif
#if 1 /*(until switch to mod_h2)*/
@@ -2151,6 +2152,10 @@ static int main_init_once (void) {
setlocale(LC_TIME, "C");
tzset();
+ #ifdef _WIN32
+ fdevent_win32_init(&handle_sig_child);
+ #endif
+
return 1;
}
@@ -2198,6 +2203,9 @@ int main (int argc, char ** argv) {
chunkqueue_internal_pipes(0);
remove_pid_file(srv);
config_log_error_close(srv);
+ #ifdef _WIN32
+ fdevent_win32_cleanup();
+ #endif
if (graceful_restart)
server_sockets_save(srv);
else