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#include "apr_arch_threadproc.h"
18#include "apr_arch_file_io.h"
19
20#include "apr_thread_proc.h"
21#include "apr_file_io.h"
22#include "apr_general.h"
23#include "apr_strings.h"
24#include "apr_portable.h"
25#include "apr_lib.h"
26#include <stdlib.h>
27#if APR_HAVE_SIGNAL_H
28#include <signal.h>
29#endif
30#include <string.h>
31#if APR_HAVE_PROCESS_H
32#include <process.h>
33#endif
34
35/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
36 * requested for a specific child handle;
37 */
39
40/* We have very carefully excluded volumes of definitions from the
41 * Microsoft Platform SDK, which kill the build time performance.
42 * These the sole constants we borrow from WinBase.h and WinUser.h
43 */
44#ifndef LOGON32_LOGON_NETWORK
45#define LOGON32_LOGON_NETWORK 3
46#endif
47
48#ifdef _WIN32_WCE
49#ifndef DETACHED_PROCESS
50#define DETACHED_PROCESS 0
51#endif
52#ifndef CREATE_UNICODE_ENVIRONMENT
53#define CREATE_UNICODE_ENVIRONMENT 0
54#endif
55#ifndef STARTF_USESHOWWINDOW
56#define STARTF_USESHOWWINDOW 0
57#endif
58#ifndef SW_HIDE
59#define SW_HIDE 0
60#endif
61#endif
62
63/*
64 * some of the ideas expressed herein are based off of Microsoft
65 * Knowledge Base article: Q190351
66 *
67 */
70{
71 (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
72 (*new)->pool = pool;
73 (*new)->cmdtype = APR_PROGRAM;
74 return APR_SUCCESS;
75}
76
81{
83
84 if (in) {
85 /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
86 * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose
87 * the CHILD/PARENT blocking flags for the stdin pipe.
88 * stdout/stderr map to the correct mode by default.
89 */
90 if (in == APR_CHILD_BLOCK)
92 else if (in == APR_PARENT_BLOCK)
94
95 if (in == APR_NO_FILE)
97 else {
99 in, attr->pool);
100 }
101 if (stat == APR_SUCCESS)
103 }
104 if (out && stat == APR_SUCCESS) {
105 if (out == APR_NO_FILE)
107 else {
109 out, attr->pool);
110 }
111 if (stat == APR_SUCCESS)
113 }
114 if (err && stat == APR_SUCCESS) {
115 if (err == APR_NO_FILE)
117 else {
119 err, attr->pool);
120 }
121 if (stat == APR_SUCCESS)
123 }
124 return stat;
125}
126
130{
132
133 if (child_in) {
134 if ((attr->child_in == NULL) || (attr->child_in == &no_file))
136 else
138
139 if (rv == APR_SUCCESS)
141 }
142
143 if (parent_in && rv == APR_SUCCESS) {
144 if (attr->parent_in == NULL)
146 else
148 }
149
150 return rv;
151}
152
156{
158
159 if (child_out) {
160 if ((attr->child_out == NULL) || (attr->child_out == &no_file))
162 else
164
165 if (rv == APR_SUCCESS)
167 }
168
169 if (parent_out && rv == APR_SUCCESS) {
170 if (attr->parent_out == NULL)
172 else
174 }
175
176 return rv;
177}
178
182{
184
185 if (child_err) {
186 if ((attr->child_err == NULL) || (attr->child_err == &no_file))
188 else
190
191 if (rv == APR_SUCCESS)
193 }
194
195 if (parent_err && rv == APR_SUCCESS) {
196 if (attr->parent_err == NULL)
198 else
200 }
201
202 return rv;
203}
204
206 const char *dir)
207{
208 /* curr dir must be in native format, there are all sorts of bugs in
209 * the NT library loading code that flunk the '/' parsing test.
210 */
213}
214
217{
218 attr->cmdtype = cmd;
219 return APR_SUCCESS;
220}
221
224{
225 attr->detached = det;
226 return APR_SUCCESS;
227}
228
229#ifndef _WIN32_WCE
238#endif
239
241 const char *username,
242 const char *password)
243{
244#ifdef _WIN32_WCE
245 return APR_ENOTIMPL;
246#else
247 HANDLE user;
250 apr_status_t rv;
252
254 {
255 if (attr->user_token) {
256 /* Cannot set that twice */
257 if (attr->errfn) {
258 attr->errfn(attr->pool, 0,
260 "function called twice"
261 " on username: ", username, NULL));
262 }
263 return APR_EINVAL;
264 }
265 len = strlen(username) + 1;
266 wlen = len;
269 != APR_SUCCESS) {
270 if (attr->errfn) {
271 attr->errfn(attr->pool, rv,
273 "utf8 to ucs2 conversion failed"
274 " on username: ", username, NULL));
275 }
276 return rv;
277 }
278 if (password) {
279 len = strlen(password) + 1;
280 wlen = len;
283 != APR_SUCCESS) {
284 if (attr->errfn) {
285 attr->errfn(attr->pool, rv,
287 "utf8 to ucs2 conversion failed"
288 " on password: ", password, NULL));
289 }
290 return rv;
291 }
292 }
293 if (!LogonUserW(wusername,
294 NULL,
295 wpassword ? wpassword : L"",
298 &user)) {
299 /* Logon Failed */
300 return apr_get_os_error();
301 }
302 if (wpassword)
303 memset(wpassword, 0, wlen * sizeof(apr_wchar_t));
304 /* Get the primary token for user */
305 if (!DuplicateTokenEx(user,
307 NULL,
310 &(attr->user_token))) {
311 /* Failed to duplicate the user token */
312 rv = apr_get_os_error();
313 CloseHandle(user);
314 return rv;
315 }
316 CloseHandle(user);
317
322 attr->sa->nLength = sizeof (SECURITY_ATTRIBUTES);
323 attr->sa->lpSecurityDescriptor = attr->sd;
324 attr->sa->bInheritHandle = FALSE;
325
326 /* register the cleanup */
330 return APR_SUCCESS;
331 }
332 else
333 return APR_ENOTIMPL;
334#endif
335}
336
338 const char *groupname)
339{
340 /* Always return SUCCESS cause groups are irrelevant */
341 return APR_SUCCESS;
342}
343
344static const char* has_space(const char *str)
345{
346 const char *ch;
347 for (ch = str; *ch; ++ch) {
348 if (apr_isspace(*ch)) {
349 return ch;
350 }
351 }
352 return NULL;
353}
354
355static char *apr_caret_escape_args(apr_pool_t *p, const char *str)
356{
357 char *cmd;
358 unsigned char *d;
359 const unsigned char *s;
360
361 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
362 d = (unsigned char *)cmd;
363 s = (const unsigned char *)str;
364 for (; *s; ++s) {
365
366 /*
367 * Newlines to Win32/OS2 CreateProcess() are ill advised.
368 * Convert them to spaces since they are effectively white
369 * space to most applications
370 */
371 if (*s == '\r' || *s == '\n') {
372 *d++ = ' ';
373 continue;
374 }
375
376 if (IS_SHCHAR(*s)) {
377 *d++ = '^';
378 }
379 *d++ = *s;
380 }
381 *d = '\0';
382
383 return cmd;
384}
385
388{
389 attr->errfn = errfn;
390 return APR_SUCCESS;
391}
392
395{
396 attr->errchk = chk;
397 return APR_SUCCESS;
398}
399
402{
403 /* won't ever be used on this platform, so don't save the flag */
404 return APR_SUCCESS;
405}
406
407#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE)
408
409/* Used only for the NT code path, a critical section is the fastest
410 * implementation available.
411 */
413
415{
417 return APR_SUCCESS;
418}
419
420/* Called from apr_initialize, we need a critical section to handle
421 * the pipe inheritance on win32. This will mutex any process create
422 * so as we change our inherited pipes, we prevent another process from
423 * also inheriting those alternate handles, and prevent the other process
424 * from failing to inherit our standard handles.
425 */
427{
429 {
431 /* register the cleanup */
435 }
436 return APR_SUCCESS;
437}
438
439#else /* !APR_HAS_UNICODE_FS || defined(_WIN32_WCE) */
440
445
446#endif
447
449 const char *progname,
450 const char * const *args,
451 const char * const *env,
454{
455 apr_status_t rv;
457 const char *argv0;
458 char *cmdline;
459 char *pEnvBlock;
462
463 new->in = attr->parent_in;
464 new->out = attr->parent_out;
465 new->err = attr->parent_err;
466
467 if (attr->detached) {
468 /* If we are creating ourselves detached, then we should hide the
469 * window we are starting in. And we had better redefine our
470 * handles for STDIN, STDOUT, and STDERR. Do not set the
471 * detached attribute for Win9x. We have found that Win9x does
472 * not manage the stdio handles properly when running old 16
473 * bit executables if the detached attribute is set.
474 */
475 if (apr_os_level >= APR_WIN_NT) {
476 /*
477 * XXX DETACHED_PROCESS won't on Win9x at all; on NT/W2K
478 * 16 bit executables fail (MS KB: Q150956)
479 */
481 }
482 }
483
484 /* progname must be unquoted, in native format, as there are all sorts
485 * of bugs in the NT library loader code that fault when parsing '/'.
486 * XXX progname must be NULL if this is a 16 bit app running in WOW
487 */
488 if (progname[0] == '\"') {
489 progname = apr_pstrmemdup(pool, progname + 1, strlen(progname) - 2);
490 }
491
493 char *fullpath = NULL;
496 if (attr->errfn) {
497 attr->errfn(pool, rv,
498 apr_pstrcat(pool, "filepath_merge failed.",
499 " currdir: ", attr->currdir,
500 " progname: ", progname, NULL));
501 }
502 return rv;
503 }
505 }
506 else {
507 /* Do not fail if the path isn't parseable for APR_PROGRAM_PATH
508 * or APR_SHELLCMD. We only invoke apr_filepath_merge (with no
509 * left hand side expression) in order to correct the path slash
510 * delimiters. But the filename doesn't need to be in the CWD,
511 * nor does it need to be a filename at all (it could be a
512 * built-in shell command.)
513 */
514 char *fullpath = NULL;
515 if ((rv = apr_filepath_merge(&fullpath, "", progname,
518 }
519 }
520
521 if (has_space(progname)) {
522 argv0 = apr_pstrcat(pool, "\"", progname, "\"", NULL);
523 }
524 else {
525 argv0 = progname;
526 }
527
528 /* Handle the args, seperate from argv0 */
529 cmdline = "";
530 for (i = 1; args && args[i]; ++i) {
531 if (has_space(args[i]) || !args[i][0]) {
532 cmdline = apr_pstrcat(pool, cmdline, " \"", args[i], "\"", NULL);
533 }
534 else {
536 }
537 }
538
539#ifndef _WIN32_WCE
541 char *shellcmd = getenv("COMSPEC");
542 if (!shellcmd) {
543 if (attr->errfn) {
544 attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set");
545 }
546 return APR_EINVAL;
547 }
548 if (shellcmd[0] == '"') {
549 progname = apr_pstrmemdup(pool, shellcmd + 1, strlen(shellcmd) - 2);
550 }
551 else {
553 if (has_space(shellcmd)) {
554 shellcmd = apr_pstrcat(pool, "\"", shellcmd, "\"", NULL);
555 }
556 }
557 /* Command.com does not support a quoted command, while cmd.exe demands one.
558 */
559 i = strlen(progname);
560 if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) {
562 }
563 else {
564 cmdline = apr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL);
565 }
566 }
567 else
568#endif
569 {
570#if defined(_WIN32_WCE)
571 {
572#else
573 /* Win32 is _different_ than unix. While unix will find the given
574 * program since it's already chdir'ed, Win32 cannot since the parent
575 * attempts to open the program with it's own path.
576 * ###: This solution isn't much better - it may defeat path searching
577 * when the path search was desired. Open to further discussion.
578 */
579 i = strlen(progname);
580 if (i >= 4 && (strcasecmp(progname + i - 4, ".bat") == 0
581 || strcasecmp(progname + i - 4, ".cmd") == 0))
582 {
583 char *shellcmd = getenv("COMSPEC");
584 if (!shellcmd) {
585 if (attr->errfn) {
586 attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set");
587 }
588 return APR_EINVAL;
589 }
590 if (shellcmd[0] == '"') {
591 progname = apr_pstrmemdup(pool, shellcmd + 1, strlen(shellcmd) - 2);
592 }
593 else {
595 if (has_space(shellcmd)) {
596 shellcmd = apr_pstrcat(pool, "\"", shellcmd, "\"", NULL);
597 }
598 }
599 i = strlen(progname);
600 if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) {
601 /* XXX: Still insecure - need doubled-quotes on each individual
602 * arg of cmdline. Suspect we need to postpone cmdline parsing
603 * until this moment in all four code paths, with some flags
604 * to toggle 'which flavor' is needed.
605 */
607 }
608 else {
609 /* We must protect the cmdline args from any interpolation - this
610 * is not a shellcmd, and the source of argv[] is untrusted.
611 * Notice we escape ALL the cmdline args, including the quotes
612 * around the individual args themselves. No sense in allowing
613 * the shift-state to be toggled, and the application will
614 * not see the caret escapes.
615 */
617 /*
618 * Our app name must always be quoted so the quotes surrounding
619 * the entire /c "command args" are unambigious.
620 */
621 if (*argv0 != '"') {
622 cmdline = apr_pstrcat(pool, shellcmd, " /C \"\"", argv0, "\"", cmdline, "\"", NULL);
623 }
624 else {
625 cmdline = apr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL);
626 }
627 }
628 }
629 else {
630#endif
631 /* A simple command we are directly invoking. Do not pass
632 * the first arg to CreateProc() for APR_PROGRAM_PATH
633 * invocation, since it would need to be a literal and
634 * complete file path. That is; "c:\bin\aprtest.exe"
635 * would succeed, but "c:\bin\aprtest" or "aprtest.exe"
636 * can fail.
637 */
639
640 if (attr->cmdtype == APR_PROGRAM_PATH) {
641 progname = NULL;
642 }
643 }
644 }
645
646 if (!env || attr->cmdtype == APR_PROGRAM_ENV ||
648 pEnvBlock = NULL;
649 }
650 else {
652 /*
653 * Win32's CreateProcess call requires that the environment
654 * be passed in an environment block, a null terminated block of
655 * null terminated strings.
656 */
657 i = 0;
658 iEnvBlockLen = 1;
659 while (env[i]) {
660 iEnvBlockLen += strlen(env[i]) + 1;
661 i++;
662 }
663 if (!i)
664 ++iEnvBlockLen;
665
666#if APR_HAS_UNICODE_FS
668 {
669 apr_wchar_t *pNext;
670 pEnvBlock = (char *)apr_palloc(pool, iEnvBlockLen * 2);
672
673 i = 0;
674 pNext = (apr_wchar_t*)pEnvBlock;
675 while (env[i]) {
676 apr_size_t in = strlen(env[i]) + 1;
677 if ((rv = apr_conv_utf8_to_ucs2(env[i], &in,
678 pNext, &iEnvBlockLen))
679 != APR_SUCCESS) {
680 if (attr->errfn) {
681 attr->errfn(pool, rv,
683 "utf8 to ucs2 conversion failed"
684 " on this string: ", env[i], NULL));
685 }
686 return rv;
687 }
688 pNext = wcschr(pNext, L'\0') + 1;
689 i++;
690 }
691 if (!i)
692 *(pNext++) = L'\0';
693 *pNext = L'\0';
694 }
695#endif /* APR_HAS_UNICODE_FS */
696#if APR_HAS_ANSI_FS
698 {
699 char *pNext;
701
702 i = 0;
703 pNext = pEnvBlock;
704 while (env[i]) {
705 strcpy(pNext, env[i]);
706 pNext = strchr(pNext, '\0') + 1;
707 i++;
708 }
709 if (!i)
710 *(pNext++) = '\0';
711 *pNext = '\0';
712 }
713#endif /* APR_HAS_ANSI_FS */
714 }
715
716 new->invoked = cmdline;
717
718#if APR_HAS_UNICODE_FS
720 {
722 DWORD stdin_reset = 0;
728
729 if (progname) {
730 apr_size_t nprg = strlen(progname) + 1;
731 apr_size_t nwprg = nprg + 6;
732 wprg = apr_palloc(pool, nwprg * sizeof(wprg[0]));
734 != APR_SUCCESS) {
735 if (attr->errfn) {
736 attr->errfn(pool, rv,
738 "utf8 to ucs2 conversion failed"
739 " on progname: ", progname, NULL));
740 }
741 return rv;
742 }
743 }
744
745 if (cmdline) {
746 apr_size_t ncmd = strlen(cmdline) + 1;
748 wcmd = apr_palloc(pool, nwcmd * sizeof(wcmd[0]));
750 != APR_SUCCESS) {
751 if (attr->errfn) {
752 attr->errfn(pool, rv,
754 "utf8 to ucs2 conversion failed"
755 " on cmdline: ", cmdline, NULL));
756 }
757 return rv;
758 }
759 }
760
761 if (attr->currdir)
762 {
763 apr_size_t ncwd = strlen(attr->currdir) + 1;
765 wcwd = apr_palloc(pool, ncwd * sizeof(wcwd[0]));
767 wcwd, &nwcwd))
768 != APR_SUCCESS) {
769 if (attr->errfn) {
770 attr->errfn(pool, rv,
772 "utf8 to ucs2 conversion failed"
773 " on currdir: ", attr->currdir, NULL));
774 }
775 return rv;
776 }
777 }
778
779 memset(&si, 0, sizeof(si));
780 si.cb = sizeof(si);
781
782 if (attr->detached) {
783 si.dwFlags |= STARTF_USESHOWWINDOW;
784 si.wShowWindow = SW_HIDE;
785 }
786
787#ifndef _WIN32_WCE
788 /* LOCK CRITICAL SECTION
789 * before we begin to manipulate the inherited handles
790 */
792
796 {
797 si.dwFlags |= STARTF_USESTDHANDLES;
798
799 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
801 {
802 if (GetHandleInformation(si.hStdInput,
805 SetHandleInformation(si.hStdInput,
807
808 if ( (si.hStdInput = attr->child_in->filehand)
812 }
813
814 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
816 {
817 if (GetHandleInformation(si.hStdOutput,
820 SetHandleInformation(si.hStdOutput,
822
823 if ( (si.hStdOutput = attr->child_out->filehand)
827 }
828
829 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
831 {
832 if (GetHandleInformation(si.hStdError,
835 SetHandleInformation(si.hStdError,
837
838 if ( (si.hStdError = attr->child_err->filehand)
842 }
843 }
844 if (attr->user_token) {
845 /* XXX: for terminal services, handles can't be cannot be
846 * inherited across sessions. This process must be created
847 * in our existing session. lpDesktop assignment appears
848 * to be wrong according to these rules.
849 */
850 si.lpDesktop = L"Winsta0\\Default";
852 /* failed to impersonate the logged user */
853 rv = apr_get_os_error();
857 return rv;
858 }
860 wprg, wcmd,
861 attr->sa,
862 NULL,
863 TRUE,
865 pEnvBlock,
866 wcwd,
867 &si, &pi);
868
869 RevertToSelf();
870 }
871 else {
872 rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */
873 NULL, NULL, /* Proc & thread security attributes */
874 TRUE, /* Inherit handles */
875 dwCreationFlags, /* Creation flags */
876 pEnvBlock, /* Environment block */
877 wcwd, /* Current directory name */
878 &si, &pi);
879 }
880
884 {
885 if (stdin_reset)
888
889 if (stdout_reset)
892
893 if (stderr_reset)
896 }
897 /* RELEASE CRITICAL SECTION
898 * The state of the inherited handles has been restored.
899 */
901
902#else /* defined(_WIN32_WCE) */
903 rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */
904 NULL, NULL, /* Proc & thread security attributes */
905 FALSE, /* must be 0 */
906 dwCreationFlags, /* Creation flags */
907 NULL, /* Environment block must be NULL */
908 NULL, /* Current directory name must be NULL*/
909 NULL, /* STARTUPINFO not supported */
910 &pi);
911#endif
912 }
913#endif /* APR_HAS_UNICODE_FS */
914#if APR_HAS_ANSI_FS
916 {
918 memset(&si, 0, sizeof(si));
919 si.cb = sizeof(si);
920
921 if (attr->detached) {
922 si.dwFlags |= STARTF_USESHOWWINDOW;
923 si.wShowWindow = SW_HIDE;
924 }
925
929 {
930 si.dwFlags |= STARTF_USESTDHANDLES;
931
932 si.hStdInput = (attr->child_in)
935
936 si.hStdOutput = (attr->child_out)
939
940 si.hStdError = (attr->child_err)
943 }
944
945 rv = CreateProcessA(progname, cmdline, /* Command line */
946 NULL, NULL, /* Proc & thread security attributes */
947 TRUE, /* Inherit handles */
948 dwCreationFlags, /* Creation flags */
949 pEnvBlock, /* Environment block */
950 attr->currdir, /* Current directory name */
951 &si, &pi);
952 }
953#endif /* APR_HAS_ANSI_FS */
954
955 /* Check CreateProcess result
956 */
957 if (!rv)
958 return apr_get_os_error();
959
960 /* XXX Orphaned handle warning - no fix due to broken apr_proc_t api.
961 */
962 new->hproc = pi.hProcess;
963 new->pid = pi.dwProcessId;
964
965 if ((attr->child_in) && (attr->child_in != &no_file)) {
967 }
968 if ((attr->child_out) && (attr->child_out != &no_file)) {
970 }
971 if ((attr->child_err) && (attr->child_err != &no_file)) {
973 }
974 CloseHandle(pi.hThread);
975
976 return APR_SUCCESS;
977}
978
980 /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how
981 * this class of failures was determined
982 */
983 if (((exit & 0xC0000000) == 0xC0000000)
984 && !(exit & 0x3FFF0000))
985 return APR_PROC_SIGNAL;
986 else
987 return APR_PROC_EXIT;
988
989 /* ### No way to tell if Dr Watson grabbed a core, AFAICT. */
990}
991
993 int *exitcode,
996 apr_pool_t *p)
997{
998#if APR_HAS_UNICODE_FS
999#ifndef _WIN32_WCE
1001 {
1003 DWORD i;
1004 DWORD nChilds = 0;
1005 DWORD nActive = 0;
1006 HANDLE ps32;
1011
1012 if (waithow == APR_WAIT)
1013 dwFlags |= SYNCHRONIZE;
1015 return apr_get_os_error();
1016 }
1017 pe32.dwSize = sizeof(PROCESSENTRY32W);
1018 if (!Process32FirstW(ps32, &pe32)) {
1020 return APR_EOF;
1021 else
1022 return apr_get_os_error();
1023 }
1024 do {
1025 DWORD dwRetval = 0;
1026 DWORD nHandles = 0;
1029 do {
1030 if (pe32.th32ParentProcessID == dwId) {
1031 nChilds++;
1032 if ((hProcess = OpenProcess(dwFlags, FALSE,
1033 pe32.th32ProcessID)) != NULL) {
1035 if (dwRetval == STILL_ACTIVE) {
1036 nActive++;
1037 if (waithow == APR_WAIT)
1039 else
1041 }
1042 else {
1043 /* Process has exited.
1044 * No need to wait for its termination.
1045 */
1047 if (exitcode)
1048 *exitcode = dwRetval;
1049 if (exitwhy)
1051 proc->pid = pe32.th32ProcessID;
1052 }
1053 }
1054 else {
1055 /* Unexpected error code.
1056 * Cleanup and return;
1057 */
1058 rv = apr_get_os_error();
1060 for (i = 0; i < nHandles; i++)
1062 return rv;
1063 }
1064 }
1065 else {
1066 /* This is our child, so it shouldn't happen
1067 * that we cannot open our child's process handle.
1068 * However if the child process increased the
1069 * security token it might fail.
1070 */
1071 }
1072 }
1073 } while ((bHasMore = Process32NextW(ps32, &pe32)) &&
1075 if (nHandles) {
1076 /* Wait for all collected processes to finish */
1078 TRUE, INFINITE);
1079 for (i = 0; i < nHandles; i++)
1081 if (waitStatus == WAIT_OBJECT_0) {
1082 /* Decrease active count by the number of awaited
1083 * processes.
1084 */
1085 nActive -= nHandles;
1086 }
1087 else {
1088 /* Broken from the infinite loop */
1089 break;
1090 }
1091 }
1092 } while (bHasMore);
1094 if (waithow != APR_WAIT) {
1095 if (nChilds && nChilds == nActive) {
1096 /* All child processes are running */
1097 rv = APR_CHILD_NOTDONE;
1098 proc->pid = -1;
1099 }
1100 else {
1101 /* proc->pid contains the pid of the
1102 * exited processes
1103 */
1104 rv = APR_CHILD_DONE;
1105 }
1106 }
1107 if (nActive == 0) {
1108 rv = APR_CHILD_DONE;
1109 proc->pid = -1;
1110 }
1111 return rv;
1112 }
1113#endif /* _WIN32_WCE */
1114#endif /* APR_HAS_UNICODE_FS */
1115 return APR_ENOTIMPL;
1116}
1117
1121{
1122 DWORD stat;
1123 DWORD time;
1124
1125 if (waithow == APR_WAIT)
1126 time = INFINITE;
1127 else
1128 time = 0;
1129
1130 if ((stat = WaitForSingleObject(proc->hproc, time)) == WAIT_OBJECT_0) {
1131 if (GetExitCodeProcess(proc->hproc, &stat)) {
1132 if (exitcode)
1133 *exitcode = stat;
1134 if (exitwhy)
1136 CloseHandle(proc->hproc);
1137 proc->hproc = NULL;
1138 return APR_CHILD_DONE;
1139 }
1140 }
1141 else if (stat == WAIT_TIMEOUT) {
1142 return APR_CHILD_NOTDONE;
1143 }
1144 return apr_get_os_error();
1145}
1146
1148{
1149 return APR_ENOTIMPL;
1150}
1151
1154 void *data,
1156{
1157 return APR_ENOTIMPL;
1158}
const char apr_size_t len
Definition ap_regex.h:187
#define TRUE
Definition abts.h:38
#define FALSE
Definition abts.h:35
apr_uint16_t apr_wchar_t
#define WaitForMultipleObjects(d1, ah, b, d2)
#define GetStdHandle(d)
#define CreateProcessA(s1, s2, sd1, sd2, b, d1, s3, s4, pd2, hr)
#define CreateProcessW(s1, s2, sd1, sd2, b, d1, s3, s4, pd2, hr)
#define CloseHandle(h)
#define WaitForSingleObject(h, d)
APR File I/O Handling.
APR Miscellaneous library routines.
APR general purpose library routines.
APR Portability Routines.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
APR Thread and Process Library.
static apr_file_t no_file
Definition proc.c:23
#define APR_CHILD_NOTDONE
Definition apr_errno.h:448
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_CHILD_DONE
Definition apr_errno.h:446
#define APR_EOF
Definition apr_errno.h:461
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EINVAL
Definition apr_errno.h:711
#define BOOL
Definition ssl_private.h:81
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
#define apr_get_os_error()
Definition apr_errno.h:1217
int apr_status_t
Definition apr_errno.h:44
apr_int32_t apr_fileperms_t
const char apr_fileperms_t perms
void * data
#define APR_FILEPATH_NATIVE
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)
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_dir_t * dir
const char * s
Definition apr_strings.h:95
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
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
int * exitcode
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_ENV
@ APR_PROGRAM_PATH
@ 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
apr_pool_t * pool
apr_file_t * child_err
apr_child_errfn_t * errfn
apr_file_t * parent_in
apr_file_t * parent_out
LPSECURITY_ATTRIBUTES sa
apr_file_t * child_out
apr_file_t * child_in
apr_file_t * parent_err
#define str
#define IS_SHCHAR(c)
#define ELSE_WIN_OS_IS_ANSI
typedef HANDLE(WINAPI *apr_winapi_fpt_CreateToolhelp32Snapshot)(DWORD dwFlags
APR_DECLARE_DATA apr_oslevel_e apr_os_level
Definition misc.c:24
@ APR_WIN_NT
@ APR_WIN_NT_4
#define CreateToolhelp32Snapshot
#define IF_WIN_OS_IS_UNICODE
#define Process32NextW
typedef DWORD(WINAPI *apr_winapi_fpt_GetCompressedFileSizeA)(IN LPCSTR lpFileName
#define Process32FirstW
static const char * has_space(const char *str)
Definition proc.c:344
static char * apr_caret_escape_args(apr_pool_t *p, const char *str)
Definition proc.c:355
#define LOGON32_LOGON_NETWORK
Definition proc.c:45
static apr_status_t attr_cleanup(void *theattr)
Definition proc.c:230
static apr_exit_why_e why_from_exit_code(DWORD exit)
Definition proc.c:979
apr_status_t apr_threadproc_init(apr_pool_t *pool)
Definition proc.c:441