Apache HTTPD
proc.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define INCL_DOS
18#define INCL_DOSERRORS
19
20#include "apr_arch_threadproc.h"
21#include "apr_arch_file_io.h"
22#include "apr_private.h"
23#include "apr_thread_proc.h"
24#include "apr_file_io.h"
25#include "apr_general.h"
26#include "apr_lib.h"
27#include "apr_portable.h"
28#include "apr_strings.h"
29#include "apr_signal.h"
30#include <signal.h>
31#include <string.h>
32#include <sys/wait.h>
33#include <unistd.h>
34#include <process.h>
35#include <stdlib.h>
36
37/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
38 * requested for a specific child handle;
39 */
40static apr_file_t no_file = { NULL, -1, };
41
43{
44 (*new) = (apr_procattr_t *)apr_palloc(pool,
45 sizeof(apr_procattr_t));
46
47 if ((*new) == NULL) {
48 return APR_ENOMEM;
49 }
50 (*new)->pool = pool;
51 (*new)->parent_in = NULL;
52 (*new)->child_in = NULL;
53 (*new)->parent_out = NULL;
54 (*new)->child_out = NULL;
55 (*new)->parent_err = NULL;
56 (*new)->child_err = NULL;
57 (*new)->currdir = NULL;
58 (*new)->cmdtype = APR_PROGRAM;
59 (*new)->detached = FALSE;
60 return APR_SUCCESS;
61}
62
67{
68 apr_status_t rv;
69
70 if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) {
71 /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
72 * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose
73 * the CHILD/PARENT blocking flags for the stdin pipe.
74 * stdout/stderr map to the correct mode by default.
75 */
76 if (in == APR_CHILD_BLOCK)
78 else if (in == APR_PARENT_BLOCK)
80
82 in, attr->pool)) == APR_SUCCESS)
84 if (rv != APR_SUCCESS)
85 return rv;
86 }
87 else if (in == APR_NO_FILE)
89
90 if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) {
92 out, attr->pool)) == APR_SUCCESS)
94 if (rv != APR_SUCCESS)
95 return rv;
96 }
97 else if (out == APR_NO_FILE)
99
100 if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) {
102 err, attr->pool)) == APR_SUCCESS)
104 if (rv != APR_SUCCESS)
105 return rv;
106 }
107 else if (err == APR_NO_FILE)
109
110 return APR_SUCCESS;
111}
112
115{
116 apr_status_t rv;
117
118 if (attr->child_in == NULL && attr->parent_in == NULL
119 && child_in == NULL && parent_in == NULL)
121 attr->pool)) == APR_SUCCESS)
123
124 if (child_in != NULL && rv == APR_SUCCESS) {
125 if (attr->child_in && (attr->child_in->filedes != -1))
127 else {
128 attr->child_in = NULL;
129 if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool))
130 == APR_SUCCESS)
132 }
133 }
134
135 if (parent_in != NULL && rv == APR_SUCCESS) {
137 }
138
139 return rv;
140}
141
144{
145 apr_status_t rv;
146
147 if (attr->child_out == NULL && attr->parent_out == NULL
148 && child_out == NULL && parent_out == NULL)
150 attr->pool)) == APR_SUCCESS)
152
153 if (child_out != NULL && rv == APR_SUCCESS) {
154 if (attr->child_out && (attr->child_out->filedes != -1))
156 else {
159 == APR_SUCCESS)
161 }
162 }
163
164 if (parent_out != NULL && rv == APR_SUCCESS) {
166 }
167
168 return rv;
169}
170
173{
174 apr_status_t rv;
175
176 if (attr->child_err == NULL && attr->parent_err == NULL
177 && child_err == NULL && parent_err == NULL)
179 attr->pool)) == APR_SUCCESS)
181
182 if (child_err != NULL && rv == APR_SUCCESS) {
183 if (attr->child_err && (attr->child_err->filedes != -1))
185 else {
188 == APR_SUCCESS)
190 }
191 }
192
193 if (parent_err != NULL && rv == APR_SUCCESS) {
195 }
196
197 return rv;
198}
199
201{
203 if (attr->currdir) {
204 return APR_SUCCESS;
205 }
206 return APR_ENOMEM;
207}
208
211{
212 attr->cmdtype = cmd;
213 return APR_SUCCESS;
214}
215
217{
219 return APR_SUCCESS;
220}
221
223{
224 int pid;
225
226 if ((pid = fork()) < 0) {
227 return errno;
228 }
229 else if (pid == 0) {
230 proc->pid = pid;
231 proc->in = NULL;
232 proc->out = NULL;
233 proc->err = NULL;
234 return APR_INCHILD;
235 }
236 proc->pid = pid;
237 proc->in = NULL;
238 proc->out = NULL;
239 proc->err = NULL;
240 return APR_INPARENT;
241}
242
243
244
245/* quotes in the string are doubled up.
246 * Used to escape quotes in args passed to OS/2's cmd.exe
247 */
248static char *double_quotes(apr_pool_t *pool, const char *str)
249{
250 int num_quotes = 0;
251 int len = 0;
252 char *quote_doubled_str, *dest;
253
254 while (str[len]) {
255 num_quotes += str[len++] == '\"';
256 }
257
260
261 while (*str) {
262 if (*str == '\"')
263 *(dest++) = '\"';
264 *(dest++) = *(str++);
265 }
266
267 *dest = 0;
268 return quote_doubled_str;
269}
270
271
272
275{
276 /* won't ever be called on this platform, so don't save the function pointer */
277 return APR_SUCCESS;
278}
279
280
281
284{
285 /* won't ever be used on this platform, so don't save the flag */
286 return APR_SUCCESS;
287}
288
291{
292 /* won't ever be used on this platform, so don't save the flag */
293 return APR_SUCCESS;
294}
295
296
297
299 const char * const *args,
300 const char * const *env,
302{
303 int i, arg, numargs, cmdlen;
305 const char **newargs;
306 char savedir[300];
310 char interpreter[1024];
311 char error_object[260];
313 int env_len, e;
314 char *env_block, *env_block_pos;
316
317 proc->in = attr->parent_in;
320
321 /* Prevent other threads from running while these process-wide resources are modified */
325 }
326
327 if (attr->child_in) {
328 save_in = -1;
331 if (attr->child_in->filedes == -1)
332 DosClose(dup);
333 else
335 }
336
337 if (attr->child_out) {
338 save_out = -1;
341 if (attr->child_out->filedes == -1)
342 DosClose(dup);
343 else
345 }
346
347 if (attr->child_err) {
348 save_err = -1;
351 if (attr->child_err->filedes == -1)
352 DosClose(dup);
353 else
355 }
356
357 apr_signal(SIGCHLD, SIG_DFL); /*not sure if this is needed or not */
358
359 if (attr->currdir != NULL) {
360 _getcwd2(savedir, sizeof(savedir));
361
362 if (_chdir2(attr->currdir) < 0) {
363 if (criticalsection)
365 return errno;
366 }
367 }
368
369 interpreter[0] = 0;
370 extension = strrchr(progname, '.');
371
372 if (extension == NULL || strchr(extension, '/') || strchr(extension, '\\'))
373 extension = "";
374
375 /* ### how to handle APR_PROGRAM_ENV and APR_PROGRAM_PATH? */
376
377 if (attr->cmdtype == APR_SHELLCMD ||
379 strcasecmp(extension, ".cmd") == 0) {
381 extra_arg = "/C";
382 } else if (stricmp(extension, ".exe") != 0) {
384
387 }
388
389 if (status == APR_SUCCESS) {
391
392 if (status == APR_SUCCESS) {
393 if (interpreter[0] == '#' && interpreter[1] == '!') {
394 /* delete CR/LF & any other whitespace off the end */
395 int end = strlen(interpreter) - 1;
396
397 while (end >= 0 && apr_isspace(interpreter[end])) {
398 interpreter[end] = '\0';
399 end--;
400 }
401
402 if (interpreter[2] != '/' && interpreter[2] != '\\' && interpreter[3] != ':') {
403 char buffer[300];
404
405 if (DosSearchPath(SEARCH_ENVIRONMENT, "PATH", interpreter+2, buffer, sizeof(buffer)) == 0) {
407 } else {
408 strcat(interpreter, ".exe");
409 if (DosSearchPath(SEARCH_ENVIRONMENT, "PATH", interpreter+2, buffer, sizeof(buffer)) == 0) {
411 }
412 }
413 }
414 } else {
415 interpreter[0] = 0;
416 }
417 }
418
420 }
421 }
422
423 i = 0;
424
425 while (args && args[i]) {
426 i++;
427 }
428
429 newargs = (const char **)apr_palloc(pool, sizeof (char *) * (i + 4));
430 numargs = 0;
431
432 if (interpreter[0])
433 newargs[numargs++] = interpreter + 2;
434 if (extra_arg)
435 newargs[numargs++] = "/c";
436
438 arg = 1;
439
440 while (args && args[arg]) {
441 newargs[numargs++] = args[arg++];
442 }
443
445
446 for (i=0; newprogname[i]; i++)
447 if (newprogname[i] == '/')
448 newprogname[i] = '\\';
449
450 cmdlen = 0;
451
452 for (i=0; i<numargs; i++)
453 cmdlen += strlen(newargs[i]) + 3;
454
457
458 for (i=0; i<numargs; i++) {
459 const char *a = newargs[i];
460
461 if (strpbrk(a, "&|<>\" "))
462 a = apr_pstrcat(pool, "\"", double_quotes(pool, a), "\"", NULL);
463
464 if (i)
465 *(cmdline_pos++) = ' ';
466
468 cmdline_pos += strlen(cmdline_pos);
469 }
470
471 *(++cmdline_pos) = 0; /* Add required second terminator */
472 cmdline_pos = strchr(cmdline, ' ');
473
474 if (cmdline_pos) {
475 *cmdline_pos = 0;
476 cmdline_pos++;
477 }
478
479 /* Create environment block from list of envariables */
480 if (env) {
481 for (env_len=1, e=0; env[e]; e++)
482 env_len += strlen(env[e]) + 1;
483
486
487 for (e=0; env[e]; e++) {
489 env_block_pos += strlen(env_block_pos) + 1;
490 }
491
492 *env_block_pos = 0; /* environment block is terminated by a double null */
493 } else
494 env_block = NULL;
495
499
500 proc->pid = rescodes.codeTerminate;
501
502 if (attr->currdir != NULL) {
503 chdir(savedir);
504 }
505
506 if (attr->child_in) {
507 if (attr->child_in->filedes != -1) {
509 }
510
514 }
515
516 if (attr->child_out) {
517 if (attr->child_out->filedes != -1) {
519 }
520
524 }
525
526 if (attr->child_err) {
527 if (attr->child_err->filedes != -1) {
529 }
530
534 }
535
536 if (criticalsection)
538
539 return status;
540}
541
542
543
545 int *exitcode,
547{
548 int result = 0;
550
551 switch (codes.codeTerminate) {
552 case TC_EXIT: /* Normal exit */
554 result = codes.codeResult;
555 break;
556
557 case TC_HARDERROR: /* Hard error halt */
559 result = SIGSYS;
560 break;
561
562 case TC_KILLPROCESS: /* Was killed by a DosKillProcess() */
564 result = SIGKILL;
565 break;
566
567 case TC_TRAP: /* TRAP in 16 bit code */
568 case TC_EXCEPTION: /* Threw an exception (32 bit code) */
570
571 switch (codes.codeResult | XCPT_FATAL_EXCEPTION) {
573 result = SIGSEGV;
574 break;
575
577 result = SIGILL;
578 break;
579
582 result = SIGFPE;
583 break;
584
585 default:
586 result = codes.codeResult;
587 break;
588 }
589 }
590
591 if (exitcode) {
592 *exitcode = result;
593 }
594
595 if (exitwhy) {
596 *exitwhy = why;
597 }
598}
599
600
601
603 int *exitcode,
606 apr_pool_t *p)
607{
609 ULONG rc;
610 PID pid;
611
613
614 if (rc == 0) {
615 proc->pid = pid;
617 return APR_CHILD_DONE;
618 } else if (rc == ERROR_CHILD_NOT_COMPLETE) {
619 return APR_CHILD_NOTDONE;
620 }
621
622 return APR_OS2_STATUS(rc);
623}
624
625
626
630{
632 ULONG rc;
633 PID pid;
635
636 if (rc == 0) {
638 return APR_CHILD_DONE;
639 } else if (rc == ERROR_CHILD_NOT_COMPLETE) {
640 return APR_CHILD_NOTDONE;
641 }
642
643 return APR_OS2_STATUS(rc);
644}
645
646
647
649{
650 return APR_ENOTIMPL;
651}
652
654 const char *username,
655 const char *password)
656{
657 return APR_ENOTIMPL;
658}
659
661 const char *groupname)
662{
663 return APR_ENOTIMPL;
664}
665
668 void *data,
670{
671 return APR_ENOTIMPL;
672}
const char apr_size_t len
Definition ap_regex.h:187
#define TRUE
Definition abts.h:38
#define FALSE
Definition abts.h:35
APR File I/O Handling.
APR Miscellaneous library routines.
APR general purpose library routines.
APR Portability Routines.
APR Signal Handling.
APR Strings library.
APR Thread and Process Library.
#define SHELL_PATH
static apr_file_t no_file
Definition proc.c:23
void const char * arg
Definition http_vhost.h:63
#define APR_CHILD_NOTDONE
Definition apr_errno.h:448
#define APR_CHILD_DONE
Definition apr_errno.h:446
#define APR_INCHILD
Definition apr_errno.h:438
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_INPARENT
Definition apr_errno.h:440
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_STATUS_IS_ENOENT(s)
Definition apr_errno.h:1246
apr_bucket * e
apr_bucket apr_bucket_brigade * a
apr_redis_t * rc
Definition apr_redis.h:173
const void apr_status_t(*) apr_status_t(* APR_DECLARE)(void) apr_pool_pre_cleanup_register(apr_pool_t *p
Definition apr_pools.h:646
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define apr_isspace(c)
Definition apr_lib.h:225
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_int32_t apr_fileperms_t
const char apr_fileperms_t perms
void * data
char * buffer
#define APR_READ
Definition apr_file_io.h:93
#define APR_BUFFERED
apr_array_header_t ** result
int strcasecmp(const char *a, const char *b)
char const *const char const *const ** env
apr_status_t() apr_perms_setfn_t(void *object, apr_fileperms_t perms, apr_uid_t uid, apr_gid_t gid)
apr_dir_t * dir
#define apr_signal(a, b)
Definition apr_signal.h:71
const char char ** end
apr_proc_t * proc
const char const char * password
apr_int32_t apr_int32_t apr_int32_t err
apr_file_t apr_file_t * parent_out
apr_perms_setfn_t * perms_set_fn
const char const char *const const char *const apr_procattr_t * attr
void() apr_child_errfn_t(apr_pool_t *proc, apr_status_t err, const char *description)
apr_int32_t in
apr_child_errfn_t * errfn
#define APR_WRITE_BLOCK
const char * groupname
#define APR_NO_FILE
apr_int32_t addrspace
apr_wait_how_e
int apr_exit_why_e * exitwhy
apr_cmdtype_e cmd
apr_int32_t chk
apr_file_t apr_file_t * parent_in
#define APR_PARENT_BLOCK
apr_file_t * child_err
const char const char *const * args
#define APR_NO_PIPE
const char * username
apr_exit_why_e
int apr_exit_why_e apr_wait_how_e waithow
#define APR_CHILD_BLOCK
const char * progname
apr_cmdtype_e
apr_int32_t detach
int * exitcode
int int status
apr_file_t * child_out
apr_file_t apr_file_t * parent_err
apr_file_t * child_in
#define APR_READ_BLOCK
@ APR_WAIT
@ APR_PROC_SIGNAL
@ APR_PROC_EXIT
@ APR_SHELLCMD
@ APR_PROGRAM
@ APR_SHELLCMD_ENV
apr_pool_t * p
Definition md_event.c:32
static apr_file_t * out
Definition mod_info.c:85
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
apr_status_t apr_proc_detach(int daemonize)
Definition procsup.c:19
static char * double_quotes(apr_pool_t *pool, const char *str)
Definition proc.c:248
static void proces_result_codes(RESULTCODES codes, int *exitcode, apr_exit_why_e *exitwhy)
Definition proc.c:544
apr_pool_t * pool
apr_file_t * in
apr_file_t * out
apr_file_t * err
apr_file_t * child_err
apr_file_t * parent_in
apr_file_t * parent_out
apr_file_t * child_out
apr_file_t * child_in
apr_file_t * parent_err
#define str