1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr_arch_threadproc.h" 18251875Speter#include "apr_strings.h" 19251875Speter#include "apr_portable.h" 20251875Speter#include "apr_signal.h" 21251875Speter#include "apr_random.h" 22251875Speter 23251875Speter/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE 24251875Speter * requested for a specific child handle; 25251875Speter */ 26251875Speterstatic apr_file_t no_file = { NULL, -1, }; 27251875Speter 28251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, 29251875Speter apr_pool_t *pool) 30251875Speter{ 31251875Speter (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t)); 32251875Speter 33251875Speter if ((*new) == NULL) { 34251875Speter return APR_ENOMEM; 35251875Speter } 36251875Speter (*new)->pool = pool; 37251875Speter (*new)->cmdtype = APR_PROGRAM; 38251875Speter (*new)->uid = (*new)->gid = -1; 39251875Speter return APR_SUCCESS; 40251875Speter} 41251875Speter 42251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, 43251875Speter apr_int32_t in, 44251875Speter apr_int32_t out, 45251875Speter apr_int32_t err) 46251875Speter{ 47251875Speter apr_status_t rv; 48251875Speter 49251875Speter if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) { 50251875Speter /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while 51251875Speter * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose 52251875Speter * the CHILD/PARENT blocking flags for the stdin pipe. 53251875Speter * stdout/stderr map to the correct mode by default. 54251875Speter */ 55251875Speter if (in == APR_CHILD_BLOCK) 56251875Speter in = APR_READ_BLOCK; 57251875Speter else if (in == APR_PARENT_BLOCK) 58251875Speter in = APR_WRITE_BLOCK; 59251875Speter 60251875Speter if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, 61251875Speter in, attr->pool)) == APR_SUCCESS) 62251875Speter rv = apr_file_inherit_unset(attr->parent_in); 63251875Speter if (rv != APR_SUCCESS) 64251875Speter return rv; 65251875Speter } 66251875Speter else if (in == APR_NO_FILE) 67251875Speter attr->child_in = &no_file; 68251875Speter 69251875Speter if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) { 70251875Speter if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, 71251875Speter out, attr->pool)) == APR_SUCCESS) 72251875Speter rv = apr_file_inherit_unset(attr->parent_out); 73251875Speter if (rv != APR_SUCCESS) 74251875Speter return rv; 75251875Speter } 76251875Speter else if (out == APR_NO_FILE) 77251875Speter attr->child_out = &no_file; 78251875Speter 79251875Speter if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) { 80251875Speter if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, 81251875Speter err, attr->pool)) == APR_SUCCESS) 82251875Speter rv = apr_file_inherit_unset(attr->parent_err); 83251875Speter if (rv != APR_SUCCESS) 84251875Speter return rv; 85251875Speter } 86251875Speter else if (err == APR_NO_FILE) 87251875Speter attr->child_err = &no_file; 88251875Speter 89251875Speter return APR_SUCCESS; 90251875Speter} 91251875Speter 92251875Speter 93251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, 94251875Speter apr_file_t *child_in, 95251875Speter apr_file_t *parent_in) 96251875Speter{ 97251875Speter apr_status_t rv = APR_SUCCESS; 98251875Speter 99251875Speter if (attr->child_in == NULL && attr->parent_in == NULL 100251875Speter && child_in == NULL && parent_in == NULL) 101251875Speter if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in, 102251875Speter attr->pool)) == APR_SUCCESS) 103251875Speter rv = apr_file_inherit_unset(attr->parent_in); 104251875Speter 105251875Speter if (child_in != NULL && rv == APR_SUCCESS) { 106251875Speter if (attr->child_in && (attr->child_in->filedes != -1)) 107251875Speter rv = apr_file_dup2(attr->child_in, child_in, attr->pool); 108251875Speter else { 109251875Speter attr->child_in = NULL; 110251875Speter if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool)) 111251875Speter == APR_SUCCESS) 112251875Speter rv = apr_file_inherit_set(attr->child_in); 113251875Speter } 114251875Speter } 115251875Speter 116251875Speter if (parent_in != NULL && rv == APR_SUCCESS) { 117251875Speter if (attr->parent_in) 118251875Speter rv = apr_file_dup2(attr->parent_in, parent_in, attr->pool); 119251875Speter else 120251875Speter rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool); 121251875Speter } 122251875Speter 123251875Speter return rv; 124251875Speter} 125251875Speter 126251875Speter 127251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, 128251875Speter apr_file_t *child_out, 129251875Speter apr_file_t *parent_out) 130251875Speter{ 131251875Speter apr_status_t rv = APR_SUCCESS; 132251875Speter 133251875Speter if (attr->child_out == NULL && attr->parent_out == NULL 134251875Speter && child_out == NULL && parent_out == NULL) 135251875Speter if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out, 136251875Speter attr->pool)) == APR_SUCCESS) 137251875Speter rv = apr_file_inherit_unset(attr->parent_out); 138251875Speter 139251875Speter if (child_out != NULL && rv == APR_SUCCESS) { 140251875Speter if (attr->child_out && (attr->child_out->filedes != -1)) 141251875Speter rv = apr_file_dup2(attr->child_out, child_out, attr->pool); 142251875Speter else { 143251875Speter attr->child_out = NULL; 144251875Speter if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool)) 145251875Speter == APR_SUCCESS) 146251875Speter rv = apr_file_inherit_set(attr->child_out); 147251875Speter } 148251875Speter } 149251875Speter 150251875Speter if (parent_out != NULL && rv == APR_SUCCESS) { 151251875Speter if (attr->parent_out) 152251875Speter rv = apr_file_dup2(attr->parent_out, parent_out, attr->pool); 153251875Speter else 154251875Speter rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool); 155251875Speter } 156251875Speter 157251875Speter return rv; 158251875Speter} 159251875Speter 160251875Speter 161251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, 162251875Speter apr_file_t *child_err, 163251875Speter apr_file_t *parent_err) 164251875Speter{ 165251875Speter apr_status_t rv = APR_SUCCESS; 166251875Speter 167251875Speter if (attr->child_err == NULL && attr->parent_err == NULL 168251875Speter && child_err == NULL && parent_err == NULL) 169251875Speter if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err, 170251875Speter attr->pool)) == APR_SUCCESS) 171251875Speter rv = apr_file_inherit_unset(attr->parent_err); 172251875Speter 173251875Speter if (child_err != NULL && rv == APR_SUCCESS) { 174251875Speter if (attr->child_err && (attr->child_err->filedes != -1)) 175251875Speter rv = apr_file_dup2(attr->child_err, child_err, attr->pool); 176251875Speter else { 177251875Speter attr->child_err = NULL; 178251875Speter if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool)) 179251875Speter == APR_SUCCESS) 180251875Speter rv = apr_file_inherit_set(attr->child_err); 181251875Speter } 182251875Speter } 183251875Speter if (parent_err != NULL && rv == APR_SUCCESS) { 184251875Speter if (attr->parent_err) 185251875Speter rv = apr_file_dup2(attr->parent_err, parent_err, attr->pool); 186251875Speter else 187251875Speter rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool); 188251875Speter } 189251875Speter 190251875Speter return rv; 191251875Speter} 192251875Speter 193251875Speter 194251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, 195251875Speter const char *dir) 196251875Speter{ 197251875Speter attr->currdir = apr_pstrdup(attr->pool, dir); 198251875Speter if (attr->currdir) { 199251875Speter return APR_SUCCESS; 200251875Speter } 201251875Speter 202251875Speter return APR_ENOMEM; 203251875Speter} 204251875Speter 205251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, 206251875Speter apr_cmdtype_e cmd) 207251875Speter{ 208251875Speter attr->cmdtype = cmd; 209251875Speter return APR_SUCCESS; 210251875Speter} 211251875Speter 212251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, 213251875Speter apr_int32_t detach) 214251875Speter{ 215251875Speter attr->detached = detach; 216251875Speter return APR_SUCCESS; 217251875Speter} 218251875Speter 219251875SpeterAPR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) 220251875Speter{ 221251875Speter int pid; 222251875Speter 223251875Speter memset(proc, 0, sizeof(apr_proc_t)); 224251875Speter 225251875Speter if ((pid = fork()) < 0) { 226251875Speter return errno; 227251875Speter } 228251875Speter else if (pid == 0) { 229251875Speter proc->pid = getpid(); 230251875Speter 231251875Speter apr_random_after_fork(proc); 232251875Speter 233251875Speter return APR_INCHILD; 234251875Speter } 235251875Speter 236251875Speter proc->pid = pid; 237251875Speter 238251875Speter return APR_INPARENT; 239251875Speter} 240251875Speter 241251875Speterstatic apr_status_t limit_proc(apr_procattr_t *attr) 242251875Speter{ 243251875Speter#if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT 244251875Speter#ifdef RLIMIT_CPU 245251875Speter if (attr->limit_cpu != NULL) { 246251875Speter if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) { 247251875Speter return errno; 248251875Speter } 249251875Speter } 250251875Speter#endif 251251875Speter#ifdef RLIMIT_NPROC 252251875Speter if (attr->limit_nproc != NULL) { 253251875Speter if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) { 254251875Speter return errno; 255251875Speter } 256251875Speter } 257251875Speter#endif 258251875Speter#ifdef RLIMIT_NOFILE 259251875Speter if (attr->limit_nofile != NULL) { 260251875Speter if ((setrlimit(RLIMIT_NOFILE, attr->limit_nofile)) != 0) { 261251875Speter return errno; 262251875Speter } 263251875Speter } 264251875Speter#endif 265251875Speter#if defined(RLIMIT_AS) 266251875Speter if (attr->limit_mem != NULL) { 267251875Speter if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) { 268251875Speter return errno; 269251875Speter } 270251875Speter } 271251875Speter#elif defined(RLIMIT_DATA) 272251875Speter if (attr->limit_mem != NULL) { 273251875Speter if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) { 274251875Speter return errno; 275251875Speter } 276251875Speter } 277251875Speter#elif defined(RLIMIT_VMEM) 278251875Speter if (attr->limit_mem != NULL) { 279251875Speter if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) { 280251875Speter return errno; 281251875Speter } 282251875Speter } 283251875Speter#endif 284251875Speter#else 285251875Speter /* 286251875Speter * Maybe make a note in error_log that setrlimit isn't supported?? 287251875Speter */ 288251875Speter 289251875Speter#endif 290251875Speter return APR_SUCCESS; 291251875Speter} 292251875Speter 293251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, 294251875Speter apr_child_errfn_t *errfn) 295251875Speter{ 296251875Speter attr->errfn = errfn; 297251875Speter return APR_SUCCESS; 298251875Speter} 299251875Speter 300251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, 301251875Speter apr_int32_t chk) 302251875Speter{ 303251875Speter attr->errchk = chk; 304251875Speter return APR_SUCCESS; 305251875Speter} 306251875Speter 307251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, 308251875Speter apr_int32_t addrspace) 309251875Speter{ 310251875Speter /* won't ever be used on this platform, so don't save the flag */ 311251875Speter return APR_SUCCESS; 312251875Speter} 313251875Speter 314251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, 315251875Speter const char *username, 316251875Speter const char *password) 317251875Speter{ 318251875Speter apr_status_t rv; 319251875Speter apr_gid_t gid; 320251875Speter 321251875Speter if ((rv = apr_uid_get(&attr->uid, &gid, username, 322251875Speter attr->pool)) != APR_SUCCESS) { 323251875Speter attr->uid = -1; 324251875Speter return rv; 325251875Speter } 326251875Speter 327251875Speter /* Use default user group if not already set */ 328251875Speter if (attr->gid == -1) { 329251875Speter attr->gid = gid; 330251875Speter } 331251875Speter return APR_SUCCESS; 332251875Speter} 333251875Speter 334251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, 335251875Speter const char *groupname) 336251875Speter{ 337251875Speter apr_status_t rv; 338251875Speter 339251875Speter if ((rv = apr_gid_get(&attr->gid, groupname, attr->pool)) != APR_SUCCESS) 340251875Speter attr->gid = -1; 341251875Speter return rv; 342251875Speter} 343251875Speter 344251875SpeterAPR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, 345251875Speter const char *progname, 346251875Speter const char * const *args, 347251875Speter const char * const *env, 348251875Speter apr_procattr_t *attr, 349251875Speter apr_pool_t *pool) 350251875Speter{ 351251875Speter int i; 352251875Speter const char * const empty_envp[] = {NULL}; 353251875Speter 354251875Speter if (!env) { /* Specs require an empty array instead of NULL; 355251875Speter * Purify will trigger a failure, even if many 356251875Speter * implementations don't. 357251875Speter */ 358251875Speter env = empty_envp; 359251875Speter } 360251875Speter 361251875Speter new->in = attr->parent_in; 362251875Speter new->err = attr->parent_err; 363251875Speter new->out = attr->parent_out; 364251875Speter 365251875Speter if (attr->errchk) { 366251875Speter if (attr->currdir) { 367251875Speter if (access(attr->currdir, X_OK) == -1) { 368251875Speter /* chdir() in child wouldn't have worked */ 369251875Speter return errno; 370251875Speter } 371251875Speter } 372251875Speter 373251875Speter if (attr->cmdtype == APR_PROGRAM || 374251875Speter attr->cmdtype == APR_PROGRAM_ENV || 375251875Speter *progname == '/') { 376251875Speter /* for both of these values of cmdtype, caller must pass 377251875Speter * full path, so it is easy to check; 378251875Speter * caller can choose to pass full path for other 379251875Speter * values of cmdtype 380251875Speter */ 381251875Speter if (access(progname, X_OK) == -1) { 382251875Speter /* exec*() in child wouldn't have worked */ 383251875Speter return errno; 384251875Speter } 385251875Speter } 386251875Speter else { 387251875Speter /* todo: search PATH for progname then try to access it */ 388251875Speter } 389251875Speter } 390251875Speter 391251875Speter if ((new->pid = fork()) < 0) { 392251875Speter return errno; 393251875Speter } 394251875Speter else if (new->pid == 0) { 395251875Speter /* child process */ 396251875Speter 397251875Speter /* 398251875Speter * If we do exec cleanup before the dup2() calls to set up pipes 399251875Speter * on 0-2, we accidentally close the pipes used by programs like 400251875Speter * mod_cgid. 401251875Speter * 402251875Speter * If we do exec cleanup after the dup2() calls, cleanup can accidentally 403251875Speter * close our pipes which replaced any files which previously had 404251875Speter * descriptors 0-2. 405251875Speter * 406251875Speter * The solution is to kill the cleanup for the pipes, then do 407251875Speter * exec cleanup, then do the dup2() calls. 408251875Speter */ 409251875Speter 410251875Speter if (attr->child_in) { 411251875Speter apr_pool_cleanup_kill(apr_file_pool_get(attr->child_in), 412251875Speter attr->child_in, apr_unix_file_cleanup); 413251875Speter } 414251875Speter 415251875Speter if (attr->child_out) { 416251875Speter apr_pool_cleanup_kill(apr_file_pool_get(attr->child_out), 417251875Speter attr->child_out, apr_unix_file_cleanup); 418251875Speter } 419251875Speter 420251875Speter if (attr->child_err) { 421251875Speter apr_pool_cleanup_kill(apr_file_pool_get(attr->child_err), 422251875Speter attr->child_err, apr_unix_file_cleanup); 423251875Speter } 424251875Speter 425251875Speter apr_pool_cleanup_for_exec(); 426251875Speter 427251875Speter if ((attr->child_in) && (attr->child_in->filedes == -1)) { 428251875Speter close(STDIN_FILENO); 429251875Speter } 430251875Speter else if (attr->child_in && 431251875Speter attr->child_in->filedes != STDIN_FILENO) { 432251875Speter dup2(attr->child_in->filedes, STDIN_FILENO); 433251875Speter apr_file_close(attr->child_in); 434251875Speter } 435251875Speter 436251875Speter if ((attr->child_out) && (attr->child_out->filedes == -1)) { 437251875Speter close(STDOUT_FILENO); 438251875Speter } 439251875Speter else if (attr->child_out && 440251875Speter attr->child_out->filedes != STDOUT_FILENO) { 441251875Speter dup2(attr->child_out->filedes, STDOUT_FILENO); 442251875Speter apr_file_close(attr->child_out); 443251875Speter } 444251875Speter 445251875Speter if ((attr->child_err) && (attr->child_err->filedes == -1)) { 446251875Speter close(STDERR_FILENO); 447251875Speter } 448251875Speter else if (attr->child_err && 449251875Speter attr->child_err->filedes != STDERR_FILENO) { 450251875Speter dup2(attr->child_err->filedes, STDERR_FILENO); 451251875Speter apr_file_close(attr->child_err); 452251875Speter } 453251875Speter 454251875Speter apr_signal(SIGCHLD, SIG_DFL); /* not sure if this is needed or not */ 455251875Speter 456251875Speter if (attr->currdir != NULL) { 457251875Speter if (chdir(attr->currdir) == -1) { 458251875Speter if (attr->errfn) { 459251875Speter attr->errfn(pool, errno, "change of working directory failed"); 460251875Speter } 461251875Speter _exit(-1); /* We have big problems, the child should exit. */ 462251875Speter } 463251875Speter } 464251875Speter 465251875Speter /* Only try to switch if we are running as root */ 466251875Speter if (attr->gid != -1 && !geteuid()) { 467251875Speter if (setgid(attr->gid)) { 468251875Speter if (attr->errfn) { 469251875Speter attr->errfn(pool, errno, "setting of group failed"); 470251875Speter } 471251875Speter _exit(-1); /* We have big problems, the child should exit. */ 472251875Speter } 473251875Speter } 474251875Speter 475251875Speter if (attr->uid != -1 && !geteuid()) { 476251875Speter if (setuid(attr->uid)) { 477251875Speter if (attr->errfn) { 478251875Speter attr->errfn(pool, errno, "setting of user failed"); 479251875Speter } 480251875Speter _exit(-1); /* We have big problems, the child should exit. */ 481251875Speter } 482251875Speter } 483251875Speter 484251875Speter if (limit_proc(attr) != APR_SUCCESS) { 485251875Speter if (attr->errfn) { 486251875Speter attr->errfn(pool, errno, "setting of resource limits failed"); 487251875Speter } 488251875Speter _exit(-1); /* We have big problems, the child should exit. */ 489251875Speter } 490251875Speter 491251875Speter if (attr->cmdtype == APR_SHELLCMD || 492251875Speter attr->cmdtype == APR_SHELLCMD_ENV) { 493251875Speter int onearg_len = 0; 494251875Speter const char *newargs[4]; 495251875Speter 496251875Speter newargs[0] = SHELL_PATH; 497251875Speter newargs[1] = "-c"; 498251875Speter 499251875Speter i = 0; 500251875Speter while (args[i]) { 501251875Speter onearg_len += strlen(args[i]); 502251875Speter onearg_len++; /* for space delimiter */ 503251875Speter i++; 504251875Speter } 505251875Speter 506251875Speter switch(i) { 507251875Speter case 0: 508251875Speter /* bad parameters; we're doomed */ 509251875Speter break; 510251875Speter case 1: 511251875Speter /* no args, or caller already built a single string from 512251875Speter * progname and args 513251875Speter */ 514251875Speter newargs[2] = args[0]; 515251875Speter break; 516251875Speter default: 517251875Speter { 518251875Speter char *ch, *onearg; 519251875Speter 520251875Speter ch = onearg = apr_palloc(pool, onearg_len); 521251875Speter i = 0; 522251875Speter while (args[i]) { 523251875Speter size_t len = strlen(args[i]); 524251875Speter 525251875Speter memcpy(ch, args[i], len); 526251875Speter ch += len; 527251875Speter *ch = ' '; 528251875Speter ++ch; 529251875Speter ++i; 530251875Speter } 531251875Speter --ch; /* back up to trailing blank */ 532251875Speter *ch = '\0'; 533251875Speter newargs[2] = onearg; 534251875Speter } 535251875Speter } 536251875Speter 537251875Speter newargs[3] = NULL; 538251875Speter 539251875Speter if (attr->detached) { 540251875Speter apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); 541251875Speter } 542251875Speter 543251875Speter if (attr->cmdtype == APR_SHELLCMD) { 544251875Speter execve(SHELL_PATH, (char * const *) newargs, (char * const *)env); 545251875Speter } 546251875Speter else { 547251875Speter execv(SHELL_PATH, (char * const *)newargs); 548251875Speter } 549251875Speter } 550251875Speter else if (attr->cmdtype == APR_PROGRAM) { 551251875Speter if (attr->detached) { 552251875Speter apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); 553251875Speter } 554251875Speter 555251875Speter execve(progname, (char * const *)args, (char * const *)env); 556251875Speter } 557251875Speter else if (attr->cmdtype == APR_PROGRAM_ENV) { 558251875Speter if (attr->detached) { 559251875Speter apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); 560251875Speter } 561251875Speter 562251875Speter execv(progname, (char * const *)args); 563251875Speter } 564251875Speter else { 565251875Speter /* APR_PROGRAM_PATH */ 566251875Speter if (attr->detached) { 567251875Speter apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); 568251875Speter } 569251875Speter 570251875Speter execvp(progname, (char * const *)args); 571251875Speter } 572251875Speter if (attr->errfn) { 573251875Speter char *desc; 574251875Speter 575251875Speter desc = apr_psprintf(pool, "exec of '%s' failed", 576251875Speter progname); 577251875Speter attr->errfn(pool, errno, desc); 578251875Speter } 579251875Speter 580251875Speter _exit(-1); /* if we get here, there is a problem, so exit with an 581251875Speter * error code. */ 582251875Speter } 583251875Speter 584251875Speter /* Parent process */ 585251875Speter if (attr->child_in && (attr->child_in->filedes != -1)) { 586251875Speter apr_file_close(attr->child_in); 587251875Speter } 588251875Speter 589251875Speter if (attr->child_out && (attr->child_out->filedes != -1)) { 590251875Speter apr_file_close(attr->child_out); 591251875Speter } 592251875Speter 593251875Speter if (attr->child_err && (attr->child_err->filedes != -1)) { 594251875Speter apr_file_close(attr->child_err); 595251875Speter } 596251875Speter 597251875Speter return APR_SUCCESS; 598251875Speter} 599251875Speter 600251875SpeterAPR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, 601251875Speter int *exitcode, 602251875Speter apr_exit_why_e *exitwhy, 603251875Speter apr_wait_how_e waithow, 604251875Speter apr_pool_t *p) 605251875Speter{ 606251875Speter proc->pid = -1; 607251875Speter return apr_proc_wait(proc, exitcode, exitwhy, waithow); 608251875Speter} 609251875Speter 610251875SpeterAPR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, 611251875Speter int *exitcode, apr_exit_why_e *exitwhy, 612251875Speter apr_wait_how_e waithow) 613251875Speter{ 614251875Speter pid_t pstatus; 615251875Speter int waitpid_options = WUNTRACED; 616251875Speter int exit_int; 617251875Speter int ignore; 618251875Speter apr_exit_why_e ignorewhy; 619251875Speter 620251875Speter if (exitcode == NULL) { 621251875Speter exitcode = &ignore; 622251875Speter } 623251875Speter 624251875Speter if (exitwhy == NULL) { 625251875Speter exitwhy = &ignorewhy; 626251875Speter } 627251875Speter 628251875Speter if (waithow != APR_WAIT) { 629251875Speter waitpid_options |= WNOHANG; 630251875Speter } 631251875Speter 632251875Speter do { 633251875Speter pstatus = waitpid(proc->pid, &exit_int, waitpid_options); 634251875Speter } while (pstatus < 0 && errno == EINTR); 635251875Speter 636251875Speter if (pstatus > 0) { 637251875Speter proc->pid = pstatus; 638251875Speter 639251875Speter if (WIFEXITED(exit_int)) { 640251875Speter *exitwhy = APR_PROC_EXIT; 641251875Speter *exitcode = WEXITSTATUS(exit_int); 642251875Speter } 643251875Speter else if (WIFSIGNALED(exit_int)) { 644251875Speter *exitwhy = APR_PROC_SIGNAL; 645251875Speter 646251875Speter#ifdef WCOREDUMP 647251875Speter if (WCOREDUMP(exit_int)) { 648251875Speter *exitwhy |= APR_PROC_SIGNAL_CORE; 649251875Speter } 650251875Speter#endif 651251875Speter 652251875Speter *exitcode = WTERMSIG(exit_int); 653251875Speter } 654251875Speter else { 655251875Speter /* unexpected condition */ 656251875Speter return APR_EGENERAL; 657251875Speter } 658251875Speter 659251875Speter return APR_CHILD_DONE; 660251875Speter } 661251875Speter else if (pstatus == 0) { 662251875Speter return APR_CHILD_NOTDONE; 663251875Speter } 664251875Speter 665251875Speter return errno; 666251875Speter} 667251875Speter 668251875Speter#if APR_HAVE_STRUCT_RLIMIT 669251875SpeterAPR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, 670251875Speter apr_int32_t what, 671251875Speter struct rlimit *limit) 672251875Speter{ 673251875Speter switch(what) { 674251875Speter case APR_LIMIT_CPU: 675251875Speter#ifdef RLIMIT_CPU 676251875Speter attr->limit_cpu = limit; 677251875Speter break; 678251875Speter#else 679251875Speter return APR_ENOTIMPL; 680251875Speter#endif 681251875Speter 682251875Speter case APR_LIMIT_MEM: 683251875Speter#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) 684251875Speter attr->limit_mem = limit; 685251875Speter break; 686251875Speter#else 687251875Speter return APR_ENOTIMPL; 688251875Speter#endif 689251875Speter 690251875Speter case APR_LIMIT_NPROC: 691251875Speter#ifdef RLIMIT_NPROC 692251875Speter attr->limit_nproc = limit; 693251875Speter break; 694251875Speter#else 695251875Speter return APR_ENOTIMPL; 696251875Speter#endif 697251875Speter 698251875Speter case APR_LIMIT_NOFILE: 699251875Speter#ifdef RLIMIT_NOFILE 700251875Speter attr->limit_nofile = limit; 701251875Speter break; 702251875Speter#else 703251875Speter return APR_ENOTIMPL; 704251875Speter#endif 705251875Speter 706251875Speter } 707251875Speter 708251875Speter return APR_SUCCESS; 709251875Speter} 710251875Speter#endif /* APR_HAVE_STRUCT_RLIMIT */ 711251875Speter 712