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_strings.h"
19
20 /* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
21 * requested for a specific child handle;
22 */
23 static apr_file_t no_file = { NULL, -1, };
24
25 struct send_pipe {
26 int in;
27 int out;
28 int err;
29 };
30
apr_procattr_create(apr_procattr_t ** new,apr_pool_t * pool)31 APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, apr_pool_t *pool)
32 {
33 (*new) = (apr_procattr_t *)apr_palloc(pool,
34 sizeof(apr_procattr_t));
35
36 if ((*new) == NULL) {
37 return APR_ENOMEM;
38 }
39 (*new)->pool = pool;
40 (*new)->parent_in = NULL;
41 (*new)->child_in = NULL;
42 (*new)->parent_out = NULL;
43 (*new)->child_out = NULL;
44 (*new)->parent_err = NULL;
45 (*new)->child_err = NULL;
46 (*new)->currdir = NULL;
47 (*new)->cmdtype = APR_PROGRAM;
48 (*new)->detached = 0;
49 return APR_SUCCESS;
50 }
51
apr_procattr_io_set(apr_procattr_t * attr,apr_int32_t in,apr_int32_t out,apr_int32_t err)52 APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr,
53 apr_int32_t in,
54 apr_int32_t out,
55 apr_int32_t err)
56 {
57 apr_status_t rv;
58
59 if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) {
60 /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
61 * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose
62 * the CHILD/PARENT blocking flags for the stdin pipe.
63 * stdout/stderr map to the correct mode by default.
64 */
65 if (in == APR_CHILD_BLOCK)
66 in = APR_READ_BLOCK;
67 else if (in == APR_PARENT_BLOCK)
68 in = APR_WRITE_BLOCK;
69
70 if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in,
71 in, attr->pool)) == APR_SUCCESS)
72 rv = apr_file_inherit_unset(attr->parent_in);
73 if (rv != APR_SUCCESS)
74 return rv;
75 }
76 else if (in == APR_NO_FILE)
77 attr->child_in = &no_file;
78
79 if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) {
80 if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out,
81 out, attr->pool)) == APR_SUCCESS)
82 rv = apr_file_inherit_unset(attr->parent_out);
83 if (rv != APR_SUCCESS)
84 return rv;
85 }
86 else if (out == APR_NO_FILE)
87 attr->child_out = &no_file;
88
89 if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) {
90 if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err,
91 err, attr->pool)) == APR_SUCCESS)
92 rv = apr_file_inherit_unset(attr->parent_err);
93 if (rv != APR_SUCCESS)
94 return rv;
95 }
96 else if (err == APR_NO_FILE)
97 attr->child_err = &no_file;
98
99 return APR_SUCCESS;
100 }
101
apr_procattr_dir_set(apr_procattr_t * attr,const char * dir)102 APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr,
103 const char *dir)
104 {
105 char * cwd;
106 if (dir[0] != '/') {
107 cwd = (char*)malloc(sizeof(char) * PATH_MAX);
108 getcwd(cwd, PATH_MAX);
109 attr->currdir = (char *)apr_pstrcat(attr->pool, cwd, "/", dir, NULL);
110 free(cwd);
111 } else {
112 attr->currdir = (char *)apr_pstrdup(attr->pool, dir);
113 }
114 if (attr->currdir) {
115 return APR_SUCCESS;
116 }
117 return APR_ENOMEM;
118 }
119
apr_procattr_cmdtype_set(apr_procattr_t * attr,apr_cmdtype_e cmd)120 APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
121 apr_cmdtype_e cmd)
122 {
123 attr->cmdtype = cmd;
124 return APR_SUCCESS;
125 }
126
apr_procattr_detach_set(apr_procattr_t * attr,apr_int32_t detach)127 APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach)
128 {
129 attr->detached = detach;
130 return APR_SUCCESS;
131 }
132
apr_proc_fork(apr_proc_t * proc,apr_pool_t * pool)133 APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
134 {
135 int pid;
136
137 if ((pid = fork()) < 0) {
138 return errno;
139 }
140 else if (pid == 0) {
141 /* This is really ugly...
142 * The semantics of BeOS's fork() are that areas (used for shared
143 * memory) get COW'd :-( The only way we can make shared memory
144 * work across fork() is therefore to find any areas that have
145 * been created and then clone them into our address space.
146 * Thankfully only COW'd areas have the lock variable set at
147 * anything but 0, so we can use that to find the areas we need to
148 * copy. Of course what makes it even worse is that the loop through
149 * the area's will go into an infinite loop, eating memory and then
150 * eventually segfault unless we know when we reach then end of the
151 * "original" areas and stop. Why? Well, we delete the area and then
152 * add another to the end of the list...
153 */
154 area_info ai;
155 int32 cookie = 0;
156 area_id highest = 0;
157
158 while (get_next_area_info(0, &cookie, &ai) == B_OK)
159 if (ai.area > highest)
160 highest = ai.area;
161 cookie = 0;
162 while (get_next_area_info(0, &cookie, &ai) == B_OK) {
163 if (ai.area > highest)
164 break;
165 if (ai.lock > 0) {
166 area_id original = find_area(ai.name);
167 delete_area(ai.area);
168 clone_area(ai.name, &ai.address, B_CLONE_ADDRESS,
169 ai.protection, original);
170 }
171 }
172
173 proc->pid = pid;
174 proc->in = NULL;
175 proc->out = NULL;
176 proc->err = NULL;
177 return APR_INCHILD;
178 }
179 proc->pid = pid;
180 proc->in = NULL;
181 proc->out = NULL;
182 proc->err = NULL;
183 return APR_INPARENT;
184 }
185
apr_procattr_child_errfn_set(apr_procattr_t * attr,apr_child_errfn_t * errfn)186 APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
187 apr_child_errfn_t *errfn)
188 {
189 /* won't ever be called on this platform, so don't save the function pointer */
190 return APR_SUCCESS;
191 }
192
apr_procattr_error_check_set(apr_procattr_t * attr,apr_int32_t chk)193 APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
194 apr_int32_t chk)
195 {
196 /* won't ever be used on this platform, so don't save the flag */
197 return APR_SUCCESS;
198 }
199
apr_procattr_addrspace_set(apr_procattr_t * attr,apr_int32_t addrspace)200 APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
201 apr_int32_t addrspace)
202 {
203 /* won't ever be used on this platform, so don't save the flag */
204 return APR_SUCCESS;
205 }
206
apr_proc_create(apr_proc_t * new,const char * progname,const char * const * args,const char * const * env,apr_procattr_t * attr,apr_pool_t * pool)207 APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, const char *progname,
208 const char * const *args,
209 const char * const *env,
210 apr_procattr_t *attr,
211 apr_pool_t *pool)
212 {
213 int i=0,nargs=0;
214 char **newargs = NULL;
215 thread_id newproc, sender;
216 struct send_pipe *sp;
217 char * dir = NULL;
218
219 sp = (struct send_pipe *)apr_palloc(pool, sizeof(struct send_pipe));
220
221 new->in = attr->parent_in;
222 new->err = attr->parent_err;
223 new->out = attr->parent_out;
224 sp->in = attr->child_in ? attr->child_in->filedes : FILENO_STDIN;
225 sp->out = attr->child_out ? attr->child_out->filedes : FILENO_STDOUT;
226 sp->err = attr->child_err ? attr->child_err->filedes : FILENO_STDERR;
227
228 i = 0;
229 while (args && args[i]) {
230 i++;
231 }
232
233 newargs = (char**)malloc(sizeof(char *) * (i + 4));
234 newargs[0] = strdup("/boot/home/config/bin/apr_proc_stub");
235 if (attr->currdir == NULL) {
236 /* we require the directory , so use a temp. variable */
237 dir = malloc(sizeof(char) * PATH_MAX);
238 getcwd(dir, PATH_MAX);
239 newargs[1] = strdup(dir);
240 free(dir);
241 } else {
242 newargs[1] = strdup(attr->currdir);
243 }
244 newargs[2] = strdup(progname);
245 i=0;nargs = 3;
246
247 while (args && args[i]) {
248 newargs[nargs] = strdup(args[i]);
249 i++;nargs++;
250 }
251 newargs[nargs] = NULL;
252
253 /* ### we should be looking at attr->cmdtype in here... */
254
255 newproc = load_image(nargs, (const char**)newargs, (const char**)env);
256
257 /* load_image copies the data so now we can free it... */
258 while (--nargs >= 0)
259 free (newargs[nargs]);
260 free(newargs);
261
262 if (newproc < B_NO_ERROR) {
263 return errno;
264 }
265
266 resume_thread(newproc);
267
268 if (attr->child_in && (attr->child_in->filedes != -1)) {
269 apr_file_close(attr->child_in);
270 }
271 if (attr->child_out && (attr->child_in->filedes != -1)) {
272 apr_file_close(attr->child_out);
273 }
274 if (attr->child_err && (attr->child_in->filedes != -1)) {
275 apr_file_close(attr->child_err);
276 }
277
278 send_data(newproc, 0, (void*)sp, sizeof(struct send_pipe));
279 new->pid = newproc;
280
281 /* before we go charging on we need the new process to get to a
282 * certain point. When it gets there it'll let us know and we
283 * can carry on. */
284 receive_data(&sender, (void*)NULL,0);
285
286 return APR_SUCCESS;
287 }
288
apr_proc_wait_all_procs(apr_proc_t * proc,int * exitcode,apr_exit_why_e * exitwhy,apr_wait_how_e waithow,apr_pool_t * p)289 APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
290 int *exitcode,
291 apr_exit_why_e *exitwhy,
292 apr_wait_how_e waithow,
293 apr_pool_t *p)
294 {
295 proc->pid = -1;
296 return apr_proc_wait(proc, exitcode, exitwhy, waithow);
297 }
298
apr_proc_wait(apr_proc_t * proc,int * exitcode,apr_exit_why_e * exitwhy,apr_wait_how_e waithow)299 APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc,
300 int *exitcode,
301 apr_exit_why_e *exitwhy,
302 apr_wait_how_e waithow)
303 {
304 pid_t pstatus;
305 int waitpid_options = WUNTRACED;
306 int exit_int;
307 int ignore;
308 apr_exit_why_e ignorewhy;
309
310 if (exitcode == NULL) {
311 exitcode = &ignore;
312 }
313 if (exitwhy == NULL) {
314 exitwhy = &ignorewhy;
315 }
316
317 if (waithow != APR_WAIT) {
318 waitpid_options |= WNOHANG;
319 }
320
321 if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) {
322 proc->pid = pstatus;
323 if (WIFEXITED(exit_int)) {
324 *exitwhy = APR_PROC_EXIT;
325 *exitcode = WEXITSTATUS(exit_int);
326 }
327 else if (WIFSIGNALED(exit_int)) {
328 *exitwhy = APR_PROC_SIGNAL;
329 *exitcode = WTERMSIG(exit_int);
330 }
331 else {
332
333 /* unexpected condition */
334 return APR_EGENERAL;
335 }
336 return APR_CHILD_DONE;
337 }
338 else if (pstatus == 0) {
339 return APR_CHILD_NOTDONE;
340 }
341
342 return errno;
343 }
344
apr_procattr_child_in_set(apr_procattr_t * attr,apr_file_t * child_in,apr_file_t * parent_in)345 APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in,
346 apr_file_t *parent_in)
347 {
348 apr_status_t rv;
349
350 if (attr->child_in == NULL && attr->parent_in == NULL
351 && child_in == NULL && parent_in == NULL)
352 if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in,
353 attr->pool)) == APR_SUCCESS)
354 rv = apr_file_inherit_unset(attr->parent_in);
355
356 if (child_in != NULL && rv == APR_SUCCESS) {
357 if (attr->child_in && (attr->child_in->filedes != -1))
358 rv = apr_file_dup2(attr->child_in, child_in, attr->pool);
359 else {
360 attr->child_in = NULL;
361 if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool))
362 == APR_SUCCESS)
363 rv = apr_file_inherit_set(attr->child_in);
364 }
365 }
366
367 if (parent_in != NULL && rv == APR_SUCCESS)
368 rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool);
369
370 return rv;
371 }
372
apr_procattr_child_out_set(apr_procattr_t * attr,apr_file_t * child_out,apr_file_t * parent_out)373 APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out,
374 apr_file_t *parent_out)
375 {
376 apr_status_t rv;
377
378 if (attr->child_out == NULL && attr->parent_out == NULL
379 && child_out == NULL && parent_out == NULL)
380 if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out,
381 attr->pool)) == APR_SUCCESS)
382 rv = apr_file_inherit_unset(attr->parent_out);
383
384 if (child_out != NULL && rv == APR_SUCCESS) {
385 if (attr->child_out && (attr->child_out->filedes != -1))
386 rv = apr_file_dup2(attr->child_out, child_out, attr->pool);
387 else {
388 attr->child_out = NULL;
389 if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool))
390 == APR_SUCCESS)
391 rv = apr_file_inherit_set(attr->child_out);
392 }
393 }
394
395 if (parent_out != NULL && rv == APR_SUCCESS)
396 rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool);
397
398 return rv;
399 }
400
apr_procattr_child_err_set(apr_procattr_t * attr,apr_file_t * child_err,apr_file_t * parent_err)401 APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err,
402 apr_file_t *parent_err)
403 {
404 apr_status_t rv;
405
406 if (attr->child_err == NULL && attr->parent_err == NULL
407 && child_err == NULL && parent_err == NULL)
408 if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err,
409 attr->pool)) == APR_SUCCESS)
410 rv = apr_file_inherit_unset(attr->parent_err);
411
412 if (child_err != NULL && rv == APR_SUCCESS) {
413 if (attr->child_err && (attr->child_err->filedes != -1))
414 rv = apr_file_dup2(attr->child_err, child_err, attr->pool);
415 else {
416 attr->child_err = NULL;
417 if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool))
418 == APR_SUCCESS)
419 rv = apr_file_inherit_set(attr->child_err);
420 }
421 }
422
423 if (parent_err != NULL && rv == APR_SUCCESS)
424 rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool);
425
426 return rv;
427 }
428
apr_procattr_limit_set(apr_procattr_t * attr,apr_int32_t what,void * limit)429 APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, apr_int32_t what,
430 void *limit)
431 {
432 return APR_ENOTIMPL;
433 }
434
apr_procattr_user_set(apr_procattr_t * attr,const char * username,const char * password)435 APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr,
436 const char *username,
437 const char *password)
438 {
439 return APR_ENOTIMPL;
440 }
441
apr_procattr_group_set(apr_procattr_t * attr,const char * groupname)442 APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr,
443 const char *groupname)
444 {
445 return APR_ENOTIMPL;
446 }
447