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.h"
18#include "apr_arch_misc.h"
19#include "apr_arch_threadproc.h"
20#include "apr_arch_file_io.h"
21
22#if APR_HAS_OTHER_CHILD
23
24#ifdef HAVE_TIME_H
25#include <sys/time.h>
26#endif
27#ifdef HAVE_SYS_SELECT_H
28#include <sys/select.h>
29#endif
30#if APR_HAVE_SYS_WAIT_H
31#include <sys/wait.h>
32#endif
33#ifdef BEOS
34#include <sys/socket.h> /* for fd_set definition! */
35#endif
36
37static apr_other_child_rec_t *other_children = NULL;
38
39static apr_status_t other_child_cleanup(void *data)
40{
41    apr_other_child_rec_t **pocr, *nocr;
42
43    for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) {
44        if ((*pocr)->data == data) {
45            nocr = (*pocr)->next;
46            (*(*pocr)->maintenance) (APR_OC_REASON_UNREGISTER, (*pocr)->data, -1);
47            *pocr = nocr;
48            /* XXX: um, well we've just wasted some space in pconf ? */
49            return APR_SUCCESS;
50        }
51    }
52    return APR_SUCCESS;
53}
54
55APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc,
56                     void (*maintenance) (int reason, void *, int status),
57                     void *data, apr_file_t *write_fd, apr_pool_t *p)
58{
59    apr_other_child_rec_t *ocr;
60
61    ocr = apr_palloc(p, sizeof(*ocr));
62    ocr->p = p;
63    ocr->proc = proc;
64    ocr->maintenance = maintenance;
65    ocr->data = data;
66    if (write_fd == NULL) {
67        ocr->write_fd = (apr_os_file_t) -1;
68    }
69    else {
70#ifdef WIN32
71        /* This should either go away as part of eliminating apr_proc_probe_writable_fds
72         * or write_fd should point to an apr_file_t
73         */
74        ocr->write_fd = write_fd->filehand;
75#else
76        ocr->write_fd = write_fd->filedes;
77#endif
78
79    }
80    ocr->next = other_children;
81    other_children = ocr;
82    apr_pool_cleanup_register(p, ocr->data, other_child_cleanup,
83                              apr_pool_cleanup_null);
84}
85
86APR_DECLARE(void) apr_proc_other_child_unregister(void *data)
87{
88    apr_other_child_rec_t *cur;
89
90    cur = other_children;
91    while (cur) {
92        if (cur->data == data) {
93            break;
94        }
95        cur = cur->next;
96    }
97
98    /* segfault if this function called with invalid parm */
99    apr_pool_cleanup_kill(cur->p, cur->data, other_child_cleanup);
100    other_child_cleanup(data);
101}
102
103APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc,
104                                                     int reason,
105                                                     int status)
106{
107    apr_other_child_rec_t *ocr, *nocr;
108
109    for (ocr = other_children; ocr; ocr = nocr) {
110        nocr = ocr->next;
111        if (ocr->proc->pid != proc->pid)
112            continue;
113
114        ocr->proc = NULL;
115        (*ocr->maintenance) (reason, ocr->data, status);
116        return APR_SUCCESS;
117    }
118    return APR_EPROC_UNKNOWN;
119}
120
121APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr,
122                                               int reason)
123{
124    /* Todo:
125     * Implement code to detect if pipes are still alive.
126     */
127#ifdef WIN32
128    DWORD status;
129
130    if (ocr->proc == NULL)
131        return;
132
133    if (!ocr->proc->hproc) {
134        /* Already mopped up, perhaps we apr_proc_kill'ed it,
135         * they should have already unregistered!
136         */
137        ocr->proc = NULL;
138        (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
139    }
140    else if (!GetExitCodeProcess(ocr->proc->hproc, &status)) {
141        CloseHandle(ocr->proc->hproc);
142        ocr->proc->hproc = NULL;
143        ocr->proc = NULL;
144        (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
145    }
146    else if (status == STILL_ACTIVE) {
147        (*ocr->maintenance) (reason, ocr->data, -1);
148    }
149    else {
150        CloseHandle(ocr->proc->hproc);
151        ocr->proc->hproc = NULL;
152        ocr->proc = NULL;
153        (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status);
154    }
155
156#else /* ndef Win32 */
157    pid_t waitret;
158    int status;
159
160    if (ocr->proc == NULL)
161        return;
162
163    waitret = waitpid(ocr->proc->pid, &status, WNOHANG);
164    if (waitret == ocr->proc->pid) {
165        ocr->proc = NULL;
166        (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status);
167    }
168    else if (waitret == 0) {
169        (*ocr->maintenance) (reason, ocr->data, -1);
170    }
171    else if (waitret == -1) {
172        /* uh what the heck? they didn't call unregister? */
173        ocr->proc = NULL;
174        (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1);
175    }
176#endif
177}
178
179APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason)
180{
181    apr_other_child_rec_t *ocr, *next_ocr;
182
183    for (ocr = other_children; ocr; ocr = next_ocr) {
184        next_ocr = ocr->next;
185        apr_proc_other_child_refresh(ocr, reason);
186    }
187}
188
189#else /* !APR_HAS_OTHER_CHILD */
190
191APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc,
192                     void (*maintenance) (int reason, void *, int status),
193                     void *data, apr_file_t *write_fd, apr_pool_t *p)
194{
195    return;
196}
197
198APR_DECLARE(void) apr_proc_other_child_unregister(void *data)
199{
200    return;
201}
202
203APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc,
204                                                     int reason,
205                                                     int status)
206{
207    return APR_ENOTIMPL;
208}
209
210APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr,
211                                               int reason)
212{
213    return;
214}
215
216APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason)
217{
218    return;
219}
220
221#endif /* APR_HAS_OTHER_CHILD */
222