~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/threadproc/os2/proc.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
 
2
 * applicable.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * 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
APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, apr_pool_t *pool)
 
38
{
 
39
    (*new) = (apr_procattr_t *)apr_palloc(pool, 
 
40
              sizeof(apr_procattr_t));
 
41
 
 
42
    if ((*new) == NULL) {
 
43
        return APR_ENOMEM;
 
44
    }
 
45
    (*new)->pool = pool;
 
46
    (*new)->parent_in = NULL;
 
47
    (*new)->child_in = NULL;
 
48
    (*new)->parent_out = NULL;
 
49
    (*new)->child_out = NULL;
 
50
    (*new)->parent_err = NULL;
 
51
    (*new)->child_err = NULL;
 
52
    (*new)->currdir = NULL; 
 
53
    (*new)->cmdtype = APR_PROGRAM;
 
54
    (*new)->detached = FALSE;
 
55
    return APR_SUCCESS;
 
56
}
 
57
 
 
58
APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, apr_int32_t in, 
 
59
                                              apr_int32_t out, apr_int32_t err)
 
60
{
 
61
    apr_status_t stat;
 
62
    if (in) {
 
63
        if ((stat = apr_file_pipe_create(&attr->child_in, &attr->parent_in,
 
64
                                   attr->pool)) != APR_SUCCESS) {
 
65
            return stat;
 
66
        }
 
67
        switch (in) {
 
68
        case APR_FULL_BLOCK:
 
69
            break;
 
70
        case APR_PARENT_BLOCK:
 
71
            apr_file_pipe_timeout_set(attr->child_in, 0);
 
72
            break;
 
73
        case APR_CHILD_BLOCK:
 
74
            apr_file_pipe_timeout_set(attr->parent_in, 0);
 
75
            break;
 
76
        default:
 
77
            apr_file_pipe_timeout_set(attr->child_in, 0);
 
78
            apr_file_pipe_timeout_set(attr->parent_in, 0);
 
79
        }
 
80
    } 
 
81
    if (out) {
 
82
        if ((stat = apr_file_pipe_create(&attr->parent_out, &attr->child_out,
 
83
                                   attr->pool)) != APR_SUCCESS) {
 
84
            return stat;
 
85
        }
 
86
        switch (out) {
 
87
        case APR_FULL_BLOCK:
 
88
            break;
 
89
        case APR_PARENT_BLOCK:
 
90
            apr_file_pipe_timeout_set(attr->child_out, 0);
 
91
            break;
 
92
        case APR_CHILD_BLOCK:
 
93
            apr_file_pipe_timeout_set(attr->parent_out, 0);
 
94
            break;
 
95
        default:
 
96
            apr_file_pipe_timeout_set(attr->child_out, 0);
 
97
            apr_file_pipe_timeout_set(attr->parent_out, 0);
 
98
        }
 
99
    } 
 
100
    if (err) {
 
101
        if ((stat = apr_file_pipe_create(&attr->parent_err, &attr->child_err,
 
102
                                   attr->pool)) != APR_SUCCESS) {
 
103
            return stat;
 
104
        }
 
105
        switch (err) {
 
106
        case APR_FULL_BLOCK:
 
107
            break;
 
108
        case APR_PARENT_BLOCK:
 
109
            apr_file_pipe_timeout_set(attr->child_err, 0);
 
110
            break;
 
111
        case APR_CHILD_BLOCK:
 
112
            apr_file_pipe_timeout_set(attr->parent_err, 0);
 
113
            break;
 
114
        default:
 
115
            apr_file_pipe_timeout_set(attr->child_err, 0);
 
116
            apr_file_pipe_timeout_set(attr->parent_err, 0);
 
117
        }
 
118
    } 
 
119
    return APR_SUCCESS;
 
120
}
 
121
 
 
122
APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in,
 
123
                                                    apr_file_t *parent_in)
 
124
{
 
125
    if (attr->child_in == NULL && attr->parent_in == NULL)
 
126
        apr_file_pipe_create(&attr->child_in, &attr->parent_in, attr->pool);
 
127
 
 
128
    if (child_in != NULL)
 
129
        apr_file_dup(&attr->child_in, child_in, attr->pool);
 
130
 
 
131
    if (parent_in != NULL)
 
132
        apr_file_dup(&attr->parent_in, parent_in, attr->pool);
 
133
 
 
134
    return APR_SUCCESS;
 
135
}
 
136
 
 
137
 
 
138
APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out,
 
139
                                                     apr_file_t *parent_out)
 
140
{
 
141
    if (attr->child_out == NULL && attr->parent_out == NULL)
 
142
        apr_file_pipe_create(&attr->child_out, &attr->parent_out, attr->pool);
 
143
 
 
144
    if (child_out != NULL)
 
145
        apr_file_dup(&attr->child_out, child_out, attr->pool);
 
146
 
 
147
    if (parent_out != NULL)
 
148
        apr_file_dup(&attr->parent_out, parent_out, attr->pool);
 
149
 
 
150
    return APR_SUCCESS;
 
151
}
 
152
 
 
153
 
 
154
APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err,
 
155
                                                     apr_file_t *parent_err)
 
156
{
 
157
    if (attr->child_err == NULL && attr->parent_err == NULL)
 
158
        apr_file_pipe_create(&attr->child_err, &attr->parent_err, attr->pool);
 
159
 
 
160
    if (child_err != NULL)
 
161
        apr_file_dup(&attr->child_err, child_err, attr->pool);
 
162
 
 
163
    if (parent_err != NULL)
 
164
        apr_file_dup(&attr->parent_err, parent_err, attr->pool);
 
165
 
 
166
    return APR_SUCCESS;
 
167
}
 
168
 
 
169
 
 
170
APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, const char *dir)
 
171
{
 
172
    attr->currdir = apr_pstrdup(attr->pool, dir);
 
173
    if (attr->currdir) {
 
174
        return APR_SUCCESS;
 
175
    }
 
176
    return APR_ENOMEM;
 
177
}
 
178
 
 
179
APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
 
180
                                                   apr_cmdtype_e cmd) 
 
181
{
 
182
    attr->cmdtype = cmd;
 
183
    return APR_SUCCESS;
 
184
}
 
185
 
 
186
APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach) 
 
187
{
 
188
    attr->detached = detach;
 
189
    return APR_SUCCESS;
 
190
}
 
191
 
 
192
APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
 
193
{
 
194
    int pid;
 
195
    
 
196
    if ((pid = fork()) < 0) {
 
197
        return errno;
 
198
    }
 
199
    else if (pid == 0) {
 
200
        proc->pid = pid;
 
201
        proc->in = NULL; 
 
202
        proc->out = NULL; 
 
203
        proc->err = NULL; 
 
204
        return APR_INCHILD;
 
205
    }
 
206
    proc->pid = pid;
 
207
    proc->in = NULL; 
 
208
    proc->out = NULL; 
 
209
    proc->err = NULL; 
 
210
    return APR_INPARENT;
 
211
}
 
212
 
 
213
 
 
214
 
 
215
/* quotes in the string are doubled up.
 
216
 * Used to escape quotes in args passed to OS/2's cmd.exe
 
217
 */
 
218
static char *double_quotes(apr_pool_t *pool, const char *str)
 
219
{
 
220
    int num_quotes = 0;
 
221
    int len = 0;
 
222
    char *quote_doubled_str, *dest;
 
223
    
 
224
    while (str[len]) {
 
225
        num_quotes += str[len++] == '\"';
 
226
    }
 
227
    
 
228
    quote_doubled_str = apr_palloc(pool, len + num_quotes + 1);
 
229
    dest = quote_doubled_str;
 
230
    
 
231
    while (*str) {
 
232
        if (*str == '\"')
 
233
            *(dest++) = '\"';
 
234
        *(dest++) = *(str++);
 
235
    }
 
236
    
 
237
    *dest = 0;
 
238
    return quote_doubled_str;
 
239
}
 
240
 
 
241
 
 
242
 
 
243
APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
 
244
                                                       apr_child_errfn_t *errfn)
 
245
{
 
246
    /* won't ever be called on this platform, so don't save the function pointer */
 
247
    return APR_SUCCESS;
 
248
}
 
249
 
 
250
 
 
251
 
 
252
APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
 
253
                                                       apr_int32_t chk)
 
254
{
 
255
    /* won't ever be used on this platform, so don't save the flag */
 
256
    return APR_SUCCESS;
 
257
}
 
258
 
 
259
APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
 
260
                                                       apr_int32_t addrspace)
 
261
{
 
262
    /* won't ever be used on this platform, so don't save the flag */
 
263
    return APR_SUCCESS;
 
264
}
 
265
 
 
266
 
 
267
 
 
268
APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *proc, const char *progname,
 
269
                                          const char * const *args,
 
270
                                          const char * const *env,
 
271
                                          apr_procattr_t *attr, apr_pool_t *pool)
 
272
{
 
273
    int i, arg, numargs, cmdlen;
 
274
    apr_status_t status;
 
275
    const char **newargs;
 
276
    char savedir[300];
 
277
    HFILE save_in, save_out, save_err, dup;
 
278
    int criticalsection = FALSE;
 
279
    char *extension, *newprogname, *extra_arg = NULL, *cmdline, *cmdline_pos;
 
280
    char interpreter[1024];
 
281
    char error_object[260];
 
282
    apr_file_t *progfile;
 
283
    int env_len, e;
 
284
    char *env_block, *env_block_pos;
 
285
    RESULTCODES rescodes;
 
286
 
 
287
    /* Prevent other threads from running while these process-wide resources are modified */
 
288
    if (attr->child_in || attr->child_out || attr->child_err || attr->currdir) {
 
289
        criticalsection = TRUE;
 
290
        DosEnterCritSec();
 
291
    }
 
292
 
 
293
    if (attr->child_in) {
 
294
        save_in = -1;
 
295
        DosDupHandle(STDIN_FILENO, &save_in);
 
296
        dup = STDIN_FILENO;
 
297
        DosDupHandle(attr->child_in->filedes, &dup);
 
298
        DosSetFHState(attr->parent_in->filedes, OPEN_FLAGS_NOINHERIT);
 
299
    }
 
300
    
 
301
    if (attr->child_out) {
 
302
        save_out = -1;
 
303
        DosDupHandle(STDOUT_FILENO, &save_out);
 
304
        dup = STDOUT_FILENO;
 
305
        DosDupHandle(attr->child_out->filedes, &dup);
 
306
        DosSetFHState(attr->parent_out->filedes, OPEN_FLAGS_NOINHERIT);
 
307
    }
 
308
    
 
309
    if (attr->child_err) {
 
310
        save_err = -1;
 
311
        DosDupHandle(STDERR_FILENO, &save_err);
 
312
        dup = STDERR_FILENO;
 
313
        DosDupHandle(attr->child_err->filedes, &dup);
 
314
        DosSetFHState(attr->parent_err->filedes, OPEN_FLAGS_NOINHERIT);
 
315
    }
 
316
 
 
317
    apr_signal(SIGCHLD, SIG_DFL); /*not sure if this is needed or not */
 
318
 
 
319
    if (attr->currdir != NULL) {
 
320
        _getcwd2(savedir, sizeof(savedir));
 
321
        
 
322
        if (_chdir2(attr->currdir) < 0) {
 
323
            if (criticalsection)
 
324
                DosExitCritSec();
 
325
            return errno;
 
326
        }
 
327
    }
 
328
 
 
329
    interpreter[0] = 0;
 
330
    extension = strrchr(progname, '.');
 
331
 
 
332
    if (extension == NULL || strchr(extension, '/') || strchr(extension, '\\'))
 
333
        extension = "";
 
334
 
 
335
    /* ### how to handle APR_PROGRAM_ENV and APR_PROGRAM_PATH? */
 
336
 
 
337
    if (attr->cmdtype == APR_SHELLCMD ||
 
338
        attr->cmdtype == APR_SHELLCMD_ENV ||
 
339
        strcasecmp(extension, ".cmd") == 0) {
 
340
        strcpy(interpreter, "#!" SHELL_PATH);
 
341
        extra_arg = "/C";
 
342
    } else if (stricmp(extension, ".exe") != 0) {
 
343
        status = apr_file_open(&progfile, progname, APR_READ|APR_BUFFERED, 0, pool);
 
344
 
 
345
        if (status != APR_SUCCESS && APR_STATUS_IS_ENOENT(status)) {
 
346
            progname = apr_pstrcat(pool, progname, ".exe", NULL);
 
347
        }
 
348
 
 
349
        if (status == APR_SUCCESS) {
 
350
            status = apr_file_gets(interpreter, sizeof(interpreter), progfile);
 
351
 
 
352
            if (status == APR_SUCCESS) {
 
353
                if (interpreter[0] == '#' && interpreter[1] == '!') {
 
354
                    /* delete CR/LF & any other whitespace off the end */
 
355
                    int end = strlen(interpreter) - 1;
 
356
 
 
357
                    while (end >= 0 && apr_isspace(interpreter[end])) {
 
358
                        interpreter[end] = '\0';
 
359
                        end--;
 
360
                    }
 
361
 
 
362
                    if (interpreter[2] != '/' && interpreter[2] != '\\' && interpreter[3] != ':') {
 
363
                        char buffer[300];
 
364
 
 
365
                        if (DosSearchPath(SEARCH_ENVIRONMENT, "PATH", interpreter+2, buffer, sizeof(buffer)) == 0) {
 
366
                            strcpy(interpreter+2, buffer);
 
367
                        } else {
 
368
                            strcat(interpreter, ".exe");
 
369
                            if (DosSearchPath(SEARCH_ENVIRONMENT, "PATH", interpreter+2, buffer, sizeof(buffer)) == 0) {
 
370
                                strcpy(interpreter+2, buffer);
 
371
                            }
 
372
                        }
 
373
                    }
 
374
                } else {
 
375
                    interpreter[0] = 0;
 
376
                }
 
377
            }
 
378
 
 
379
            apr_file_close(progfile);
 
380
        }
 
381
    }
 
382
 
 
383
    i = 0;
 
384
 
 
385
    while (args && args[i]) {
 
386
        i++;
 
387
    }
 
388
 
 
389
    newargs = (const char **)apr_palloc(pool, sizeof (char *) * (i + 4));
 
390
    numargs = 0;
 
391
 
 
392
    if (interpreter[0])
 
393
        newargs[numargs++] = interpreter + 2;
 
394
    if (extra_arg)
 
395
        newargs[numargs++] = "/c";
 
396
 
 
397
    newargs[numargs++] = newprogname = apr_pstrdup(pool, progname);
 
398
    arg = 1;
 
399
 
 
400
    while (args && args[arg]) {
 
401
        newargs[numargs++] = args[arg++];
 
402
    }
 
403
 
 
404
    newargs[numargs] = NULL;
 
405
 
 
406
    for (i=0; newprogname[i]; i++)
 
407
        if (newprogname[i] == '/')
 
408
            newprogname[i] = '\\';
 
409
 
 
410
    cmdlen = 0;
 
411
 
 
412
    for (i=0; i<numargs; i++)
 
413
        cmdlen += strlen(newargs[i]) + 3;
 
414
 
 
415
    cmdline = apr_palloc(pool, cmdlen + 2);
 
416
    cmdline_pos = cmdline;
 
417
 
 
418
    for (i=0; i<numargs; i++) {
 
419
        const char *a = newargs[i];
 
420
 
 
421
        if (strpbrk(a, "&|<>\" "))
 
422
            a = apr_pstrcat(pool, "\"", double_quotes(pool, a), "\"", NULL);
 
423
 
 
424
        if (i)
 
425
            *(cmdline_pos++) = ' ';
 
426
 
 
427
        strcpy(cmdline_pos, a);
 
428
        cmdline_pos += strlen(cmdline_pos);
 
429
    }
 
430
 
 
431
    *(++cmdline_pos) = 0; /* Add required second terminator */
 
432
    cmdline_pos = strchr(cmdline, ' ');
 
433
 
 
434
    if (cmdline_pos) {
 
435
        *cmdline_pos = 0;
 
436
        cmdline_pos++;
 
437
    }
 
438
 
 
439
    /* Create environment block from list of envariables */
 
440
    if (env) {
 
441
        for (env_len=1, e=0; env[e]; e++)
 
442
            env_len += strlen(env[e]) + 1;
 
443
 
 
444
        env_block = apr_palloc(pool, env_len);
 
445
        env_block_pos = env_block;
 
446
 
 
447
        for (e=0; env[e]; e++) {
 
448
            strcpy(env_block_pos, env[e]);
 
449
            env_block_pos += strlen(env_block_pos) + 1;
 
450
        }
 
451
 
 
452
        *env_block_pos = 0; /* environment block is terminated by a double null */
 
453
    } else
 
454
        env_block = NULL;
 
455
 
 
456
    status = DosExecPgm(error_object, sizeof(error_object),
 
457
                        attr->detached ? EXEC_BACKGROUND : EXEC_ASYNCRESULT,
 
458
                        cmdline, env_block, &rescodes, cmdline);
 
459
 
 
460
    proc->pid = rescodes.codeTerminate;
 
461
 
 
462
    if (attr->currdir != NULL) {
 
463
        chdir(savedir);
 
464
    }
 
465
 
 
466
    if (attr->child_in) {
 
467
        apr_file_close(attr->child_in);
 
468
        dup = STDIN_FILENO;
 
469
        DosDupHandle(save_in, &dup);
 
470
        DosClose(save_in);
 
471
    }
 
472
    
 
473
    if (attr->child_out) {
 
474
        apr_file_close(attr->child_out);
 
475
        dup = STDOUT_FILENO;
 
476
        DosDupHandle(save_out, &dup);
 
477
        DosClose(save_out);
 
478
    }
 
479
    
 
480
    if (attr->child_err) {
 
481
        apr_file_close(attr->child_err);
 
482
        dup = STDERR_FILENO;
 
483
        DosDupHandle(save_err, &dup);
 
484
        DosClose(save_err);
 
485
    }
 
486
 
 
487
    if (criticalsection)
 
488
        DosExitCritSec();
 
489
 
 
490
    proc->in = attr->parent_in;
 
491
    proc->err = attr->parent_err;
 
492
    proc->out = attr->parent_out;
 
493
    return status;
 
494
}
 
495
 
 
496
 
 
497
 
 
498
static void proces_result_codes(RESULTCODES codes, 
 
499
                                int *exitcode, 
 
500
                                apr_exit_why_e *exitwhy)
 
501
{
 
502
    int result = 0;
 
503
    apr_exit_why_e why = APR_PROC_EXIT;
 
504
 
 
505
    switch (codes.codeTerminate) {
 
506
    case TC_EXIT:        /* Normal exit */
 
507
        why = APR_PROC_EXIT;
 
508
        result = codes.codeResult;
 
509
        break;
 
510
 
 
511
    case TC_HARDERROR:   /* Hard error halt */
 
512
        why = APR_PROC_SIGNAL;
 
513
        result = SIGSYS;
 
514
        break;
 
515
 
 
516
    case TC_KILLPROCESS: /* Was killed by a DosKillProcess() */
 
517
        why = APR_PROC_SIGNAL;
 
518
        result = SIGKILL;
 
519
        break;
 
520
 
 
521
    case TC_TRAP:        /* TRAP in 16 bit code */
 
522
    case TC_EXCEPTION:   /* Threw an exception (32 bit code) */
 
523
        why = APR_PROC_SIGNAL;
 
524
 
 
525
        switch (codes.codeResult | XCPT_FATAL_EXCEPTION) {
 
526
        case XCPT_ACCESS_VIOLATION:
 
527
            result = SIGSEGV;
 
528
            break;
 
529
 
 
530
        case XCPT_ILLEGAL_INSTRUCTION:
 
531
            result = SIGILL;
 
532
            break;
 
533
 
 
534
        case XCPT_FLOAT_DIVIDE_BY_ZERO:
 
535
        case XCPT_INTEGER_DIVIDE_BY_ZERO:
 
536
            result = SIGFPE;
 
537
            break;
 
538
 
 
539
        default:
 
540
            result = codes.codeResult;
 
541
            break;
 
542
        }
 
543
    }
 
544
 
 
545
    if (exitcode) {
 
546
        *exitcode = result;
 
547
    }
 
548
 
 
549
    if (exitwhy) {
 
550
        *exitwhy = why;
 
551
    }
 
552
}
 
553
 
 
554
 
 
555
 
 
556
APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
 
557
                                                  int *exitcode,
 
558
                                                  apr_exit_why_e *exitwhy,
 
559
                                                  apr_wait_how_e waithow,
 
560
                                                  apr_pool_t *p)
 
561
{
 
562
    RESULTCODES codes;
 
563
    ULONG rc;
 
564
    PID pid;
 
565
 
 
566
    rc = DosWaitChild(DCWA_PROCESSTREE, waithow == APR_WAIT ? DCWW_WAIT : DCWW_NOWAIT, &codes, &pid, 0);
 
567
 
 
568
    if (rc == 0) {
 
569
        proc->pid = pid;
 
570
        proces_result_codes(codes, exitcode, exitwhy);
 
571
        return APR_CHILD_DONE;
 
572
    } else if (rc == ERROR_CHILD_NOT_COMPLETE) {
 
573
        return APR_CHILD_NOTDONE;
 
574
    }
 
575
 
 
576
    return APR_OS2_STATUS(rc);
 
577
 
578
 
 
579
 
 
580
 
 
581
APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc,
 
582
                                        int *exitcode, apr_exit_why_e *exitwhy,
 
583
                                        apr_wait_how_e waithow)
 
584
{
 
585
    RESULTCODES codes;
 
586
    ULONG rc;
 
587
    PID pid;
 
588
    rc = DosWaitChild(DCWA_PROCESS, waithow == APR_WAIT ? DCWW_WAIT : DCWW_NOWAIT, &codes, &pid, proc->pid);
 
589
 
 
590
    if (rc == 0) {
 
591
        proces_result_codes(codes, exitcode, exitwhy);
 
592
        return APR_CHILD_DONE;
 
593
    } else if (rc == ERROR_CHILD_NOT_COMPLETE) {
 
594
        return APR_CHILD_NOTDONE;
 
595
    }
 
596
 
 
597
    return APR_OS2_STATUS(rc);
 
598
 
599
 
 
600
 
 
601
 
 
602
APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize)
 
603
{
 
604
    return APR_ENOTIMPL;
 
605
}
 
606
 
 
607
APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, 
 
608
                                                const char *username,
 
609
                                                const char *password)
 
610
{
 
611
    return APR_ENOTIMPL;
 
612
}
 
613
 
 
614
APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr,
 
615
                                                 const char *groupname)
 
616
{
 
617
    return APR_ENOTIMPL;
 
618
}