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 
apr_netware_proc_cleanup(void * theproc)24 apr_status_t apr_netware_proc_cleanup(void *theproc)
25 {
26     apr_proc_t *proc = theproc;
27     int exit_int;
28     int waitpid_options = WUNTRACED | WNOHANG;
29 
30     if (proc->pid > 0) {
31         waitpid(proc->pid, &exit_int, waitpid_options);
32     }
33 
34 /*	NXVmDestroy(proc->pid); */
35     return APR_SUCCESS;
36 }
37 
apr_procattr_create(apr_procattr_t ** new,apr_pool_t * pool)38 APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,apr_pool_t *pool)
39 {
40     (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
41 
42     if ((*new) == NULL) {
43         return APR_ENOMEM;
44     }
45     (*new)->pool = pool;
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);
49     (*new)->detached = 1;
50     return APR_SUCCESS;
51 
52 }
53 
apr_procattr_io_set(apr_procattr_t * attr,apr_int32_t in,apr_int32_t out,apr_int32_t err)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)
56 {
57     apr_status_t status;
58     if (in != 0) {
59         if ((status = apr_file_pipe_create(&attr->child_in, &attr->parent_in,
60                                    attr->pool)) != APR_SUCCESS) {
61             return status;
62         }
63         switch (in) {
64         case APR_FULL_BLOCK:
65             break;
66         case APR_PARENT_BLOCK:
67             apr_file_pipe_timeout_set(attr->child_in, 0);
68             break;
69         case APR_CHILD_BLOCK:
70             apr_file_pipe_timeout_set(attr->parent_in, 0);
71             break;
72         default:
73             apr_file_pipe_timeout_set(attr->child_in, 0);
74             apr_file_pipe_timeout_set(attr->parent_in, 0);
75         }
76     }
77     if (out) {
78         if ((status = apr_file_pipe_create(&attr->parent_out, &attr->child_out,
79                                    attr->pool)) != APR_SUCCESS) {
80             return status;
81         }
82         switch (out) {
83         case APR_FULL_BLOCK:
84             break;
85         case APR_PARENT_BLOCK:
86             apr_file_pipe_timeout_set(attr->child_out, 0);
87             break;
88         case APR_CHILD_BLOCK:
89             apr_file_pipe_timeout_set(attr->parent_out, 0);
90             break;
91         default:
92             apr_file_pipe_timeout_set(attr->child_out, 0);
93             apr_file_pipe_timeout_set(attr->parent_out, 0);
94         }
95     }
96     if (err) {
97         if ((status = apr_file_pipe_create(&attr->parent_err, &attr->child_err,
98                                    attr->pool)) != APR_SUCCESS) {
99             return status;
100         }
101         switch (err) {
102         case APR_FULL_BLOCK:
103             break;
104         case APR_PARENT_BLOCK:
105             apr_file_pipe_timeout_set(attr->child_err, 0);
106             break;
107         case APR_CHILD_BLOCK:
108             apr_file_pipe_timeout_set(attr->parent_err, 0);
109             break;
110         default:
111             apr_file_pipe_timeout_set(attr->child_err, 0);
112             apr_file_pipe_timeout_set(attr->parent_err, 0);
113         }
114     }
115     return APR_SUCCESS;
116 }
117 
118 
apr_procattr_child_in_set(apr_procattr_t * attr,apr_file_t * child_in,apr_file_t * parent_in)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)
121 {
122     if (attr->child_in == NULL && attr->parent_in == NULL)
123         apr_file_pipe_create(&attr->child_in, &attr->parent_in, attr->pool);
124 
125     if (child_in != NULL)
126         apr_file_dup2(attr->child_in, child_in, attr->pool);
127 
128     if (parent_in != NULL)
129         apr_file_dup2(attr->parent_in, parent_in, attr->pool);
130 
131     return APR_SUCCESS;
132 }
133 
134 
apr_procattr_child_out_set(apr_procattr_t * attr,apr_file_t * child_out,apr_file_t * parent_out)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)
137 {
138     if (attr->child_out == NULL && attr->parent_out == NULL)
139         apr_file_pipe_create(&attr->child_out, &attr->parent_out, attr->pool);
140 
141     if (child_out != NULL)
142         apr_file_dup2(attr->child_out, child_out, attr->pool);
143 
144     if (parent_out != NULL)
145         apr_file_dup2(attr->parent_out, parent_out, attr->pool);
146 
147     return APR_SUCCESS;
148 }
149 
150 
apr_procattr_child_err_set(apr_procattr_t * attr,apr_file_t * child_err,apr_file_t * parent_err)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)
153 {
154     if (attr->child_err == NULL && attr->parent_err == NULL)
155         apr_file_pipe_create(&attr->child_err, &attr->parent_err, attr->pool);
156 
157     if (child_err != NULL)
158         apr_file_dup2(attr->child_err, child_err, attr->pool);
159 
160     if (parent_err != NULL)
161         apr_file_dup2(attr->parent_err, parent_err, attr->pool);
162 
163     return APR_SUCCESS;
164 }
165 
166 
apr_procattr_dir_set(apr_procattr_t * attr,const char * dir)167 APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr,
168                                const char *dir)
169 {
170     return apr_filepath_merge(&attr->currdir, NULL, dir,
171                               APR_FILEPATH_NATIVE, attr->pool);
172 }
173 
apr_procattr_cmdtype_set(apr_procattr_t * attr,apr_cmdtype_e cmd)174 APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
175                                      apr_cmdtype_e cmd)
176 {
177     /* won't ever be called on this platform, so don't save the function pointer */
178     return APR_SUCCESS;
179 }
180 
apr_procattr_detach_set(apr_procattr_t * attr,apr_int32_t detach)181 APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach)
182 {
183     attr->detached = detach;
184     return APR_SUCCESS;
185 }
186 
187 #if APR_HAS_FORK
apr_proc_fork(apr_proc_t * proc,apr_pool_t * pool)188 APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
189 {
190     int pid;
191 
192     if ((pid = fork()) < 0) {
193         return errno;
194     }
195     else if (pid == 0) {
196         proc->pid = pid;
197         proc->in = NULL;
198         proc->out = NULL;
199         proc->err = NULL;
200         return APR_INCHILD;
201     }
202     proc->pid = pid;
203     proc->in = NULL;
204     proc->out = NULL;
205     proc->err = NULL;
206     return APR_INPARENT;
207 }
208 #endif
209 
limit_proc(apr_procattr_t * attr)210 static apr_status_t limit_proc(apr_procattr_t *attr)
211 {
212 #if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT
213 #ifdef RLIMIT_CPU
214     if (attr->limit_cpu != NULL) {
215         if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) {
216             return errno;
217         }
218     }
219 #endif
220 #ifdef RLIMIT_NPROC
221     if (attr->limit_nproc != NULL) {
222         if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) {
223             return errno;
224         }
225     }
226 #endif
227 #if defined(RLIMIT_AS)
228     if (attr->limit_mem != NULL) {
229         if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) {
230             return errno;
231         }
232     }
233 #elif defined(RLIMIT_DATA)
234     if (attr->limit_mem != NULL) {
235         if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) {
236             return errno;
237         }
238     }
239 #elif defined(RLIMIT_VMEM)
240     if (attr->limit_mem != NULL) {
241         if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) {
242             return errno;
243         }
244     }
245 #endif
246 #else
247     /*
248      * Maybe make a note in error_log that setrlimit isn't supported??
249      */
250 
251 #endif
252     return APR_SUCCESS;
253 }
254 
apr_procattr_child_errfn_set(apr_procattr_t * attr,apr_child_errfn_t * errfn)255 APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
256                                                        apr_child_errfn_t *errfn)
257 {
258     /* won't ever be called on this platform, so don't save the function pointer */
259     return APR_SUCCESS;
260 }
261 
apr_procattr_error_check_set(apr_procattr_t * attr,apr_int32_t chk)262 APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
263                                                        apr_int32_t chk)
264 {
265     /* won't ever be used on this platform, so don't save the flag */
266     return APR_SUCCESS;
267 }
268 
apr_procattr_addrspace_set(apr_procattr_t * attr,apr_int32_t addrspace)269 APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
270                                                        apr_int32_t addrspace)
271 {
272     attr->addrspace = addrspace;
273     return APR_SUCCESS;
274 }
275 
apr_proc_create(apr_proc_t * newproc,const char * progname,const char * const * args,const char * const * env,apr_procattr_t * attr,apr_pool_t * pool)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,
281                               		apr_pool_t *pool)
282 {
283 	wiring_t		wire;
284     int             addr_space;
285 
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;
289 
290     newproc->in = attr->parent_in;
291     newproc->out = attr->parent_out;
292     newproc->err = attr->parent_err;
293 
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);
299 
300     if (attr->currdir) {
301         char *fullpath = NULL;
302         apr_status_t rv;
303 
304         if ((rv = apr_filepath_merge(&fullpath, attr->currdir, progname,
305                                      APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) {
306             return rv;
307         }
308         progname = fullpath;
309     }
310 
311     if ((newproc->pid = procve(progname, addr_space, (const char**)env, &wire,
312         NULL, NULL, 0, NULL, (const char **)args)) == -1) {
313         return errno;
314     }
315 
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);
320     }
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);
325     }
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);
330     }
331 
332 
333     apr_pool_cleanup_register(pool, (void *)newproc, apr_netware_proc_cleanup,
334         apr_pool_cleanup_null);
335 
336     return APR_SUCCESS;
337 }
338 
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)339 APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
340                                                   int *exitcode,
341                                                   apr_exit_why_e *exitwhy,
342                                                   apr_wait_how_e waithow,
343                                                   apr_pool_t *p)
344 {
345     proc->pid = -1;
346     return apr_proc_wait(proc, exitcode, exitwhy, waithow);
347 }
348 
apr_proc_wait(apr_proc_t * proc,int * exitcode,apr_exit_why_e * exitwhy,apr_wait_how_e 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)
352 {
353     pid_t pstatus;
354     int waitpid_options = WUNTRACED;
355     int exit_int;
356     int ignore;
357     apr_exit_why_e ignorewhy;
358 
359     if (exitcode == NULL) {
360         exitcode = &ignore;
361     }
362 
363     if (exitwhy == NULL) {
364         exitwhy = &ignorewhy;
365     }
366 
367     if (waithow != APR_WAIT) {
368         waitpid_options |= WNOHANG;
369     }
370 
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
378        thread hanging. */
379     if (proc->pid == 0) {
380         *exitwhy = APR_PROC_EXIT;
381         *exitcode = 0;
382         return APR_CHILD_DONE;
383     }
384 
385     if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) {
386         proc->pid = pstatus;
387 
388         if (WIFEXITED(exit_int)) {
389             *exitwhy = APR_PROC_EXIT;
390             *exitcode = WEXITSTATUS(exit_int);
391         }
392         else if (WIFSIGNALED(exit_int)) {
393             *exitwhy = APR_PROC_SIGNAL;
394             *exitcode = WIFTERMSIG(exit_int);
395         }
396         else {
397             /* unexpected condition */
398             return APR_EGENERAL;
399         }
400 
401         return APR_CHILD_DONE;
402     }
403     else if (pstatus == 0) {
404         return APR_CHILD_NOTDONE;
405     }
406 
407     return errno;
408 }
409 
apr_procattr_limit_set(apr_procattr_t * attr,apr_int32_t what,struct rlimit * limit)410 APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, apr_int32_t what,
411                           struct rlimit *limit)
412 {
413     switch(what) {
414         case APR_LIMIT_CPU:
415 #ifdef RLIMIT_CPU
416             attr->limit_cpu = limit;
417             break;
418 #else
419             return APR_ENOTIMPL;
420 #endif
421         case APR_LIMIT_MEM:
422 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
423             attr->limit_mem = limit;
424             break;
425 #else
426             return APR_ENOTIMPL;
427 #endif
428         case APR_LIMIT_NPROC:
429 #ifdef RLIMIT_NPROC
430             attr->limit_nproc = limit;
431             break;
432 #else
433             return APR_ENOTIMPL;
434 #endif
435     }
436     return APR_SUCCESS;
437 }
438 
apr_procattr_user_set(apr_procattr_t * attr,const char * username,const char * password)439 APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr,
440                                                 const char *username,
441                                                 const char *password)
442 {
443     /* Always return SUCCESS because NetWare threads don't run as a user */
444     return APR_SUCCESS;
445 }
446 
apr_procattr_group_set(apr_procattr_t * attr,const char * groupname)447 APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr,
448                                                  const char *groupname)
449 {
450     /* Always return SUCCESS because NetWare threads don't run within a group */
451     return APR_SUCCESS;
452 }
453