diff options
Diffstat (limited to 'threadproc/win32/proc.c')
-rw-r--r-- | threadproc/win32/proc.c | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/threadproc/win32/proc.c b/threadproc/win32/proc.c new file mode 100644 index 000000000..50c454a35 --- /dev/null +++ b/threadproc/win32/proc.c @@ -0,0 +1,384 @@ +/* ==================================================================== + * Copyright (c) 1999 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group. + * For more information on the Apache Group and the Apache HTTP server + * project, please see <http://www.apache.org/>. + * + */ + +#include "threadproc.h" +#include "fileio.h" + +#include "apr_thread_proc.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_portable.h" +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <process.h> + +ap_status_t ap_createprocattr_init(ap_context_t *cont, struct procattr_t **new) +{ + (*new) = (struct procattr_t *)ap_palloc(cont, + sizeof(struct procattr_t)); + + if ((*new) == NULL) { + return APR_ENOMEM; + } + (*new)->cntxt = cont; + (*new)->parent_in = NULL; + (*new)->child_in = NULL; + (*new)->parent_out = NULL; + (*new)->child_out = NULL; + (*new)->parent_err = NULL; + (*new)->child_err = NULL; + (*new)->currdir = NULL; + (*new)->cmdtype = APR_PROGRAM; + (*new)->detached = TRUE; + + memset(&(*new)->si, 0, sizeof((*new)->si)); + + return APR_SUCCESS; +} + +ap_status_t ap_setprocattr_io(struct procattr_t *attr, ap_int32_t in, + ap_int32_t out, ap_int32_t err) +{ + ap_status_t stat; + if (in) { + if ((stat = ap_create_pipe(attr->cntxt, &attr->child_in, + &attr->parent_in)) != APR_SUCCESS) { + return stat; + } + } + if (out) { + if ((stat = ap_create_pipe(attr->cntxt, &attr->parent_out, + &attr->child_out)) != APR_SUCCESS) { + return stat; + } + } + if (err) { + if ((stat = ap_create_pipe(attr->cntxt, &attr->parent_err, + &attr->child_err)) != APR_SUCCESS) { + return stat; + } + } + return APR_SUCCESS; +} + +ap_status_t ap_setprocattr_dir(struct procattr_t *attr, + char *dir) +{ + attr->currdir = ap_pstrdup(attr->cntxt, dir); + if (attr->currdir) { + return APR_SUCCESS; + } + return APR_ENOMEM; +} + +ap_status_t ap_setprocattr_cmdtype(struct procattr_t *attr, + ap_cmdtype_e cmd) +{ + attr->cmdtype = cmd; + return APR_SUCCESS; +} + +ap_status_t ap_setprocattr_detach(struct procattr_t *attr, + ap_int32_t det) +{ + attr->detached = det; + return APR_SUCCESS; +} + +ap_status_t ap_create_process(ap_context_t *cont, char *progname, + char *const args[], char **env, + struct procattr_t *attr, struct proc_t **new) +{ + int i, iEnvBlockLen; + char *cmdline; + HANDLE hCurrentProcess; + HANDLE hParentindup, hParentoutdup,hParenterrdup; + char ppid[20]; + char *envstr; + char *pEnvBlock, *pNext; + + + + (*new) = (struct proc_t *)ap_palloc(cont, sizeof(struct proc_t)); + + if ((*new) == NULL) { + return APR_ENOMEM; + } + + (*new)->cntxt = cont; + (*new)->attr = attr; + + attr->si.cb = sizeof(attr->si); + if (attr->detached) { + /* If we are creating ourselves detached, Then we should hide the + * window we are starting in. And we had better redfine our + * handles for STDIN, STDOUT, and STDERR. + */ + attr->si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + attr->si.wShowWindow = SW_HIDE; + + if (attr->child_in) { + attr->si.hStdInput = attr->child_in->filehand; + } + + if (attr->child_out) { + attr->si.hStdOutput = attr->child_out->filehand; + } + + if (attr->child_err) { + attr->si.hStdError = attr->child_err->filehand; + } + } + + cmdline = args[0]; + i = 1; + while (args[i]) { + cmdline = ap_pstrcat(cont, cmdline, " ", args[i], NULL); + i++; + } + /* + * When the pipe handles are created, the security descriptor + * indicates that the handle can be inherited. However, we do not + * want the server side handles to the pipe to be inherited by the + * child CGI process. If the child CGI does inherit the server + * side handles, then the child may be left around if the server + * closes its handles (e.g. if the http connection is aborted), + * because the child will have a valid copy of handles to both + * sides of the pipes, and no I/O error will occur. Microsoft + * recommends using DuplicateHandle to turn off the inherit bit + * under NT and Win95. + */ + hCurrentProcess = GetCurrentProcess(); + if ((attr->child_in && !DuplicateHandle(hCurrentProcess, attr->parent_in->filehand, + hCurrentProcess, + &hParentindup, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + || (attr->child_out && !DuplicateHandle(hCurrentProcess, attr->parent_out->filehand, + hCurrentProcess, &hParentoutdup, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + || (attr->child_err && !DuplicateHandle(hCurrentProcess, attr->parent_err->filehand, + hCurrentProcess, &hParenterrdup, + 0, FALSE, DUPLICATE_SAME_ACCESS))) { + if (attr->child_in) { + ap_close(attr->child_in); + ap_close(attr->parent_in); + } + if (attr->child_out) { + ap_close(attr->child_out); + ap_close(attr->parent_out); + } + if (attr->child_err) { + ap_close(attr->child_err); + ap_close(attr->parent_err); + } + return APR_EEXIST; + } + else { + if (attr->child_in) { + ap_close(attr->parent_in); + attr->parent_in->filehand = hParentindup; + } + if (attr->child_out) { + ap_close(attr->parent_out); + attr->parent_out->filehand = hParentoutdup; + } + if (attr->child_err) { + ap_close(attr->parent_err); + attr->parent_err->filehand = hParenterrdup; + } + } + + _itoa(_getpid(), ppid, 10); + if (env) { + + envstr = ap_pstrcat(cont, "parentpid=", ppid, NULL); + /* + * Win32's CreateProcess call requires that the environment + * be passed in an environment block, a null terminated block of + * null terminated strings. + */ + i = 0; + iEnvBlockLen = 1; + while (env[i]) { + iEnvBlockLen += strlen(env[i]) + 1; + i++; + } + + pEnvBlock = (char *)ap_pcalloc(cont, iEnvBlockLen + strlen(envstr)); + + i = 0; + pNext = pEnvBlock; + while (env[i]) { + strcpy(pNext, env[i]); + pNext = pNext + strlen(pNext) + 1; + i++; + } + strcpy(pNext, envstr); + } + else { + SetEnvironmentVariable("parentpid", ppid); + pEnvBlock = NULL; + } + + + if (CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, pEnvBlock, attr->currdir, + &attr->si, &(*new)->pi)) { + if (attr->detached) { + CloseHandle((*new)->pi.hProcess); + } + if (attr->child_in) { + ap_close(attr->child_in); + } + if (attr->child_out) { + ap_close(attr->child_out); + } + if (attr->child_err) { + ap_close(attr->child_err); + } + CloseHandle((*new)->pi.hThread); + return APR_SUCCESS; + } + + return GetLastError(); +} + +ap_status_t ap_get_childin(struct proc_t *proc, ap_file_t **new) +{ + (*new) = proc->attr->parent_in; + return APR_SUCCESS; +} + +ap_status_t ap_get_childout(struct proc_t *proc, ap_file_t **new) +{ + (*new) = proc->attr->parent_out; + return APR_SUCCESS; +} + +ap_status_t ap_get_childerr(struct proc_t *proc, ap_file_t **new) +{ + (*new) = proc->attr->parent_err; + return APR_SUCCESS; +} + +ap_status_t ap_wait_proc(struct proc_t *proc, + ap_wait_how_e wait) +{ + pid_t stat; + if (!proc) + return APR_ENOPROC; + if (wait == APR_WAIT) { + if ((stat = WaitForSingleObject(proc->pi.hProcess, INFINITE)) == WAIT_OBJECT_0) { + return APR_CHILD_DONE; + } + else if (stat == WAIT_TIMEOUT) { + return APR_CHILD_NOTDONE; + } + return APR_EEXIST; + } + if ((stat = WaitForSingleObject(proc->pi.hProcess, 0)) == WAIT_OBJECT_0) { + return APR_CHILD_DONE; + } + else if (stat == WAIT_TIMEOUT) { + return APR_CHILD_NOTDONE; + } + return APR_EEXIST; +} + +ap_status_t ap_get_procdata(struct proc_t *proc, void *data) +{ + if (proc != NULL) { + return ap_get_userdata(proc->cntxt, &data); + } + else { + data = NULL; + return APR_ENOPROC; + } +} + +ap_status_t ap_set_procdata(struct proc_t *proc, void *data) +{ + if (proc != NULL) { + return ap_set_userdata(proc->cntxt, data); + } + else { + data = NULL; + return APR_ENOPROC; + } +} + +ap_status_t ap_get_os_proc(ap_proc_t *proc, ap_os_proc_t *theproc) +{ + if (proc == NULL) { + return APR_ENOPROC; + } + theproc = &(proc->pi); + return APR_SUCCESS; +} + +ap_status_t ap_put_os_proc(ap_context_t *cont, struct proc_t **proc, + ap_os_proc_t *theproc) +{ + if (cont == NULL) { + return APR_ENOCONT; + } + if ((*proc) == NULL) { + (*proc) = (struct proc_t *)ap_palloc(cont, sizeof(struct proc_t)); + (*proc)->cntxt = cont; + } + (*proc)->pi = *theproc; + return APR_SUCCESS; +} |