/* Spawn the piped logger process pl->program. */ static apr_status_t piped_log_spawn(piped_log *pl) { apr_procattr_t *procattr; apr_proc_t *procnew = NULL; apr_status_t status; if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) || ((status = apr_procattr_cmdtype_set(procattr, pl->cmdtype)) != APR_SUCCESS) || ((status = apr_procattr_child_in_set(procattr, ap_piped_log_read_fd(pl), ap_piped_log_write_fd(pl))) != APR_SUCCESS) || ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn)) != APR_SUCCESS) || ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) { char buf[120]; /* Something bad happened, give up and go away. */ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "piped_log_spawn: unable to setup child process '%s': %s", pl->program, apr_strerror(status, buf, sizeof(buf))); } else { char **args; const char *pname; apr_file_t *outfile, *errfile; if ((status = apr_file_open_stdout(&outfile, pl->p)) == APR_SUCCESS) status = apr_procattr_child_out_set(procattr, outfile, NULL); if ((status = apr_file_open_stderr(&errfile, pl->p)) == APR_SUCCESS) status = apr_procattr_child_err_set(procattr, errfile, NULL); apr_tokenize_to_argv(pl->program, &args, pl->p); pname = apr_pstrdup(pl->p, args[0]); procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t)); status = apr_proc_create(procnew, pname, (const char * const *) args, NULL, procattr, pl->p); if (status == APR_SUCCESS) { pl->pid = procnew; /* procnew->in was dup2'd from ap_piped_log_write_fd(pl); * since the original fd is still valid, close the copy to * avoid a leak. */ apr_file_close(procnew->in); procnew->in = NULL; apr_proc_other_child_register(procnew, piped_log_maintenance, pl, ap_piped_log_write_fd(pl), pl->p); close_handle_in_child(pl->p, ap_piped_log_read_fd(pl)); } else { char buf[120]; /* Something bad happened, give up and go away. */ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "unable to start piped log program '%s': %s", pl->program, apr_strerror(status, buf, sizeof(buf))); } } return status; }
static void launch_child(abts_case *tc, apr_proc_t *proc, const char *arg1, apr_pool_t *p) { apr_procattr_t *procattr; const char *args[3]; apr_status_t rv; rv = apr_procattr_create(&procattr, p); APR_ASSERT_SUCCESS(tc, "Couldn't create procattr", rv); rv = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_NO_PIPE, APR_NO_PIPE); APR_ASSERT_SUCCESS(tc, "Couldn't set io in procattr", rv); rv = apr_procattr_error_check_set(procattr, 1); APR_ASSERT_SUCCESS(tc, "Couldn't set error check in procattr", rv); rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV); APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); args[0] = "sockchild" EXTENSION; args[1] = arg1; args[2] = NULL; rv = apr_proc_create(proc, TESTBINPATH "sockchild" EXTENSION, args, NULL, procattr, p); APR_ASSERT_SUCCESS(tc, "Couldn't launch program", rv); }
static int launch_reader(abts_case *tc) { apr_proc_t proc = {0}; apr_procattr_t *procattr; const char *args[2]; apr_status_t rv; apr_exit_why_e why; int exitcode; rv = apr_procattr_create(&procattr, p); APR_ASSERT_SUCCESS(tc, "Couldn't create procattr", rv); rv = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_NO_PIPE, APR_NO_PIPE); APR_ASSERT_SUCCESS(tc, "Couldn't set io in procattr", rv); rv = apr_procattr_error_check_set(procattr, 1); APR_ASSERT_SUCCESS(tc, "Couldn't set error check in procattr", rv); args[0] = "tryread" EXTENSION; args[1] = NULL; rv = apr_proc_create(&proc, "./tryread" EXTENSION, args, NULL, procattr, p); APR_ASSERT_SUCCESS(tc, "Couldn't launch program", rv); ABTS_ASSERT(tc, "wait for child process", apr_proc_wait(&proc, &exitcode, &why, APR_WAIT) == APR_CHILD_DONE); ABTS_ASSERT(tc, "child terminated normally", why == APR_PROC_EXIT); return exitcode; }
static void test_pipe_writefull(abts_case *tc, void *data) { int iterations = 1000; int i; int bytes_per_iteration = 8000; char *buf = (char *)malloc(bytes_per_iteration); char responsebuf[128]; apr_size_t nbytes; int bytes_processed; apr_proc_t proc = {0}; apr_procattr_t *procattr; const char *args[2]; apr_status_t rv; apr_exit_why_e why; rv = apr_procattr_create(&procattr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_error_check_set(procattr, 1); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); args[0] = "readchild" EXTENSION; args[1] = NULL; rv = apr_proc_create(&proc, "./readchild" EXTENSION, args, NULL, procattr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_file_pipe_timeout_set(proc.in, apr_time_from_sec(10)); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_file_pipe_timeout_set(proc.out, apr_time_from_sec(10)); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); i = iterations; do { rv = apr_file_write_full(proc.in, buf, bytes_per_iteration, NULL); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); } while (--i); free(buf); rv = apr_file_close(proc.in); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); nbytes = sizeof(responsebuf); rv = apr_file_read(proc.out, responsebuf, &nbytes); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); bytes_processed = (int)apr_strtoi64(responsebuf, NULL, 10); ABTS_INT_EQUAL(tc, iterations * bytes_per_iteration, bytes_processed); ABTS_ASSERT(tc, "wait for child process", apr_proc_wait(&proc, NULL, &why, APR_WAIT) == APR_CHILD_DONE); ABTS_ASSERT(tc, "child terminated normally", why == APR_PROC_EXIT); }
/* Create a child process running PROGNAME with a pipe connected to * the childs stdin. The write-end of the pipe will be placed in * *FPIN on successful return. If dummy_stderr is non-zero, the * stderr for the child will be the same as the stdout of the parent. * Otherwise the child will inherit the stderr from the parent. */ static int log_child(apr_pool_t *p, const char *progname, apr_file_t **fpin, int dummy_stderr) { /* Child process code for 'ErrorLog "|..."'; * may want a common framework for this, since I expect it will * be common for other foo-loggers to want this sort of thing... */ apr_status_t rc; apr_procattr_t *procattr; apr_proc_t *procnew; apr_file_t *errfile; if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) && ((rc = apr_procattr_cmdtype_set(procattr, APR_SHELLCMD_ENV)) == APR_SUCCESS) && ((rc = apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_NO_PIPE, APR_NO_PIPE)) == APR_SUCCESS) && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS) && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) == APR_SUCCESS) && (!dummy_stderr || ((rc = apr_file_open_stdout(&errfile, p)) == APR_SUCCESS && (rc = apr_procattr_child_err_set(procattr, errfile, errfile)) == APR_SUCCESS))) { char **args; const char *pname; apr_tokenize_to_argv(progname, &args, p); pname = apr_pstrdup(p, args[0]); procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew)); rc = apr_proc_create(procnew, pname, (const char * const *)args, NULL, procattr, p); if (rc == APR_SUCCESS) { apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); (*fpin) = procnew->in; /* read handle to pipe not kept open, so no need to call * close_handle_in_child() */ } /* apr_procattr_child_err_set dups errfile twice: close the * remaining "parent-side" copy (apr_proc_create closes the * other). */ if (dummy_stderr) { apr_file_close(procnew->err); } } return rc; }
static int proc_error_check_set(lua_State *L) { apr_status_t status; apr_int32_t error_check; lua_apr_proc *process; process = proc_check(L, 1); error_check = lua_toboolean(L, 2); status = apr_procattr_error_check_set(process->attr, error_check); return push_status(L, status); }
static void test_pipe_writefull(CuTest *tc) { int iterations = 1000; int i; int bytes_per_iteration = 8000; char *buf = (char *)malloc(bytes_per_iteration); char responsebuf[128]; apr_size_t nbytes; int bytes_processed; apr_proc_t proc = {0}; apr_procattr_t *procattr; const char *args[2]; apr_status_t rv; rv = apr_procattr_create(&procattr, p); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_procattr_error_check_set(procattr, 1); CuAssertIntEquals(tc, APR_SUCCESS, rv); args[0] = "readchild" EXTENSION; args[1] = NULL; rv = apr_proc_create(&proc, "./readchild" EXTENSION, args, NULL, procattr, p); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_file_pipe_timeout_set(proc.in, apr_time_from_sec(10)); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_file_pipe_timeout_set(proc.out, apr_time_from_sec(10)); CuAssertIntEquals(tc, APR_SUCCESS, rv); i = iterations; do { rv = apr_file_write_full(proc.in, buf, bytes_per_iteration, NULL); CuAssertIntEquals(tc, APR_SUCCESS, rv); } while (--i); free(buf); rv = apr_file_close(proc.in); CuAssertIntEquals(tc, APR_SUCCESS, rv); nbytes = sizeof(responsebuf); rv = apr_file_read(proc.out, responsebuf, &nbytes); CuAssertIntEquals(tc, APR_SUCCESS, rv); bytes_processed = (int)apr_strtoi64(responsebuf, NULL, 10); CuAssertIntEquals(tc, iterations * bytes_per_iteration, bytes_processed); }
static void spawn_server(apr_pool_t *p, apr_proc_t *out_proc) { apr_proc_t proc = {0}; apr_procattr_t *procattr; apr_status_t rv; const char *args[3]; rv = apr_procattr_create(&procattr, p); if (rv != APR_SUCCESS) { aprerr("apr_procattr_create()", rv); } rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK); if (rv != APR_SUCCESS) { aprerr("apr_procattr_io_set()", rv); } rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV); if (rv != APR_SUCCESS) { aprerr("apr_procattr_cmdtype_set()", rv); } rv = apr_procattr_error_check_set(procattr, 1); if (rv != APR_SUCCESS) { aprerr("apr_procattr_error_check_set()", rv); } args[0] = "sendfile" EXTENSION; args[1] = "server"; args[2] = NULL; rv = apr_proc_create(&proc, TESTBINPATH "sendfile" EXTENSION, args, NULL, procattr, p); if (rv != APR_SUCCESS) { aprerr("apr_proc_create()", rv); } *out_proc = proc; }
/* * Handle post-rotate processing. */ static void post_rotate(apr_pool_t *pool, struct logfile *newlog, rotate_config_t *config, rotate_status_t *status) { apr_status_t rv; char error[120]; apr_procattr_t *pattr; const char *argv[4]; apr_proc_t proc; /* Handle link file, if configured. */ if (config->linkfile) { apr_file_remove(config->linkfile, newlog->pool); if (config->verbose) { fprintf(stderr,"Linking %s to %s\n", newlog->name, config->linkfile); } rv = apr_file_link(newlog->name, config->linkfile); if (rv != APR_SUCCESS) { apr_strerror(rv, error, sizeof error); fprintf(stderr, "Error linking file %s to %s (%s)\n", newlog->name, config->linkfile, error); exit(2); } } if (!config->postrotate_prog) { /* Nothing more to do. */ return; } /* Collect any zombies from a previous run, but don't wait. */ while (apr_proc_wait_all_procs(&proc, NULL, NULL, APR_NOWAIT, pool) == APR_CHILD_DONE) /* noop */; if ((rv = apr_procattr_create(&pattr, pool)) != APR_SUCCESS) { fprintf(stderr, "post_rotate: apr_procattr_create failed for '%s': %s\n", config->postrotate_prog, apr_strerror(rv, error, sizeof(error))); return; } rv = apr_procattr_error_check_set(pattr, 1); if (rv == APR_SUCCESS) rv = apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV); if (rv != APR_SUCCESS) { fprintf(stderr, "post_rotate: could not set up process attributes for '%s': %s\n", config->postrotate_prog, apr_strerror(rv, error, sizeof(error))); return; } argv[0] = config->postrotate_prog; argv[1] = newlog->name; if (status->current.fd) { argv[2] = status->current.name; argv[3] = NULL; } else { argv[2] = NULL; } if (config->verbose) fprintf(stderr, "Calling post-rotate program: %s\n", argv[0]); rv = apr_proc_create(&proc, argv[0], argv, NULL, pattr, pool); if (rv != APR_SUCCESS) { fprintf(stderr, "Could not spawn post-rotate process '%s': %s\n", config->postrotate_prog, apr_strerror(rv, error, sizeof(error))); return; } }
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 }
/* init_ext_filter_process: get the external filter process going * This is per-filter-instance (i.e., per-request) initialization. */ static apr_status_t init_ext_filter_process(ap_filter_t *f) { ef_ctx_t *ctx = f->ctx; apr_status_t rc; ef_dir_t *dc = ctx->dc; const char * const *env; ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc)); rc = apr_procattr_create(&ctx->procattr, ctx->p); ap_assert(rc == APR_SUCCESS); rc = apr_procattr_io_set(ctx->procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK); ap_assert(rc == APR_SUCCESS); rc = set_resource_limits(f->r, ctx->procattr); ap_assert(rc == APR_SUCCESS); if (dc->log_stderr > 0) { rc = apr_procattr_child_err_set(ctx->procattr, f->r->server->error_log, /* stderr in child */ NULL); ap_assert(rc == APR_SUCCESS); } rc = apr_procattr_child_errfn_set(ctx->procattr, child_errfn); ap_assert(rc == APR_SUCCESS); apr_pool_userdata_set(f->r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ctx->p); rc = apr_procattr_error_check_set(ctx->procattr, 1); if (rc != APR_SUCCESS) { return rc; } /* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO, * and QUERY_STRING_UNESCAPED */ ap_add_cgi_vars(f->r); ap_add_common_vars(f->r); apr_table_setn(f->r->subprocess_env, "DOCUMENT_URI", f->r->uri); apr_table_setn(f->r->subprocess_env, "DOCUMENT_PATH_INFO", f->r->path_info); if (f->r->args) { /* QUERY_STRING is added by ap_add_cgi_vars */ char *arg_copy = apr_pstrdup(f->r->pool, f->r->args); ap_unescape_url(arg_copy); apr_table_setn(f->r->subprocess_env, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(f->r->pool, arg_copy)); } env = (const char * const *) ap_create_environment(ctx->p, f->r->subprocess_env); rc = apr_proc_create(ctx->proc, ctx->filter->command, (const char * const *)ctx->filter->args, env, /* environment */ ctx->procattr, ctx->p); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r, "couldn't create child process to run `%s'", ctx->filter->command); return rc; } apr_pool_note_subprocess(ctx->p, ctx->proc, APR_KILL_AFTER_TIMEOUT); /* We don't want the handle to the child's stdin inherited by any * other processes created by httpd. Otherwise, when we close our * handle, the child won't see EOF because another handle will still * be open. */ apr_pool_cleanup_register(ctx->p, ctx->proc->in, apr_pool_cleanup_null, /* other mechanism */ ef_close_file); #if APR_FILES_AS_SOCKETS { apr_pollfd_t pfd = { 0 }; rc = apr_pollset_create(&ctx->pollset, 2, ctx->p, 0); ap_assert(rc == APR_SUCCESS); pfd.p = ctx->p; pfd.desc_type = APR_POLL_FILE; pfd.reqevents = APR_POLLOUT; pfd.desc.f = ctx->proc->in; rc = apr_pollset_add(ctx->pollset, &pfd); ap_assert(rc == APR_SUCCESS); pfd.reqevents = APR_POLLIN; pfd.desc.f = ctx->proc->out; rc = apr_pollset_add(ctx->pollset, &pfd); ap_assert(rc == APR_SUCCESS); } #endif return APR_SUCCESS; }
LIB_INTERNAL void run_bg_cmd(LOGMANAGER *mp, const char *cmd , const char *file_path, TIMESTAMP t) { char buf[32]; DECLARE_TPOOL; apr_procattr_t *attr; apr_proc_t proc; const char *args[2]; apr_status_t status; char errbuf[1024]; NORMALIZE_TIMESTAMP(t); if (!cmd) return; /* Security */ DEBUG1(mp,1,"Running background command : %s",cmd); /* Set environment variables */ (void)apr_env_set("LOGMANAGER_FILE_PATH",(file_path ? file_path : "") ,CHECK_TPOOL()); (void)apr_env_set("LOGMANAGER_BASE_PATH",mp->base_path,CHECK_TPOOL()); (void)apr_env_set("LOGMANAGER_BASE_DIR",mp->base_dir,CHECK_TPOOL()); (void)apr_env_set("LOGMANAGER_LOG_PATH",mp->log_path,CHECK_TPOOL()); (void)apr_env_set("LOGMANAGER_LOG_DIR",mp->log_dir,CHECK_TPOOL()); (void)apr_env_set("LOGMANAGER_COMPRESSION" ,mp->compress.handler->suffix,CHECK_TPOOL()); (void)apr_env_set("LOGMANAGER_VERSION",PACKAGE_VERSION,CHECK_TPOOL()); (void)apr_snprintf(buf,sizeof(buf),"%" TIMESTAMP_FMT,t); (void)apr_env_set("LOGMANAGER_TIME",buf,CHECK_TPOOL()); /* Run background process */ (void)apr_procattr_create(&attr,CHECK_TPOOL()); /* APR_NO_FILE is defined in APR 1.3.0 and higher */ #ifdef APR_NO_FILE #define LMGR_IO_ATTR APR_NO_FILE #else #define LMGR_IO_ATTR 0 #endif /*(void)apr_procattr_io_set(attr,LMGR_IO_ATTR,LMGR_IO_ATTR,LMGR_IO_ATTR);*/ (void)apr_procattr_cmdtype_set(attr,APR_PROGRAM_ENV); (void)apr_procattr_detach_set(attr,1); (void)apr_procattr_error_check_set(attr,1); (void)apr_procattr_child_errfn_set(attr,_proc_create_error_callback); args[0]=cmd; args[1]=NULL; status=apr_proc_create(&proc,cmd,args,NULL, attr,CHECK_TPOOL()); if (status != APR_SUCCESS) { _proc_create_error(mp,CHECK_TPOOL(),status ,apr_strerror(status,errbuf,sizeof(errbuf))); } /* The background process lives its own life. Don't care about it anymore */ FREE_TPOOL(); return; }