1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_arch_threadproc.h"
18251875Speter#include "apr_strings.h"
19251875Speter#include "apr_portable.h"
20251875Speter#include "apr_signal.h"
21251875Speter#include "apr_random.h"
22251875Speter
23251875Speter/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
24251875Speter * requested for a specific child handle;
25251875Speter */
26251875Speterstatic apr_file_t no_file = { NULL, -1, };
27251875Speter
28251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,
29251875Speter                                              apr_pool_t *pool)
30251875Speter{
31251875Speter    (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
32251875Speter
33251875Speter    if ((*new) == NULL) {
34251875Speter        return APR_ENOMEM;
35251875Speter    }
36251875Speter    (*new)->pool = pool;
37251875Speter    (*new)->cmdtype = APR_PROGRAM;
38251875Speter    (*new)->uid = (*new)->gid = -1;
39251875Speter    return APR_SUCCESS;
40251875Speter}
41251875Speter
42251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr,
43251875Speter                                              apr_int32_t in,
44251875Speter                                              apr_int32_t out,
45251875Speter                                              apr_int32_t err)
46251875Speter{
47251875Speter    apr_status_t rv;
48251875Speter
49251875Speter    if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) {
50251875Speter        /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
51251875Speter         * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose
52251875Speter         * the CHILD/PARENT blocking flags for the stdin pipe.
53251875Speter         * stdout/stderr map to the correct mode by default.
54251875Speter         */
55251875Speter        if (in == APR_CHILD_BLOCK)
56251875Speter            in = APR_READ_BLOCK;
57251875Speter        else if (in == APR_PARENT_BLOCK)
58251875Speter            in = APR_WRITE_BLOCK;
59251875Speter
60251875Speter        if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in,
61251875Speter                                          in, attr->pool)) == APR_SUCCESS)
62251875Speter            rv = apr_file_inherit_unset(attr->parent_in);
63251875Speter        if (rv != APR_SUCCESS)
64251875Speter            return rv;
65251875Speter    }
66251875Speter    else if (in == APR_NO_FILE)
67251875Speter        attr->child_in = &no_file;
68251875Speter
69251875Speter    if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) {
70251875Speter        if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out,
71251875Speter                                          out, attr->pool)) == APR_SUCCESS)
72251875Speter            rv = apr_file_inherit_unset(attr->parent_out);
73251875Speter        if (rv != APR_SUCCESS)
74251875Speter            return rv;
75251875Speter    }
76251875Speter    else if (out == APR_NO_FILE)
77251875Speter        attr->child_out = &no_file;
78251875Speter
79251875Speter    if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) {
80251875Speter        if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err,
81251875Speter                                          err, attr->pool)) == APR_SUCCESS)
82251875Speter            rv = apr_file_inherit_unset(attr->parent_err);
83251875Speter        if (rv != APR_SUCCESS)
84251875Speter            return rv;
85251875Speter    }
86251875Speter    else if (err == APR_NO_FILE)
87251875Speter        attr->child_err = &no_file;
88251875Speter
89251875Speter    return APR_SUCCESS;
90251875Speter}
91251875Speter
92251875Speter
93251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr,
94251875Speter                                                    apr_file_t *child_in,
95251875Speter                                                    apr_file_t *parent_in)
96251875Speter{
97251875Speter    apr_status_t rv = APR_SUCCESS;
98251875Speter
99251875Speter    if (attr->child_in == NULL && attr->parent_in == NULL
100251875Speter           && child_in == NULL && parent_in == NULL)
101251875Speter        if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in,
102251875Speter                                       attr->pool)) == APR_SUCCESS)
103251875Speter            rv = apr_file_inherit_unset(attr->parent_in);
104251875Speter
105251875Speter    if (child_in != NULL && rv == APR_SUCCESS) {
106251875Speter        if (attr->child_in && (attr->child_in->filedes != -1))
107251875Speter            rv = apr_file_dup2(attr->child_in, child_in, attr->pool);
108251875Speter        else {
109251875Speter            attr->child_in = NULL;
110251875Speter            if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool))
111251875Speter                    == APR_SUCCESS)
112251875Speter                rv = apr_file_inherit_set(attr->child_in);
113251875Speter        }
114251875Speter    }
115251875Speter
116251875Speter    if (parent_in != NULL && rv == APR_SUCCESS) {
117251875Speter        if (attr->parent_in)
118251875Speter            rv = apr_file_dup2(attr->parent_in, parent_in, attr->pool);
119251875Speter        else
120251875Speter            rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool);
121251875Speter    }
122251875Speter
123251875Speter    return rv;
124251875Speter}
125251875Speter
126251875Speter
127251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr,
128251875Speter                                                     apr_file_t *child_out,
129251875Speter                                                     apr_file_t *parent_out)
130251875Speter{
131251875Speter    apr_status_t rv = APR_SUCCESS;
132251875Speter
133251875Speter    if (attr->child_out == NULL && attr->parent_out == NULL
134251875Speter           && child_out == NULL && parent_out == NULL)
135251875Speter        if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out,
136251875Speter                                       attr->pool)) == APR_SUCCESS)
137251875Speter            rv = apr_file_inherit_unset(attr->parent_out);
138251875Speter
139251875Speter    if (child_out != NULL && rv == APR_SUCCESS) {
140251875Speter        if (attr->child_out && (attr->child_out->filedes != -1))
141251875Speter            rv = apr_file_dup2(attr->child_out, child_out, attr->pool);
142251875Speter        else {
143251875Speter            attr->child_out = NULL;
144251875Speter            if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool))
145251875Speter                    == APR_SUCCESS)
146251875Speter                rv = apr_file_inherit_set(attr->child_out);
147251875Speter        }
148251875Speter    }
149251875Speter
150251875Speter    if (parent_out != NULL && rv == APR_SUCCESS) {
151251875Speter        if (attr->parent_out)
152251875Speter            rv = apr_file_dup2(attr->parent_out, parent_out, attr->pool);
153251875Speter        else
154251875Speter            rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool);
155251875Speter    }
156251875Speter
157251875Speter    return rv;
158251875Speter}
159251875Speter
160251875Speter
161251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr,
162251875Speter                                                     apr_file_t *child_err,
163251875Speter                                                     apr_file_t *parent_err)
164251875Speter{
165251875Speter    apr_status_t rv = APR_SUCCESS;
166251875Speter
167251875Speter    if (attr->child_err == NULL && attr->parent_err == NULL
168251875Speter           && child_err == NULL && parent_err == NULL)
169251875Speter        if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err,
170251875Speter                                      attr->pool)) == APR_SUCCESS)
171251875Speter            rv = apr_file_inherit_unset(attr->parent_err);
172251875Speter
173251875Speter    if (child_err != NULL && rv == APR_SUCCESS) {
174251875Speter        if (attr->child_err && (attr->child_err->filedes != -1))
175251875Speter            rv = apr_file_dup2(attr->child_err, child_err, attr->pool);
176251875Speter        else {
177251875Speter            attr->child_err = NULL;
178251875Speter            if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool))
179251875Speter                    == APR_SUCCESS)
180251875Speter                rv = apr_file_inherit_set(attr->child_err);
181251875Speter        }
182251875Speter    }
183251875Speter    if (parent_err != NULL && rv == APR_SUCCESS) {
184251875Speter        if (attr->parent_err)
185251875Speter            rv = apr_file_dup2(attr->parent_err, parent_err, attr->pool);
186251875Speter        else
187251875Speter            rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool);
188251875Speter    }
189251875Speter
190251875Speter    return rv;
191251875Speter}
192251875Speter
193251875Speter
194251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr,
195251875Speter                                               const char *dir)
196251875Speter{
197251875Speter    attr->currdir = apr_pstrdup(attr->pool, dir);
198251875Speter    if (attr->currdir) {
199251875Speter        return APR_SUCCESS;
200251875Speter    }
201251875Speter
202251875Speter    return APR_ENOMEM;
203251875Speter}
204251875Speter
205251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
206251875Speter                                                   apr_cmdtype_e cmd)
207251875Speter{
208251875Speter    attr->cmdtype = cmd;
209251875Speter    return APR_SUCCESS;
210251875Speter}
211251875Speter
212251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr,
213251875Speter                                                  apr_int32_t detach)
214251875Speter{
215251875Speter    attr->detached = detach;
216251875Speter    return APR_SUCCESS;
217251875Speter}
218251875Speter
219251875SpeterAPR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
220251875Speter{
221251875Speter    int pid;
222251875Speter
223251875Speter    memset(proc, 0, sizeof(apr_proc_t));
224251875Speter
225251875Speter    if ((pid = fork()) < 0) {
226251875Speter        return errno;
227251875Speter    }
228251875Speter    else if (pid == 0) {
229251875Speter        proc->pid = getpid();
230251875Speter
231251875Speter        apr_random_after_fork(proc);
232251875Speter
233251875Speter        return APR_INCHILD;
234251875Speter    }
235251875Speter
236251875Speter    proc->pid = pid;
237251875Speter
238251875Speter    return APR_INPARENT;
239251875Speter}
240251875Speter
241251875Speterstatic apr_status_t limit_proc(apr_procattr_t *attr)
242251875Speter{
243251875Speter#if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT
244251875Speter#ifdef RLIMIT_CPU
245251875Speter    if (attr->limit_cpu != NULL) {
246251875Speter        if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) {
247251875Speter            return errno;
248251875Speter        }
249251875Speter    }
250251875Speter#endif
251251875Speter#ifdef RLIMIT_NPROC
252251875Speter    if (attr->limit_nproc != NULL) {
253251875Speter        if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) {
254251875Speter            return errno;
255251875Speter        }
256251875Speter    }
257251875Speter#endif
258251875Speter#ifdef RLIMIT_NOFILE
259251875Speter    if (attr->limit_nofile != NULL) {
260251875Speter        if ((setrlimit(RLIMIT_NOFILE, attr->limit_nofile)) != 0) {
261251875Speter            return errno;
262251875Speter        }
263251875Speter    }
264251875Speter#endif
265251875Speter#if defined(RLIMIT_AS)
266251875Speter    if (attr->limit_mem != NULL) {
267251875Speter        if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) {
268251875Speter            return errno;
269251875Speter        }
270251875Speter    }
271251875Speter#elif defined(RLIMIT_DATA)
272251875Speter    if (attr->limit_mem != NULL) {
273251875Speter        if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) {
274251875Speter            return errno;
275251875Speter        }
276251875Speter    }
277251875Speter#elif defined(RLIMIT_VMEM)
278251875Speter    if (attr->limit_mem != NULL) {
279251875Speter        if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) {
280251875Speter            return errno;
281251875Speter        }
282251875Speter    }
283251875Speter#endif
284251875Speter#else
285251875Speter    /*
286251875Speter     * Maybe make a note in error_log that setrlimit isn't supported??
287251875Speter     */
288251875Speter
289251875Speter#endif
290251875Speter    return APR_SUCCESS;
291251875Speter}
292251875Speter
293251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
294251875Speter                                                       apr_child_errfn_t *errfn)
295251875Speter{
296251875Speter    attr->errfn = errfn;
297251875Speter    return APR_SUCCESS;
298251875Speter}
299251875Speter
300251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
301251875Speter                                                       apr_int32_t chk)
302251875Speter{
303251875Speter    attr->errchk = chk;
304251875Speter    return APR_SUCCESS;
305251875Speter}
306251875Speter
307251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
308251875Speter                                                       apr_int32_t addrspace)
309251875Speter{
310251875Speter    /* won't ever be used on this platform, so don't save the flag */
311251875Speter    return APR_SUCCESS;
312251875Speter}
313251875Speter
314251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr,
315251875Speter                                                const char *username,
316251875Speter                                                const char *password)
317251875Speter{
318251875Speter    apr_status_t rv;
319251875Speter    apr_gid_t    gid;
320251875Speter
321251875Speter    if ((rv = apr_uid_get(&attr->uid, &gid, username,
322251875Speter                          attr->pool)) != APR_SUCCESS) {
323251875Speter        attr->uid = -1;
324251875Speter        return rv;
325251875Speter    }
326251875Speter
327251875Speter    /* Use default user group if not already set */
328251875Speter    if (attr->gid == -1) {
329251875Speter        attr->gid = gid;
330251875Speter    }
331251875Speter    return APR_SUCCESS;
332251875Speter}
333251875Speter
334251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr,
335251875Speter                                                 const char *groupname)
336251875Speter{
337251875Speter    apr_status_t rv;
338251875Speter
339251875Speter    if ((rv = apr_gid_get(&attr->gid, groupname, attr->pool)) != APR_SUCCESS)
340251875Speter        attr->gid = -1;
341251875Speter    return rv;
342251875Speter}
343251875Speter
344251875SpeterAPR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
345251875Speter                                          const char *progname,
346251875Speter                                          const char * const *args,
347251875Speter                                          const char * const *env,
348251875Speter                                          apr_procattr_t *attr,
349251875Speter                                          apr_pool_t *pool)
350251875Speter{
351251875Speter    int i;
352251875Speter    const char * const empty_envp[] = {NULL};
353251875Speter
354251875Speter    if (!env) { /* Specs require an empty array instead of NULL;
355251875Speter                 * Purify will trigger a failure, even if many
356251875Speter                 * implementations don't.
357251875Speter                 */
358251875Speter        env = empty_envp;
359251875Speter    }
360251875Speter
361251875Speter    new->in = attr->parent_in;
362251875Speter    new->err = attr->parent_err;
363251875Speter    new->out = attr->parent_out;
364251875Speter
365251875Speter    if (attr->errchk) {
366251875Speter        if (attr->currdir) {
367251875Speter            if (access(attr->currdir, X_OK) == -1) {
368251875Speter                /* chdir() in child wouldn't have worked */
369251875Speter                return errno;
370251875Speter            }
371251875Speter        }
372251875Speter
373251875Speter        if (attr->cmdtype == APR_PROGRAM ||
374251875Speter            attr->cmdtype == APR_PROGRAM_ENV ||
375251875Speter            *progname == '/') {
376251875Speter            /* for both of these values of cmdtype, caller must pass
377251875Speter             * full path, so it is easy to check;
378251875Speter             * caller can choose to pass full path for other
379251875Speter             * values of cmdtype
380251875Speter             */
381251875Speter            if (access(progname, X_OK) == -1) {
382251875Speter                /* exec*() in child wouldn't have worked */
383251875Speter                return errno;
384251875Speter            }
385251875Speter        }
386251875Speter        else {
387251875Speter            /* todo: search PATH for progname then try to access it */
388251875Speter        }
389251875Speter    }
390251875Speter
391251875Speter    if ((new->pid = fork()) < 0) {
392251875Speter        return errno;
393251875Speter    }
394251875Speter    else if (new->pid == 0) {
395251875Speter        /* child process */
396251875Speter
397251875Speter        /*
398251875Speter         * If we do exec cleanup before the dup2() calls to set up pipes
399251875Speter         * on 0-2, we accidentally close the pipes used by programs like
400251875Speter         * mod_cgid.
401251875Speter         *
402251875Speter         * If we do exec cleanup after the dup2() calls, cleanup can accidentally
403251875Speter         * close our pipes which replaced any files which previously had
404251875Speter         * descriptors 0-2.
405251875Speter         *
406251875Speter         * The solution is to kill the cleanup for the pipes, then do
407251875Speter         * exec cleanup, then do the dup2() calls.
408251875Speter         */
409251875Speter
410251875Speter        if (attr->child_in) {
411251875Speter            apr_pool_cleanup_kill(apr_file_pool_get(attr->child_in),
412251875Speter                                  attr->child_in, apr_unix_file_cleanup);
413251875Speter        }
414251875Speter
415251875Speter        if (attr->child_out) {
416251875Speter            apr_pool_cleanup_kill(apr_file_pool_get(attr->child_out),
417251875Speter                                  attr->child_out, apr_unix_file_cleanup);
418251875Speter        }
419251875Speter
420251875Speter        if (attr->child_err) {
421251875Speter            apr_pool_cleanup_kill(apr_file_pool_get(attr->child_err),
422251875Speter                                  attr->child_err, apr_unix_file_cleanup);
423251875Speter        }
424251875Speter
425251875Speter        apr_pool_cleanup_for_exec();
426251875Speter
427251875Speter        if ((attr->child_in) && (attr->child_in->filedes == -1)) {
428251875Speter            close(STDIN_FILENO);
429251875Speter        }
430251875Speter        else if (attr->child_in &&
431251875Speter                 attr->child_in->filedes != STDIN_FILENO) {
432251875Speter            dup2(attr->child_in->filedes, STDIN_FILENO);
433251875Speter            apr_file_close(attr->child_in);
434251875Speter        }
435251875Speter
436251875Speter        if ((attr->child_out) && (attr->child_out->filedes == -1)) {
437251875Speter            close(STDOUT_FILENO);
438251875Speter        }
439251875Speter        else if (attr->child_out &&
440251875Speter                 attr->child_out->filedes != STDOUT_FILENO) {
441251875Speter            dup2(attr->child_out->filedes, STDOUT_FILENO);
442251875Speter            apr_file_close(attr->child_out);
443251875Speter        }
444251875Speter
445251875Speter        if ((attr->child_err) && (attr->child_err->filedes == -1)) {
446251875Speter            close(STDERR_FILENO);
447251875Speter        }
448251875Speter        else if (attr->child_err &&
449251875Speter                 attr->child_err->filedes != STDERR_FILENO) {
450251875Speter            dup2(attr->child_err->filedes, STDERR_FILENO);
451251875Speter            apr_file_close(attr->child_err);
452251875Speter        }
453251875Speter
454251875Speter        apr_signal(SIGCHLD, SIG_DFL); /* not sure if this is needed or not */
455251875Speter
456251875Speter        if (attr->currdir != NULL) {
457251875Speter            if (chdir(attr->currdir) == -1) {
458251875Speter                if (attr->errfn) {
459251875Speter                    attr->errfn(pool, errno, "change of working directory failed");
460251875Speter                }
461251875Speter                _exit(-1);   /* We have big problems, the child should exit. */
462251875Speter            }
463251875Speter        }
464251875Speter
465251875Speter        /* Only try to switch if we are running as root */
466251875Speter        if (attr->gid != -1 && !geteuid()) {
467251875Speter            if (setgid(attr->gid)) {
468251875Speter                if (attr->errfn) {
469251875Speter                    attr->errfn(pool, errno, "setting of group failed");
470251875Speter                }
471251875Speter                _exit(-1);   /* We have big problems, the child should exit. */
472251875Speter            }
473251875Speter        }
474251875Speter
475251875Speter        if (attr->uid != -1 && !geteuid()) {
476251875Speter            if (setuid(attr->uid)) {
477251875Speter                if (attr->errfn) {
478251875Speter                    attr->errfn(pool, errno, "setting of user failed");
479251875Speter                }
480251875Speter                _exit(-1);   /* We have big problems, the child should exit. */
481251875Speter            }
482251875Speter        }
483251875Speter
484251875Speter        if (limit_proc(attr) != APR_SUCCESS) {
485251875Speter            if (attr->errfn) {
486251875Speter                attr->errfn(pool, errno, "setting of resource limits failed");
487251875Speter            }
488251875Speter            _exit(-1);   /* We have big problems, the child should exit. */
489251875Speter        }
490251875Speter
491251875Speter        if (attr->cmdtype == APR_SHELLCMD ||
492251875Speter            attr->cmdtype == APR_SHELLCMD_ENV) {
493251875Speter            int onearg_len = 0;
494251875Speter            const char *newargs[4];
495251875Speter
496251875Speter            newargs[0] = SHELL_PATH;
497251875Speter            newargs[1] = "-c";
498251875Speter
499251875Speter            i = 0;
500251875Speter            while (args[i]) {
501251875Speter                onearg_len += strlen(args[i]);
502251875Speter                onearg_len++; /* for space delimiter */
503251875Speter                i++;
504251875Speter            }
505251875Speter
506251875Speter            switch(i) {
507251875Speter            case 0:
508251875Speter                /* bad parameters; we're doomed */
509251875Speter                break;
510251875Speter            case 1:
511251875Speter                /* no args, or caller already built a single string from
512251875Speter                 * progname and args
513251875Speter                 */
514251875Speter                newargs[2] = args[0];
515251875Speter                break;
516251875Speter            default:
517251875Speter            {
518251875Speter                char *ch, *onearg;
519251875Speter
520251875Speter                ch = onearg = apr_palloc(pool, onearg_len);
521251875Speter                i = 0;
522251875Speter                while (args[i]) {
523251875Speter                    size_t len = strlen(args[i]);
524251875Speter
525251875Speter                    memcpy(ch, args[i], len);
526251875Speter                    ch += len;
527251875Speter                    *ch = ' ';
528251875Speter                    ++ch;
529251875Speter                    ++i;
530251875Speter                }
531251875Speter                --ch; /* back up to trailing blank */
532251875Speter                *ch = '\0';
533251875Speter                newargs[2] = onearg;
534251875Speter            }
535251875Speter            }
536251875Speter
537251875Speter            newargs[3] = NULL;
538251875Speter
539251875Speter            if (attr->detached) {
540251875Speter                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
541251875Speter            }
542251875Speter
543251875Speter            if (attr->cmdtype == APR_SHELLCMD) {
544251875Speter                execve(SHELL_PATH, (char * const *) newargs, (char * const *)env);
545251875Speter            }
546251875Speter            else {
547251875Speter                execv(SHELL_PATH, (char * const *)newargs);
548251875Speter            }
549251875Speter        }
550251875Speter        else if (attr->cmdtype == APR_PROGRAM) {
551251875Speter            if (attr->detached) {
552251875Speter                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
553251875Speter            }
554251875Speter
555251875Speter            execve(progname, (char * const *)args, (char * const *)env);
556251875Speter        }
557251875Speter        else if (attr->cmdtype == APR_PROGRAM_ENV) {
558251875Speter            if (attr->detached) {
559251875Speter                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
560251875Speter            }
561251875Speter
562251875Speter            execv(progname, (char * const *)args);
563251875Speter        }
564251875Speter        else {
565251875Speter            /* APR_PROGRAM_PATH */
566251875Speter            if (attr->detached) {
567251875Speter                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
568251875Speter            }
569251875Speter
570251875Speter            execvp(progname, (char * const *)args);
571251875Speter        }
572251875Speter        if (attr->errfn) {
573251875Speter            char *desc;
574251875Speter
575251875Speter            desc = apr_psprintf(pool, "exec of '%s' failed",
576251875Speter                                progname);
577251875Speter            attr->errfn(pool, errno, desc);
578251875Speter        }
579251875Speter
580251875Speter        _exit(-1);  /* if we get here, there is a problem, so exit with an
581251875Speter                     * error code. */
582251875Speter    }
583251875Speter
584251875Speter    /* Parent process */
585251875Speter    if (attr->child_in && (attr->child_in->filedes != -1)) {
586251875Speter        apr_file_close(attr->child_in);
587251875Speter    }
588251875Speter
589251875Speter    if (attr->child_out && (attr->child_out->filedes != -1)) {
590251875Speter        apr_file_close(attr->child_out);
591251875Speter    }
592251875Speter
593251875Speter    if (attr->child_err && (attr->child_err->filedes != -1)) {
594251875Speter        apr_file_close(attr->child_err);
595251875Speter    }
596251875Speter
597251875Speter    return APR_SUCCESS;
598251875Speter}
599251875Speter
600251875SpeterAPR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
601251875Speter                                                  int *exitcode,
602251875Speter                                                  apr_exit_why_e *exitwhy,
603251875Speter                                                  apr_wait_how_e waithow,
604251875Speter                                                  apr_pool_t *p)
605251875Speter{
606251875Speter    proc->pid = -1;
607251875Speter    return apr_proc_wait(proc, exitcode, exitwhy, waithow);
608251875Speter}
609251875Speter
610251875SpeterAPR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc,
611251875Speter                                        int *exitcode, apr_exit_why_e *exitwhy,
612251875Speter                                        apr_wait_how_e waithow)
613251875Speter{
614251875Speter    pid_t pstatus;
615251875Speter    int waitpid_options = WUNTRACED;
616251875Speter    int exit_int;
617251875Speter    int ignore;
618251875Speter    apr_exit_why_e ignorewhy;
619251875Speter
620251875Speter    if (exitcode == NULL) {
621251875Speter        exitcode = &ignore;
622251875Speter    }
623251875Speter
624251875Speter    if (exitwhy == NULL) {
625251875Speter        exitwhy = &ignorewhy;
626251875Speter    }
627251875Speter
628251875Speter    if (waithow != APR_WAIT) {
629251875Speter        waitpid_options |= WNOHANG;
630251875Speter    }
631251875Speter
632251875Speter    do {
633251875Speter        pstatus = waitpid(proc->pid, &exit_int, waitpid_options);
634251875Speter    } while (pstatus < 0 && errno == EINTR);
635251875Speter
636251875Speter    if (pstatus > 0) {
637251875Speter        proc->pid = pstatus;
638251875Speter
639251875Speter        if (WIFEXITED(exit_int)) {
640251875Speter            *exitwhy = APR_PROC_EXIT;
641251875Speter            *exitcode = WEXITSTATUS(exit_int);
642251875Speter        }
643251875Speter        else if (WIFSIGNALED(exit_int)) {
644251875Speter            *exitwhy = APR_PROC_SIGNAL;
645251875Speter
646251875Speter#ifdef WCOREDUMP
647251875Speter            if (WCOREDUMP(exit_int)) {
648251875Speter                *exitwhy |= APR_PROC_SIGNAL_CORE;
649251875Speter            }
650251875Speter#endif
651251875Speter
652251875Speter            *exitcode = WTERMSIG(exit_int);
653251875Speter        }
654251875Speter        else {
655251875Speter            /* unexpected condition */
656251875Speter            return APR_EGENERAL;
657251875Speter        }
658251875Speter
659251875Speter        return APR_CHILD_DONE;
660251875Speter    }
661251875Speter    else if (pstatus == 0) {
662251875Speter        return APR_CHILD_NOTDONE;
663251875Speter    }
664251875Speter
665251875Speter    return errno;
666251875Speter}
667251875Speter
668251875Speter#if APR_HAVE_STRUCT_RLIMIT
669251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr,
670251875Speter                                                 apr_int32_t what,
671251875Speter                                                 struct rlimit *limit)
672251875Speter{
673251875Speter    switch(what) {
674251875Speter        case APR_LIMIT_CPU:
675251875Speter#ifdef RLIMIT_CPU
676251875Speter            attr->limit_cpu = limit;
677251875Speter            break;
678251875Speter#else
679251875Speter            return APR_ENOTIMPL;
680251875Speter#endif
681251875Speter
682251875Speter        case APR_LIMIT_MEM:
683251875Speter#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
684251875Speter            attr->limit_mem = limit;
685251875Speter            break;
686251875Speter#else
687251875Speter            return APR_ENOTIMPL;
688251875Speter#endif
689251875Speter
690251875Speter        case APR_LIMIT_NPROC:
691251875Speter#ifdef RLIMIT_NPROC
692251875Speter            attr->limit_nproc = limit;
693251875Speter            break;
694251875Speter#else
695251875Speter            return APR_ENOTIMPL;
696251875Speter#endif
697251875Speter
698251875Speter        case APR_LIMIT_NOFILE:
699251875Speter#ifdef RLIMIT_NOFILE
700251875Speter            attr->limit_nofile = limit;
701251875Speter            break;
702251875Speter#else
703251875Speter            return APR_ENOTIMPL;
704251875Speter#endif
705251875Speter
706251875Speter    }
707251875Speter
708251875Speter    return APR_SUCCESS;
709251875Speter}
710251875Speter#endif /* APR_HAVE_STRUCT_RLIMIT */
711251875Speter
712