bjh 99/10/26 08:07:36
Modified: src/lib/apr/threadproc/os2 proc.c Log: OS/2: Make ap_create_process() work with scripts, allowing mod_cgi to work with all the CGI types it used to (REXX, Perl etc). Revision Changes Path 1.8 +148 -26 apache-2.0/src/lib/apr/threadproc/os2/proc.c Index: proc.c =================================================================== RCS file: /home/cvs/apache-2.0/src/lib/apr/threadproc/os2/proc.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- proc.c 1999/10/19 02:02:10 1.7 +++ proc.c 1999/10/26 15:07:31 1.8 @@ -159,16 +159,53 @@ return APR_INPARENT; } + + +/* quotes in the string are doubled up. + * Used to escape quotes in args passed to OS/2's cmd.exe + */ +static char *double_quotes(struct context_t *cntxt, char *str) +{ + int num_quotes = 0; + int len = 0; + char *quote_doubled_str, *dest; + + while (str[len]) { + num_quotes += str[len++] == '\"'; + } + + quote_doubled_str = ap_palloc(cntxt, len + num_quotes + 1); + dest = quote_doubled_str; + + while (*str) { + if (*str == '\"') + *(dest++) = '\"'; + *(dest++) = *(str++); + } + + *dest = 0; + return quote_doubled_str; +} + + + ap_status_t ap_create_process(struct proc_t **new, const char *progname, char *const args[], char **env, struct procattr_t *attr, ap_context_t *cont) { - int i; - ap_status_t stat; + int i, arg, numargs, cmdlen; + ap_status_t status; char **newargs; char savedir[300]; HFILE save_in, save_out, save_err, dup; int criticalsection = FALSE; + char *extension, *newprogname, *extra_arg = NULL, *cmdline, *cmdline_pos; + char interpreter[1024]; + char error_object[260]; + ap_file_t *progfile; + int env_len, e; + char *env_block, *env_block_pos; + RESULTCODES rescodes; (*new) = (struct proc_t *)ap_palloc(cont, sizeof(struct proc_t)); @@ -178,8 +215,8 @@ (*new)->cntxt = cont; (*new)->running = FALSE; - -/* Prevent other threads from running while these process-wide resources are modified */ + + /* Prevent other threads from running while these process-wide resources are modified */ if (attr->child_in || attr->child_out || attr->child_err || attr->currdir) { criticalsection = TRUE; DosEnterCritSec(); @@ -221,29 +258,114 @@ } } - if (attr->cmdtype == APR_SHELLCMD) { - i = 0; - while (args[i]) { - i++; - } - newargs = (char **)ap_palloc(cont, sizeof (char *) * (i + 3)); - newargs[0] = ap_pstrdup(cont, SHELL_PATH); - newargs[1] = ap_pstrdup(cont, "/c"); - i = 0; - - while (args[i]) { - newargs[i + 2] = ap_pstrdup(cont, args[i]); - i++; + interpreter[0] = 0; + extension = strrchr(progname, '.'); + + if (extension == NULL) + extension = ""; + + if (attr->cmdtype == APR_SHELLCMD || strcasecmp(extension, ".cmd") == 0) { + strcpy(interpreter, "#!" SHELL_PATH); + extra_arg = "/C"; + } else if (stricmp(progname, ".exe") != 0) { + status = ap_open(&progfile, progname, APR_READ|APR_BUFFERED, 0, cont); + + if (status == APR_SUCCESS) { + status = ap_fgets(interpreter, sizeof(interpreter), progfile); + + if (status == APR_SUCCESS) { + if (interpreter[0] == '#' && interpreter[1] == '!') { + if (interpreter[2] != '/' && interpreter[2] != '\\' && interpreter[3] != ':') { + char buffer[300]; + + if (DosSearchPath(SEARCH_ENVIRONMENT, "PATH", interpreter+2, buffer, sizeof(buffer)) == 0) { + strcpy(interpreter+2, buffer); + } else { + strcat(interpreter, ".exe"); + if (DosSearchPath(SEARCH_ENVIRONMENT, "PATH", interpreter+2, buffer, sizeof(buffer)) == 0) { + strcpy(interpreter+2, buffer); + } + } + } + } else { + interpreter[0] = 0; + } + } } + ap_close(progfile); + } - newargs[i + 3] = NULL; - (*new)->pid = spawnve(attr->detached ? P_DETACH : P_NOWAIT, SHELL_PATH, newargs, env); - } else { - (*new)->pid = spawnve(attr->detached ? P_DETACH : P_NOWAIT, progname, args, env); + i = 0; + + while (args && args[i]) { + i++; } - - stat = (*new)->pid < 0 ? errno : APR_SUCCESS; - + + newargs = (char **)ap_palloc(cont, sizeof (char *) * (i + 4)); + numargs = 0; + + if (interpreter[0]) + newargs[numargs++] = interpreter + 2; + if (extra_arg) + newargs[numargs++] = "/c"; + + newargs[numargs++] = newprogname = ap_pstrdup(cont, progname); + arg = 0; + + while (args && args[arg]) { + newargs[numargs++] = args[arg++]; + } + + newargs[numargs] = NULL; + + for (i=0; newprogname[i]; i++) + if (newprogname[i] == '/') + newprogname[i] = '\\'; + + cmdlen = 0; + + for (i=0; i<numargs; i++) + cmdlen += strlen(newargs[i]) + 3; + + cmdline = ap_pstrndup(cont, newargs[0], cmdlen + 2); + cmdline_pos = cmdline + strlen(cmdline); + + for (i=1; i<numargs; i++) { + char *a = newargs[i]; + + if (strpbrk(a, "&|<>\" ")) + a = ap_pstrcat(cont, "\"", double_quotes(cont, a), "\"", NULL); + + *(cmdline_pos++) = ' '; + strcpy(cmdline_pos, a); + cmdline_pos += strlen(cmdline_pos); + } + + *(++cmdline_pos) = 0; /* Add required second terminator */ + cmdline_pos = strchr(cmdline, ' '); + + if (cmdline_pos) { + *cmdline_pos = 0; + cmdline_pos++; + } + + /* Create environment block from list of envariables */ + for (env_len=1, e=0; env[e]; e++) + env_len += strlen(env[e]) + 1; + + env_block = ap_palloc(cont, env_len); + env_block_pos = env_block; + + for (e=0; env[e]; e++) { + strcpy(env_block_pos, env[e]); + env_block_pos += strlen(env_block_pos) + 1; + } + + *env_block_pos = 0; /* environment block is terminated by a double null */ + + status = DosExecPgm(error_object, sizeof(error_object), EXEC_ASYNC, cmdline, env_block, &rescodes, cmdline); + (*new)->pid = rescodes.codeTerminate; + if (attr->currdir != NULL) { chdir(savedir); } @@ -273,8 +395,8 @@ DosExitCritSec(); (*new)->attr = attr; - (*new)->running = stat == APR_SUCCESS; - return stat; + (*new)->running = status == APR_SUCCESS; + return status; }