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#include "apr_strings.h"
20#include "apr_portable.h"
21
22#include <proc.h>
23
24/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
25 * requested for a specific child handle;
26 */
27static apr_file_t no_file = { NULL, -1, };
28
30{
32 int exit_int;
34
35 if (proc->pid > 0) {
37 }
38
39/* NXVmDestroy(proc->pid); */
40 return APR_SUCCESS;
41}
42
44{
45 (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
46
47 if ((*new) == NULL) {
48 return APR_ENOMEM;
49 }
50 (*new)->pool = pool;
51 (*new)->cmdtype = APR_PROGRAM;
52 /* Default to a current path since NetWare doesn't handle it very well */
53 apr_filepath_get(&((*new)->currdir), APR_FILEPATH_NATIVE, pool);
54 (*new)->detached = 1;
55 return APR_SUCCESS;
56
57}
58
63{
64 apr_status_t rv;
65
66 if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) {
67 /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
68 * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose
69 * the CHILD/PARENT blocking flags for the stdin pipe.
70 * stdout/stderr map to the correct mode by default.
71 */
72 if (in == APR_CHILD_BLOCK)
74 else if (in == APR_PARENT_BLOCK)
76
78 in, attr->pool)) == APR_SUCCESS)
80 if (rv != APR_SUCCESS)
81 return rv;
82 }
83 else if (in == APR_NO_FILE)
85
86 if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) {
88 out, attr->pool)) == APR_SUCCESS)
90 if (rv != APR_SUCCESS)
91 return rv;
92 }
93 else if (out == APR_NO_FILE)
95
96 if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) {
98 err, attr->pool)) == APR_SUCCESS)
100 if (rv != APR_SUCCESS)
101 return rv;
102 }
103 else if (err == APR_NO_FILE)
105
106 return APR_SUCCESS;
107}
108
109
112{
114
115 if (attr->child_in == NULL && attr->parent_in == NULL
116 && child_in == NULL && parent_in == NULL)
118 attr->pool)) == APR_SUCCESS)
120
121 if (child_in != NULL && rv == APR_SUCCESS) {
122 if (attr->child_in && (attr->child_in->filedes != -1))
124 else {
125 attr->child_in = NULL;
126 if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool))
127 == APR_SUCCESS)
129 }
130 }
131
132 if (parent_in != NULL && rv == APR_SUCCESS) {
134 }
135
136 return rv;
137}
138
139
142{
144
145 if (attr->child_out == NULL && attr->parent_out == NULL
146 && child_out == NULL && parent_out == NULL)
148 attr->pool)) == APR_SUCCESS)
150
151 if (child_out != NULL && rv == APR_SUCCESS) {
152 if (attr->child_out && (attr->child_out->filedes != -1))
154 else {
157 == APR_SUCCESS)
159 }
160 }
161
162 if (parent_out != NULL && rv == APR_SUCCESS) {
164 }
165
166 return rv;
167}
168
169
172{
174
175 if (attr->child_err == NULL && attr->parent_err == NULL
176 && child_err == NULL && parent_err == NULL)
178 attr->pool)) == APR_SUCCESS)
180
181 if (child_err != NULL && rv == APR_SUCCESS) {
182 if (attr->child_err && (attr->child_err->filedes != -1))
184 else {
187 == APR_SUCCESS)
189 }
190 }
191
192 if (parent_err != NULL && rv == APR_SUCCESS) {
194 }
195
196 return rv;
197}
198
199
201 const char *dir)
202{
205}
206
209{
210 /* won't ever be called on this platform, so don't save the function pointer */
211 return APR_SUCCESS;
212}
213
215{
217 return APR_SUCCESS;
218}
219
220#if APR_HAS_FORK
222{
223 int pid;
224
225 if ((pid = fork()) < 0) {
226 return errno;
227 }
228 else if (pid == 0) {
229 proc->pid = pid;
230 proc->in = NULL;
231 proc->out = NULL;
232 proc->err = NULL;
233 return APR_INCHILD;
234 }
235 proc->pid = pid;
236 proc->in = NULL;
237 proc->out = NULL;
238 proc->err = NULL;
239 return APR_INPARENT;
240}
241#endif
242
244{
245#if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT
246#ifdef RLIMIT_CPU
247 if (attr->limit_cpu != NULL) {
248 if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) {
249 return errno;
250 }
251 }
252#endif
253#ifdef RLIMIT_NPROC
254 if (attr->limit_nproc != NULL) {
255 if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) {
256 return errno;
257 }
258 }
259#endif
260#if defined(RLIMIT_AS)
261 if (attr->limit_mem != NULL) {
262 if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) {
263 return errno;
264 }
265 }
266#elif defined(RLIMIT_DATA)
267 if (attr->limit_mem != NULL) {
268 if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) {
269 return errno;
270 }
271 }
272#elif defined(RLIMIT_VMEM)
273 if (attr->limit_mem != NULL) {
274 if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) {
275 return errno;
276 }
277 }
278#endif
279#else
280 /*
281 * Maybe make a note in error_log that setrlimit isn't supported??
282 */
283
284#endif
285 return APR_SUCCESS;
286}
287
290{
291 /* won't ever be called on this platform, so don't save the function pointer */
292 return APR_SUCCESS;
293}
294
297{
298 /* won't ever be used on this platform, so don't save the flag */
299 return APR_SUCCESS;
300}
301
304{
306 return APR_SUCCESS;
307}
308
310 const char *progname,
311 const char * const *args,
312 const char * const *env,
315{
317 int addr_space;
318
319 wire.infd = attr->child_in
320 ? (attr->child_in->filedes != -1 ? attr->child_in->filedes
321 : FD_UNUSED)
322 : fileno(stdin);
323 wire.outfd = attr->child_out
325 : FD_UNUSED)
326 : fileno(stdout);
327 wire.errfd = attr->child_err
329 : FD_UNUSED)
330 : fileno(stderr);
331
335
336 /* attr->detached and PROC_DETACHED do not mean the same thing. attr->detached means
337 * start the NLM in a separate address space. PROC_DETACHED means don't wait for the
338 * NLM to unload by calling wait() or waitpid(), just clean up */
341
342 if (attr->currdir) {
343 char *fullpath = NULL;
344 apr_status_t rv;
345
348 return rv;
349 }
351 }
352
353 if ((newproc->pid = procve(progname, addr_space, (const char**)env, &wire,
354 NULL, NULL, 0, NULL, (const char **)args)) == -1) {
355 return errno;
356 }
357
358 if (attr->child_in && (attr->child_in->filedes != -1)) {
362 }
363 if (attr->child_out && (attr->child_out->filedes != -1)) {
367 }
368 if (attr->child_err && (attr->child_err->filedes != -1)) {
372 }
373
376
377 return APR_SUCCESS;
378}
379
381 int *exitcode,
384 apr_pool_t *p)
385{
386 proc->pid = -1;
388}
389
393{
396 int exit_int;
397 int ignore;
399
400 if (exitcode == NULL) {
401 exitcode = &ignore;
402 }
403
404 if (exitwhy == NULL) {
406 }
407
408 if (waithow != APR_WAIT) {
410 }
411
412 /* If the pid is 0 then the process was started detached. There
413 is no need to wait since there is nothing to wait for on a
414 detached process. Starting a process as non-detached and
415 then calling wait or waitpid could cause the thread to hang.
416 The reason for this is because NetWare does not have a way
417 to kill or even signal a process to be killed. Starting
418 all processes as detached avoids the possibility of a
419 thread hanging. */
420 if (proc->pid == 0) {
422 *exitcode = 0;
423 return APR_CHILD_DONE;
424 }
425
426 if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) {
427 proc->pid = pstatus;
428
429 if (WIFEXITED(exit_int)) {
432 }
433 else if (WIFSIGNALED(exit_int)) {
436 }
437 else {
438 /* unexpected condition */
439 return APR_EGENERAL;
440 }
441
442 return APR_CHILD_DONE;
443 }
444 else if (pstatus == 0) {
445 return APR_CHILD_NOTDONE;
446 }
447
448 return errno;
449}
450
451#if APR_HAVE_STRUCT_RLIMIT
454 struct rlimit *limit)
455{
456 switch(what) {
457 case APR_LIMIT_CPU:
458#ifdef RLIMIT_CPU
459 attr->limit_cpu = limit;
460 break;
461#else
462 return APR_ENOTIMPL;
463#endif
464
465 case APR_LIMIT_MEM:
466#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
467 attr->limit_mem = limit;
468 break;
469#else
470 return APR_ENOTIMPL;
471#endif
472
473 case APR_LIMIT_NPROC:
474#ifdef RLIMIT_NPROC
475 attr->limit_nproc = limit;
476 break;
477#else
478 return APR_ENOTIMPL;
479#endif
480
481 case APR_LIMIT_NOFILE:
482#ifdef RLIMIT_NOFILE
483 attr->limit_nofile = limit;
484 break;
485#else
486 return APR_ENOTIMPL;
487#endif
488
489 }
490 return APR_SUCCESS;
491}
492#endif /* APR_HAVE_STRUCT_RLIMIT */
493
495 const char *username,
496 const char *password)
497{
498 /* Always return SUCCESS because NetWare threads don't run as a user */
499 return APR_SUCCESS;
500}
501
503 const char *groupname)
504{
505 /* Always return SUCCESS because NetWare threads don't run within a group */
506 return APR_SUCCESS;
507}
508
511 void *data,
513{
514 return APR_ENOTIMPL;
515}
APR Portability Routines.
APR Strings 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_INCHILD
Definition apr_errno.h:438
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_INPARENT
Definition apr_errno.h:440
#define APR_ENOTIMPL
Definition apr_errno.h:476
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_SUCCESS
Definition apr_errno.h:225
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
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
apr_proc_t * proc
const char const char * password
apr_int32_t apr_int32_t apr_int32_t err
#define APR_LIMIT_NOFILE
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
#define APR_LIMIT_MEM
int apr_exit_why_e * exitwhy
#define APR_LIMIT_NPROC
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
#define APR_LIMIT_CPU
const char const char *const * args
#define APR_NO_PIPE
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
apr_int32_t detach
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_PROGRAM
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
static apr_status_t limit_proc(apr_procattr_t *attr)
Definition proc.c:243
static apr_status_t apr_netware_proc_cleanup(void *theproc)
Definition proc.c:29
apr_file_t * in
apr_file_t * out
apr_file_t * err
apr_file_t * child_err
apr_file_t * parent_in
apr_file_t * parent_out
apr_file_t * child_out
apr_file_t * child_in
apr_file_t * parent_err
static apr_proc_t newproc
Definition testproc.c:30
apr_status_t apr_unix_file_cleanup(void *thefile)
Definition open.c:71
int waitpid(pid_t pid, int *statusp, int options)
Definition procsup.c:91