📄 proc.c
字号:
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
* applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "win32/apr_arch_threadproc.h"
#include "win32/apr_arch_file_io.h"
#include "apr_thread_proc.h"
#include "apr_file_io.h"
#include "apr_general.h"
#include "apr_strings.h"
#include "apr_portable.h"
#include "apr_lib.h"
#include <stdlib.h>
#if APR_HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <string.h>
#if APR_HAVE_PROCESS_H
#include <process.h>
#endif
#ifdef _WIN32_WCE
#ifndef DETACHED_PROCESS
#define DETACHED_PROCESS 0
#endif
#ifndef CREATE_UNICODE_ENVIRONMENT
#define CREATE_UNICODE_ENVIRONMENT 0
#endif
#ifndef STARTF_USESHOWWINDOW
#define STARTF_USESHOWWINDOW 0
#endif
#ifndef SW_HIDE
#define SW_HIDE 0
#endif
#endif
/*
* some of the ideas expressed herein are based off of Microsoft
* Knowledge Base article: Q190351
*
*/
APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,
apr_pool_t *pool)
{
(*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
(*new)->pool = pool;
(*new)->cmdtype = APR_PROGRAM;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr,
apr_int32_t in,
apr_int32_t out,
apr_int32_t err)
{
apr_status_t stat = APR_SUCCESS;
if (in) {
/* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
* APR_PARENT_BLOCK maps to APR_READ_BLOCK, so we
* must transpose the CHILD/PARENT blocking flags
* only for the stdin pipe. stdout/stderr naturally
* map to the correct mode.
*/
if (in == APR_CHILD_BLOCK)
in = APR_READ_BLOCK;
else if (in == APR_PARENT_BLOCK)
in = APR_WRITE_BLOCK;
stat = apr_create_nt_pipe(&attr->child_in, &attr->parent_in, in,
attr->pool);
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_in);
}
if (out && stat == APR_SUCCESS) {
stat = apr_create_nt_pipe(&attr->parent_out, &attr->child_out, out,
attr->pool);
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_out);
}
if (err && stat == APR_SUCCESS) {
stat = apr_create_nt_pipe(&attr->parent_err, &attr->child_err, err,
attr->pool);
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_err);
}
return stat;
}
APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr,
apr_file_t *child_in,
apr_file_t *parent_in)
{
apr_status_t rv = APR_SUCCESS;
if (child_in) {
if (attr->child_in == NULL)
rv = apr_file_dup(&attr->child_in, child_in, attr->pool);
else
rv = apr_file_dup2(attr->child_in, child_in, attr->pool);
if (rv == APR_SUCCESS)
rv = apr_file_inherit_set(attr->child_in);
}
if (parent_in && rv == APR_SUCCESS) {
if (attr->parent_in == NULL)
rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool);
else
rv = apr_file_dup2(attr->parent_in, parent_in, attr->pool);
}
return rv;
}
APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr,
apr_file_t *child_out,
apr_file_t *parent_out)
{
apr_status_t rv = APR_SUCCESS;
if (child_out) {
if (attr->child_out == NULL)
rv = apr_file_dup(&attr->child_out, child_out, attr->pool);
else
rv = apr_file_dup2(attr->child_out, child_out, attr->pool);
if (rv == APR_SUCCESS)
rv = apr_file_inherit_set(attr->child_out);
}
if (parent_out && rv == APR_SUCCESS) {
if (attr->parent_out == NULL)
rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool);
else
rv = apr_file_dup2(attr->parent_out, parent_out, attr->pool);
}
return rv;
}
APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr,
apr_file_t *child_err,
apr_file_t *parent_err)
{
apr_status_t rv = APR_SUCCESS;
if (child_err) {
if (attr->child_err == NULL)
rv = apr_file_dup(&attr->child_err, child_err, attr->pool);
else
rv = apr_file_dup2(attr->child_err, child_err, attr->pool);
if (rv == APR_SUCCESS)
rv = apr_file_inherit_set(attr->child_err);
}
if (parent_err && rv == APR_SUCCESS) {
if (attr->parent_err == NULL)
rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool);
else
rv = apr_file_dup2(attr->parent_err, parent_err, attr->pool);
}
return rv;
}
APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr,
const char *dir)
{
/* curr dir must be in native format, there are all sorts of bugs in
* the NT library loading code that flunk the '/' parsing test.
*/
return apr_filepath_merge(&attr->currdir, NULL, dir,
APR_FILEPATH_NATIVE, attr->pool);
}
APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
apr_cmdtype_e cmd)
{
attr->cmdtype = cmd;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr,
apr_int32_t det)
{
attr->detached = det;
return APR_SUCCESS;
}
static const char* has_space(const char *str)
{
const char *ch;
for (ch = str; *ch; ++ch) {
if (apr_isspace(*ch)) {
return ch;
}
}
return NULL;
}
static char *apr_caret_escape_args(apr_pool_t *p, const char *str)
{
char *cmd;
unsigned char *d;
const unsigned char *s;
cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
d = (unsigned char *)cmd;
s = (const unsigned char *)str;
for (; *s; ++s) {
/*
* Newlines to Win32/OS2 CreateProcess() are ill advised.
* Convert them to spaces since they are effectively white
* space to most applications
*/
if (*s == '\r' || *s == '\n') {
*d++ = ' ';
continue;
}
if (IS_SHCHAR(*s)) {
*d++ = '^';
}
*d++ = *s;
}
*d = '\0';
return cmd;
}
APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
apr_child_errfn_t *errfn)
{
attr->errfn = errfn;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
apr_int32_t chk)
{
attr->errchk = chk;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
apr_int32_t addrspace)
{
/* won't ever be used on this platform, so don't save the flag */
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
const char *progname,
const char * const *args,
const char * const *env,
apr_procattr_t *attr,
apr_pool_t *pool)
{
apr_status_t rv;
apr_size_t i;
const char *argv0;
char *cmdline;
char *pEnvBlock;
PROCESS_INFORMATION pi;
DWORD dwCreationFlags = 0;
new->in = attr->parent_in;
new->out = attr->parent_out;
new->err = attr->parent_err;
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. Do not set the
* detached attribute for Win9x. We have found that Win9x does
* not manage the stdio handles properly when running old 16
* bit executables if the detached attribute is set.
*/
if (apr_os_level >= APR_WIN_NT) {
/*
* XXX DETACHED_PROCESS won't on Win9x at all; on NT/W2K
* 16 bit executables fail (MS KB: Q150956)
*/
dwCreationFlags |= DETACHED_PROCESS;
}
}
/* progname must be unquoted, in native format, as there are all sorts
* of bugs in the NT library loader code that fault when parsing '/'.
* XXX progname must be NULL if this is a 16 bit app running in WOW
*/
if (progname[0] == '\"') {
progname = apr_pstrndup(pool, progname + 1, strlen(progname) - 2);
}
if (attr->cmdtype == APR_PROGRAM || attr->cmdtype == APR_PROGRAM_ENV) {
char *fullpath = NULL;
if ((rv = apr_filepath_merge(&fullpath, attr->currdir, progname,
APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(pool, rv,
apr_pstrcat(pool, "filepath_merge failed.",
" currdir: ", attr->currdir,
" progname: ", progname,NULL));
}
return rv;
}
progname = fullpath;
}
else {
/* Do not fail if the path isn't parseable for APR_PROGRAM_PATH
* or APR_SHELLCMD. We only invoke apr_filepath_merge (with no
* left hand side expression) in order to correct the path slash
* delimiters. But the filename doesn't need to be in the CWD,
* nor does it need to be a filename at all (it could be a
* built-in shell command.)
*/
char *fullpath = NULL;
if ((rv = apr_filepath_merge(&fullpath, "", progname,
APR_FILEPATH_NATIVE, pool)) == APR_SUCCESS) {
progname = fullpath;
}
}
if (has_space(progname)) {
argv0 = apr_pstrcat(pool, "\"", progname, "\"", NULL);
}
else {
argv0 = progname;
}
/* Handle the args, seperate from argv0 */
cmdline = "";
for (i = 1; args && args[i]; ++i) {
if (has_space(args[i])) {
cmdline = apr_pstrcat(pool, cmdline, " \"", args[i], "\"", NULL);
}
else {
cmdline = apr_pstrcat(pool, cmdline, " ", args[i], NULL);
}
}
#ifndef _WIN32_WCE
if (attr->cmdtype == APR_SHELLCMD || attr->cmdtype == APR_SHELLCMD_ENV) {
char *shellcmd = getenv("COMSPEC");
if (!shellcmd) {
if (attr->errfn) {
attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set");
}
return APR_EINVAL;
}
if (shellcmd[0] == '"') {
progname = apr_pstrndup(pool, shellcmd + 1, strlen(shellcmd) - 2);
}
else {
progname = shellcmd;
if (has_space(shellcmd)) {
shellcmd = apr_pstrcat(pool, "\"", shellcmd, "\"", NULL);
}
}
/* Command.com does not support a quoted command, while cmd.exe demands one.
*/
i = strlen(progname);
if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -