AP_DECLARE(void) ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret, apr_pool_t *p, server_rec *s) { apr_status_t rv; ++wait_or_timeout_counter; if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) { wait_or_timeout_counter = 0; ap_run_monitor(p, s); } rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p); ap_update_global_status(); if (APR_STATUS_IS_EINTR(rv)) { ret->pid = -1; return; } if (APR_STATUS_IS_CHILD_DONE(rv)) { return; } apr_sleep(apr_time_from_sec(1)); ret->pid = -1; }
static int proc_wait(lua_State *L) { apr_status_t status; apr_exit_why_e why; apr_wait_how_e how; lua_apr_proc *process; int code; process = proc_check(L, 1); how = lua_toboolean(L, 2) ? APR_WAIT : APR_NOWAIT; status = apr_proc_wait(&process->handle, &code, &why, how); if (APR_STATUS_IS_CHILD_NOTDONE(status)) return (lua_pushboolean(L, 0), 1); else if (!APR_STATUS_IS_CHILD_DONE(status)) return push_error_status(L, status); else lua_pushboolean(L, 1); switch (why) { default: case APR_PROC_EXIT: lua_pushliteral(L, "exit"); break; case APR_PROC_SIGNAL: lua_pushliteral(L, "signal"); break; case APR_PROC_SIGNAL_CORE: lua_pushliteral(L, "signal/core"); break; } lua_pushinteger(L, code); return 3; }
void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret, apr_pool_t *p) { apr_status_t rv; ++wait_or_timeout_counter; if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) { wait_or_timeout_counter = 0; ap_run_monitor(p); } rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p); if (APR_STATUS_IS_EINTR(rv)) { ret->pid = -1; return; } if (APR_STATUS_IS_CHILD_DONE(rv)) { return; } #ifdef NEED_WAITPID if ((ret = reap_children(exitcode, status)) > 0) { return; } #endif apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL); ret->pid = -1; return; }
static apr_status_t fortune_process(conn_rec *c, apr_procattr_t *pattr, apr_bucket_brigade *bb) { apr_status_t rv; int argc = 0; const char *argv[APP_MAX_ARGC]; apr_proc_t proc; apr_bucket *b; apr_pool_t *p = c->pool; fortune_conf_t *fconf = ap_get_module_config(c->base_server->module_config, &fortune_module); argv[argc++] = fconf->progname; argv[argc++] = NULL; /* @argvs should be null-terminated */ if ((rv = apr_proc_create(&proc, fconf->progname, (const char *const *) argv, NULL, (apr_procattr_t *) pattr, p)) != APR_SUCCESS) { return rv; } while (TRUE) { char buf[BUFSIZE] = { 0, }; /* read the command's output through the pipe */ rv = apr_file_gets(buf, sizeof(buf), proc.out); if (APR_STATUS_IS_EOF(rv)) { break; } b = apr_bucket_pool_create(apr_pstrdup(p, buf), strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); } apr_file_close(proc.out); { int st; apr_exit_why_e why; rv = apr_proc_wait(&proc, &st, &why, APR_WAIT); if (APR_STATUS_IS_CHILD_DONE(rv)) { ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "child done: why = %d, exit status = %d", why, st); } else { ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "child notdone"); return APR_EGENERAL; } } return APR_SUCCESS; }
/* This is needed to reap processes spawned by exec_async() */ static void xm_exec_reap(nx_module_t *module) { nx_xm_exec_conf_t *imconf; nx_event_t *event; apr_exit_why_e exitwhy; int exitval; apr_status_t rv; apr_proc_t proc; ASSERT(module->config != NULL); imconf = (nx_xm_exec_conf_t *) module->config; while ( APR_STATUS_IS_CHILD_DONE(rv = apr_proc_wait_all_procs(&proc, &exitval, &exitwhy, APR_NOWAIT, NULL)) ) { log_debug("process %d reaped by xm_exec_reap", proc.pid); if ( proc.pid > 0 ) { if ( exitwhy == APR_PROC_EXIT ) { //normal termination if ( exitval != 0 ) { log_error("subprocess '%d' returned a non-zero exit value of %d", proc.pid, exitval); } } else { log_error("subprocess '%d' was terminated by a signal", proc.pid); } } else { // on windows we get PID = -1 and it would result in an endless loop during exit break; } } event = nx_event_new(); event->module = module; event->type = NX_EVENT_MODULE_SPECIFIC; event->delayed = TRUE; event->time = apr_time_now() + APR_USEC_PER_SEC; event->priority = module->priority; nx_event_add(event); imconf->event = event; }
static void im_exec_stop(nx_module_t *module) { nx_im_exec_conf_t *imconf; int i; boolean sigterm_sent = FALSE; apr_exit_why_e exitwhy; int exitval; int sig_num; apr_status_t rv; apr_status_t stopped = APR_SUCCESS; ASSERT(module != NULL); imconf = (nx_im_exec_conf_t *) module->config; ASSERT(imconf != NULL); log_debug("im_exec stopped"); if ( module->input.desc.f != NULL ) { apr_file_close(module->input.desc.f); apr_pool_clear(module->input.pool); module->input.desc.f = NULL; } if ( imconf->running == TRUE ) { for ( i = 0; i < 50; i++ ) { if ( (rv = apr_proc_wait(&(imconf->proc), &exitval, &exitwhy, APR_NOWAIT)) != APR_SUCCESS ) { if ( APR_STATUS_IS_CHILD_DONE(rv) ) { rv = APR_SUCCESS; break; } else if ( i >= 30 ) { // still running, kill it after 3 sec if ( sigterm_sent == FALSE ) { sigterm_sent = TRUE; #ifdef WIN32 sig_num = 1; #else sig_num = SIGTERM; #endif } else { if ( i <= 31 ) { log_warn("process %s did not exit, killing it.", imconf->cmd); } #ifdef WIN32 sig_num = 1; #else sig_num = SIGKILL; #endif } if ( (rv = apr_proc_kill(&(imconf->proc), sig_num)) != APR_SUCCESS ) { stopped = rv; } } } apr_sleep(APR_USEC_PER_SEC / 10); } if ( !((stopped == APR_SUCCESS) || APR_STATUS_IS_ENOPROC(stopped)) ) { log_aprerror(stopped, "im_exec couldn't stop process"); } } imconf->event = NULL; }
static void im_exec_start(nx_module_t *module) { nx_im_exec_conf_t *imconf; apr_status_t rv; apr_procattr_t *pattr; apr_exit_why_e exitwhy; int exitval; ASSERT(module->config != NULL); imconf = (nx_im_exec_conf_t *) module->config; if ( module->input.desc.f == NULL ) { CHECKERR_MSG(apr_procattr_create(&pattr, module->input.pool), "apr_procattr_create() failed"); CHECKERR_MSG(apr_procattr_error_check_set(pattr, 1), "apr_procattr_error_check_set() failed"); #ifdef WIN32 CHECKERR_MSG(apr_procattr_io_set(pattr, APR_NO_PIPE, APR_FULL_NONBLOCK, APR_NO_PIPE), "apr_procattr_io_set() failed"); #else CHECKERR_MSG(apr_procattr_io_set(pattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE), "apr_procattr_io_set() failed"); #endif CHECKERR_MSG(apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV), "apr_procattr_cmdtype_set() failed"); CHECKERR_MSG(apr_proc_create(&(imconf->proc), imconf->cmd, (const char* const*)imconf->argv, NULL, (apr_procattr_t*)pattr, module->input.pool), "couldn't execute process %s", imconf->cmd); if ( (rv = apr_proc_wait(&(imconf->proc), &exitval, &exitwhy, APR_NOWAIT)) != APR_SUCCESS ) { if ( APR_STATUS_IS_CHILD_DONE(rv) ) { throw(rv, "im_exec process %s exited %s with exitval: %d", imconf->cmd, exitwhy == APR_PROC_EXIT ? "normally" : "due to a signal", exitval); } else { // still running OK } } log_debug("im_exec successfully spawned process"); imconf->running = TRUE; module->input.desc_type = APR_POLL_FILE; module->input.desc.f = imconf->proc.out; module->input.module = module; module->input.inputfunc = imconf->inputfunc; #ifdef WIN32 im_exec_add_read_event(module, 0); #else nx_module_pollset_add_file(module, module->input.desc.f, APR_POLLIN | APR_POLLHUP); #endif } else { log_debug("%s already executed", imconf->cmd); } #ifndef WIN32 nx_module_add_poll_event(module); #endif }
int main(void) { printf("hallo!\n"); apr_status_t rv; apr_pool_t *p = NULL; apr_proc_t newproc; rv = apr_initialize(); assert(rv == APR_SUCCESS); apr_pool_create(&p, NULL); // -- char cwd[1024]; assert(getcwd(cwd, 1024) != NULL); apr_procattr_t *attr = NULL; rv = apr_procattr_create(&attr, p); assert(rv == APR_SUCCESS); rv = apr_procattr_io_set(attr, APR_NO_PIPE, APR_NO_PIPE, APR_NO_PIPE); assert(rv == APR_SUCCESS); rv = apr_procattr_dir_set(attr, cwd); assert(rv == APR_SUCCESS); printf("cwd: %s\n", cwd); rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM_ENV ); assert(rv == APR_SUCCESS); /* pseudo code of args to apr_proc_create() */ int argc = 0; const char* argv[32]; /* 32 is a magic number. enough size for the number of arguments list */ argv[argc++] = "test.sh"; /* program path of the command to run */ /*argv[argc++] = "-i"; argv[argc++] = "foo"; argv[argc++] = "--longopt"; argv[argc++] = "bar";*/ argv[argc++] = NULL; rv = apr_proc_create(&newproc, "test.sh", argv, /* env */ NULL, attr, p); assert(rv == APR_SUCCESS); // int exitCode = 0; apr_exit_why_e exitWhy = 0; rv = apr_proc_wait(&newproc, &exitCode, &exitWhy, APR_WAIT); if (APR_STATUS_IS_CHILD_DONE(rv)) { printf("child done: why = %d, exit status = %d\n", exitWhy, exitCode); } else { printf("child notdone\n"); } /*assert(rv == APR_CHILD_DONE); assert(exitCode == 0); assert(exitWhy == APR_PROC_EXIT);*/ // -- apr_pool_destroy(p); apr_terminate(); return 0; }
/* Run an external authentication program using the given method for passing * in the data. The login name is always passed in. Dataname is "GROUP" or * "PASS" and data is the group list or password being checked. To launch * a detached daemon, run this with extmethod=NULL. * * If the authenticator was run, we return the numeric code from the * authenticator, normally 0 if the login was valid, some small positive * number if not. If we were not able to run the authenticator, we log * an error message and return a numeric error code: * * -1 Could not execute authenticator, usually a path or permission problem * -2 The external authenticator crashed or was killed. * -3 Could not create process attribute structure * -4 apr_proc_wait() did not return a status code. Should never happen. * -5 apr_proc_wait() returned before child finished. Should never happen. */ static int exec_external(const char *extpath, const char *extmethod, const request_rec *r, const char *dataname, const char *data) { conn_rec *c= r->connection; apr_pool_t *p= r->pool; int isdaemon, usecheck= 0, usepipeout= 0, usepipein= 0; apr_procattr_t *procattr; apr_proc_t proc; apr_status_t rc= APR_SUCCESS; char *child_env[12]; char *child_arg[MAX_ARG+2]; const char *t; int i, status= -4; apr_exit_why_e why= APR_PROC_EXIT; apr_sigfunc_t *sigchld; /* Set various flags based on the execution method */ isdaemon= (extmethod == NULL); if (!isdaemon) { usecheck= extmethod && !strcasecmp(extmethod, "checkpassword"); usepipeout= usecheck || (extmethod && !strcasecmp(extmethod, "pipes")); usepipein= usepipeout || (extmethod && !strcasecmp(extmethod, "pipe")); } /* Create the environment for the child. Daemons don't get these, they * just inherit apache's environment variables. */ if (!isdaemon) { const char *cookie, *host, *remote_host; authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *) ap_get_module_config(r->per_dir_config, &authnz_external_module); i= 0; if (!usepipein) { /* Put user name and password/group into environment */ child_env[i++]= apr_pstrcat(p, ENV_USER"=", r->user, NULL); child_env[i++]= apr_pstrcat(p, dataname, "=", data, NULL); } child_env[i++]= apr_pstrcat(p, "PATH=", getenv("PATH"), NULL); child_env[i++]= apr_pstrcat(p, "AUTHTYPE=", dataname, NULL); remote_host= ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST,NULL); if (remote_host != NULL) child_env[i++]= apr_pstrcat(p, ENV_HOST"=", remote_host,NULL); if (r->useragent_ip) child_env[i++]= apr_pstrcat(p, ENV_IP"=", r->useragent_ip, NULL); if (r->uri) child_env[i++]= apr_pstrcat(p, ENV_URI"=", r->uri, NULL); if ((host= apr_table_get(r->headers_in, "Host")) != NULL) child_env[i++]= apr_pstrcat(p, ENV_HTTP_HOST"=", host, NULL); if (dir->context) child_env[i++]= apr_pstrcat(r->pool, ENV_CONTEXT"=", dir->context, NULL); #ifdef ENV_COOKIE if ((cookie= apr_table_get(r->headers_in, "Cookie")) != NULL) child_env[i++]= apr_pstrcat(p, ENV_COOKIE"=", cookie, NULL); #endif /* NOTE: If you add environment variables, * remember to increase the size of the child_env[] array */ /* End of environment */ child_env[i]= NULL; } /* Construct argument array */ for (t= extpath, i=0; *t != '\0' && (i <= MAX_ARG + 1); child_arg[i++]= ap_getword_white(p, &t)) {} child_arg[i]= NULL; /* Create the process attribute structure describing the script we * want to run using the Thread/Process functions from the Apache * portable runtime library. */ if (((rc= apr_procattr_create(&procattr, p)) != APR_SUCCESS) || /* should we create pipes to stdin, stdout and stderr? */ ((rc= apr_procattr_io_set(procattr, (usepipein && !usecheck) ? APR_FULL_BLOCK : APR_NO_PIPE, usepipeout ? APR_FULL_BLOCK : APR_NO_PIPE, (usepipein && usecheck) ? APR_FULL_BLOCK : APR_NO_PIPE)) != APR_SUCCESS ) || /* will give full path of program and make a new environment */ ((rc= apr_procattr_cmdtype_set(procattr, isdaemon ? APR_PROGRAM_ENV : APR_PROGRAM)) != APR_SUCCESS) || /* detach the child only if it is a daemon */ ((rc= apr_procattr_detach_set(procattr, isdaemon)) != APR_SUCCESS) || /* function to call if child has error after fork, before exec */ ((rc= apr_procattr_child_errfn_set(procattr, extchilderr) != APR_SUCCESS))) { /* Failed. Probably never happens. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "could not set child process attributes"); return -3; } /* Sometimes other modules wil mess up sigchild. Need to fix it for * the wait call to work correctly. */ sigchld= apr_signal(SIGCHLD,SIG_DFL); /* Start the child process */ rc= apr_proc_create(&proc, child_arg[0], (const char * const *)child_arg, (const char * const *)child_env, procattr, p); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "Could not run external authenticator: %d: %s", rc, child_arg[0]); return -1; } if (isdaemon) return 0; apr_pool_note_subprocess(p, &proc, APR_KILL_AFTER_TIMEOUT); if (usepipein) { /* Select appropriate pipe to write to */ apr_file_t *pipe= (usecheck ? proc.err : proc.in); /* Send the user */ apr_file_write_full(pipe, r->user, strlen(r->user), NULL); apr_file_putc(usecheck ? '\0' : '\n', pipe); /* Send the password */ apr_file_write_full(pipe, data, strlen(data), NULL); apr_file_putc(usecheck ? '\0' : '\n', pipe); /* Send the uri/path */ apr_file_write_full(pipe, r->uri, strlen(r->uri), NULL); apr_file_putc(usecheck ? '\0' : '\n', pipe); /* Send dummy timestamp for checkpassword */ if (usecheck) apr_file_write_full(pipe, "0", 2, NULL); /* Close the file */ apr_file_close(pipe); } /* Wait for the child process to terminate, and get status */ rc= apr_proc_wait(&proc,&status,&why,APR_WAIT); /* Restore sigchild to whatever it was before we reset it */ apr_signal(SIGCHLD,sigchld); if (!APR_STATUS_IS_CHILD_DONE(rc)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "Could not get status from child process"); return -5; } if (!APR_PROC_CHECK_EXIT(why)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "External authenticator died on signal %d",status); return -2; } return status; }