1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
17
#include "apr_arch_threadproc.h"
18
#include "apr_arch_file_io.h"
19
#include "apr_strings.h"
20
#include "apr_portable.h"
24
apr_status_t apr_netware_proc_cleanup(void *theproc)
26
apr_proc_t *proc = theproc;
28
int waitpid_options = WUNTRACED | WNOHANG;
31
waitpid(proc->pid, &exit_int, waitpid_options);
34
/* NXVmDestroy(proc->pid); */
38
APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,apr_pool_t *pool)
40
(*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
46
(*new)->cmdtype = APR_PROGRAM;
47
/* Default to a current path since NetWare doesn't handle it very well */
48
apr_filepath_get(&((*new)->currdir), APR_FILEPATH_NATIVE, pool);
54
APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, apr_int32_t in,
55
apr_int32_t out, apr_int32_t err)
59
if ((status = apr_file_pipe_create(&attr->child_in, &attr->parent_in,
60
attr->pool)) != APR_SUCCESS) {
66
case APR_PARENT_BLOCK:
67
apr_file_pipe_timeout_set(attr->child_in, 0);
70
apr_file_pipe_timeout_set(attr->parent_in, 0);
73
apr_file_pipe_timeout_set(attr->child_in, 0);
74
apr_file_pipe_timeout_set(attr->parent_in, 0);
78
if ((status = apr_file_pipe_create(&attr->parent_out, &attr->child_out,
79
attr->pool)) != APR_SUCCESS) {
85
case APR_PARENT_BLOCK:
86
apr_file_pipe_timeout_set(attr->child_out, 0);
89
apr_file_pipe_timeout_set(attr->parent_out, 0);
92
apr_file_pipe_timeout_set(attr->child_out, 0);
93
apr_file_pipe_timeout_set(attr->parent_out, 0);
97
if ((status = apr_file_pipe_create(&attr->parent_err, &attr->child_err,
98
attr->pool)) != APR_SUCCESS) {
104
case APR_PARENT_BLOCK:
105
apr_file_pipe_timeout_set(attr->child_err, 0);
107
case APR_CHILD_BLOCK:
108
apr_file_pipe_timeout_set(attr->parent_err, 0);
111
apr_file_pipe_timeout_set(attr->child_err, 0);
112
apr_file_pipe_timeout_set(attr->parent_err, 0);
119
APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in,
120
apr_file_t *parent_in)
122
if (attr->child_in == NULL && attr->parent_in == NULL)
123
apr_file_pipe_create(&attr->child_in, &attr->parent_in, attr->pool);
125
if (child_in != NULL)
126
apr_file_dup2(attr->child_in, child_in, attr->pool);
128
if (parent_in != NULL)
129
apr_file_dup2(attr->parent_in, parent_in, attr->pool);
135
APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out,
136
apr_file_t *parent_out)
138
if (attr->child_out == NULL && attr->parent_out == NULL)
139
apr_file_pipe_create(&attr->child_out, &attr->parent_out, attr->pool);
141
if (child_out != NULL)
142
apr_file_dup2(attr->child_out, child_out, attr->pool);
144
if (parent_out != NULL)
145
apr_file_dup2(attr->parent_out, parent_out, attr->pool);
151
APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err,
152
apr_file_t *parent_err)
154
if (attr->child_err == NULL && attr->parent_err == NULL)
155
apr_file_pipe_create(&attr->child_err, &attr->parent_err, attr->pool);
157
if (child_err != NULL)
158
apr_file_dup2(attr->child_err, child_err, attr->pool);
160
if (parent_err != NULL)
161
apr_file_dup2(attr->parent_err, parent_err, attr->pool);
167
APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr,
170
return apr_filepath_merge(&attr->currdir, NULL, dir,
171
APR_FILEPATH_NATIVE, attr->pool);
174
APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
177
/* won't ever be called on this platform, so don't save the function pointer */
181
APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach)
183
attr->detached = detach;
188
APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
192
if ((pid = fork()) < 0) {
210
static apr_status_t limit_proc(apr_procattr_t *attr)
212
#if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT
214
if (attr->limit_cpu != NULL) {
215
if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) {
221
if (attr->limit_nproc != NULL) {
222
if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) {
227
#if defined(RLIMIT_AS)
228
if (attr->limit_mem != NULL) {
229
if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) {
233
#elif defined(RLIMIT_DATA)
234
if (attr->limit_mem != NULL) {
235
if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) {
239
#elif defined(RLIMIT_VMEM)
240
if (attr->limit_mem != NULL) {
241
if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) {
248
* Maybe make a note in error_log that setrlimit isn't supported??
255
APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
256
apr_child_errfn_t *errfn)
258
/* won't ever be called on this platform, so don't save the function pointer */
262
APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
265
/* won't ever be used on this platform, so don't save the flag */
269
APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
270
apr_int32_t addrspace)
272
attr->addrspace = addrspace;
276
APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *newproc,
277
const char *progname,
278
const char * const *args,
279
const char * const *env,
280
apr_procattr_t *attr,
286
wire.infd = attr->child_in ? attr->child_in->filedes : FD_UNUSED;
287
wire.outfd = attr->child_out ? attr->child_out->filedes : FD_UNUSED;
288
wire.errfd = attr->child_err ? attr->child_err->filedes : FD_UNUSED;
290
newproc->in = attr->parent_in;
291
newproc->out = attr->parent_out;
292
newproc->err = attr->parent_err;
294
/* attr->detached and PROC_DETACHED do not mean the same thing. attr->detached means
295
* start the NLM in a separate address space. PROC_DETACHED means don't wait for the
296
* NLM to unload by calling wait() or waitpid(), just clean up */
297
addr_space = PROC_LOAD_SILENT | (attr->addrspace ? 0 : PROC_CURRENT_SPACE);
298
addr_space |= (attr->detached ? PROC_DETACHED : 0);
301
char *fullpath = NULL;
304
if ((rv = apr_filepath_merge(&fullpath, attr->currdir, progname,
305
APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) {
311
if ((newproc->pid = procve(progname, addr_space, (const char**)env, &wire,
312
NULL, NULL, 0, NULL, (const char **)args)) == -1) {
316
if (attr->child_in) {
317
apr_pool_cleanup_kill(apr_file_pool_get(attr->child_in),
318
attr->child_in, apr_unix_file_cleanup);
319
apr_file_close(attr->child_in);
321
if (attr->child_out) {
322
apr_pool_cleanup_kill(apr_file_pool_get(attr->child_out),
323
attr->child_out, apr_unix_file_cleanup);
324
apr_file_close(attr->child_out);
326
if (attr->child_err) {
327
apr_pool_cleanup_kill(apr_file_pool_get(attr->child_err),
328
attr->child_err, apr_unix_file_cleanup);
329
apr_file_close(attr->child_err);
333
apr_pool_cleanup_register(pool, (void *)newproc, apr_netware_proc_cleanup,
334
apr_pool_cleanup_null);
339
APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
341
apr_exit_why_e *exitwhy,
342
apr_wait_how_e waithow,
346
return apr_proc_wait(proc, exitcode, exitwhy, waithow);
349
APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc,
350
int *exitcode, apr_exit_why_e *exitwhy,
351
apr_wait_how_e waithow)
354
int waitpid_options = WUNTRACED;
357
apr_exit_why_e ignorewhy;
359
if (exitcode == NULL) {
363
if (exitwhy == NULL) {
364
exitwhy = &ignorewhy;
367
if (waithow != APR_WAIT) {
368
waitpid_options |= WNOHANG;
371
/* If the pid is 0 then the process was started detached. There
372
is no need to wait since there is nothing to wait for on a
373
detached process. Starting a process as non-detached and
374
then calling wait or waitpid could cause the thread to hang.
375
The reason for this is because NetWare does not have a way
376
to kill or even signal a process to be killed. Starting
377
all processes as detached avoids the possibility of a
379
if (proc->pid == 0) {
380
*exitwhy = APR_PROC_EXIT;
382
return APR_CHILD_DONE;
385
if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) {
388
if (WIFEXITED(exit_int)) {
389
*exitwhy = APR_PROC_EXIT;
390
*exitcode = WEXITSTATUS(exit_int);
392
else if (WIFSIGNALED(exit_int)) {
393
*exitwhy = APR_PROC_SIGNAL;
394
*exitcode = WIFTERMSIG(exit_int);
397
/* unexpected condition */
401
return APR_CHILD_DONE;
403
else if (pstatus == 0) {
404
return APR_CHILD_NOTDONE;
410
APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, apr_int32_t what,
411
struct rlimit *limit)
416
attr->limit_cpu = limit;
422
#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
423
attr->limit_mem = limit;
428
case APR_LIMIT_NPROC:
430
attr->limit_nproc = limit;
439
APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr,
440
const char *username,
441
const char *password)
443
/* Always return SUCCESS because NetWare threads don't run as a user */
447
APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr,
448
const char *groupname)
450
/* Always return SUCCESS because NetWare threads don't run within a group */