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 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); }
/* 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 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); }
static int process_fortune_connection(conn_rec *c) { apr_status_t rv; apr_procattr_t *pattr; apr_pool_t *p = c->pool; apr_bucket *b; apr_bucket_brigade *bb; const char *err_msg = "200 OK\n"; fortune_conf_t *fconf = ap_get_module_config(c->base_server->module_config, &fortune_module); if (!fconf->enabled) { return DECLINED; } bb = apr_brigade_create(p, c->bucket_alloc); /* prepare process attribute */ if ((rv = apr_procattr_create(&pattr, c->pool)) != APR_SUCCESS) { goto error; } if ((rv = apr_procattr_io_set(pattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE)) != APR_SUCCESS) { goto error; } /* default value: APR_PROGRAM */ if ((rv = apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV)) != APR_SUCCESS) { goto error; } /* run the program and read the output from the pipe */ if ((rv = fortune_process(c, pattr, bb)) != APR_SUCCESS) { apr_brigade_cleanup(bb); } error: if (rv != APR_SUCCESS) { err_msg = "500 ERROR\n"; } b = apr_bucket_pool_create(err_msg, strlen(err_msg), p, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(c->output_filters, bb); return OK; }
/* 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 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 lua_apr_proc *proc_alloc(lua_State *L, const char *path) { apr_status_t status; lua_apr_proc *process; process = new_object(L, &lua_apr_proc_type); status = apr_pool_create(&process->memory_pool, NULL); if (status != APR_SUCCESS) process->memory_pool = NULL; else status = apr_procattr_create(&process->attr, process->memory_pool); if (status != APR_SUCCESS) raise_error_status(L, status); if (path != NULL) process->path = apr_pstrdup(process->memory_pool, path); return process; }
static void test_create_proc(CuTest *tc) { const char *args[2]; apr_procattr_t *attr; apr_file_t *testfile = NULL; apr_status_t rv; apr_size_t length; char *buf; rv = apr_procattr_create(&attr, p); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_procattr_io_set(attr, APR_FULL_BLOCK, APR_FULL_BLOCK, APR_NO_PIPE); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_procattr_dir_set(attr, "data"); CuAssertIntEquals(tc, APR_SUCCESS, rv); rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM); CuAssertIntEquals(tc, APR_SUCCESS, rv); args[0] = "proc_child" EXTENSION; args[1] = NULL; rv = apr_proc_create(&newproc, "../proc_child" EXTENSION, args, NULL, attr, p); CuAssertIntEquals(tc, APR_SUCCESS, rv); testfile = newproc.in; length = strlen(TESTSTR); rv = apr_file_write(testfile, TESTSTR, &length); CuAssertIntEquals(tc, APR_SUCCESS, rv); CuAssertIntEquals(tc, strlen(TESTSTR), length); testfile = newproc.out; length = 256; buf = apr_pcalloc(p, length); rv = apr_file_read(testfile, buf, &length); CuAssertIntEquals(tc, APR_SUCCESS, rv); CuAssertStrEquals(tc, TESTSTR, buf); }
static void test_create_proc(abts_case *tc, void *data) { const char *args[2]; apr_procattr_t *attr; apr_file_t *testfile = NULL; apr_status_t rv; apr_size_t length; char *buf; rv = apr_procattr_create(&attr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_io_set(attr, APR_FULL_BLOCK, APR_FULL_BLOCK, APR_NO_PIPE); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_dir_set(attr, "data"); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); args[0] = "proc_child" EXTENSION; args[1] = NULL; rv = apr_proc_create(&newproc, "../" TESTBINPATH "proc_child" EXTENSION, args, NULL, attr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); testfile = newproc.in; length = strlen(TESTSTR); rv = apr_file_write(testfile, TESTSTR, &length); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), length); testfile = newproc.out; length = 256; buf = apr_pcalloc(p, length); rv = apr_file_read(testfile, buf, &length); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_STR_EQUAL(tc, TESTSTR, buf); }
apr_file_t *ssl_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd, const char * const *argv) { apr_procattr_t *procattr; apr_proc_t *proc; if (apr_procattr_create(&procattr, p) != APR_SUCCESS) return NULL; if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK, APR_FULL_BLOCK) != APR_SUCCESS) return NULL; if (apr_procattr_dir_set(procattr, ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS) return NULL; if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS) return NULL; proc = apr_pcalloc(p, sizeof(apr_proc_t)); if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS) return NULL; return proc->out; }
/* It would be great if we could stress this stuff more, and make the test * more granular. */ static void test_child_kill(abts_case *tc, void *data) { apr_file_t *std = NULL; apr_proc_t newproc; apr_procattr_t *procattr = NULL; const char *args[3]; apr_status_t rv; args[0] = apr_pstrdup(p, "occhild" EXTENSION); args[1] = apr_pstrdup(p, "-X"); args[2] = NULL; rv = apr_procattr_create(&procattr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_NO_PIPE, APR_NO_PIPE); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_proc_create(&newproc, "./occhild" EXTENSION, args, NULL, procattr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_PTR_NOTNULL(tc, newproc.in); ABTS_PTR_EQUAL(tc, NULL, newproc.out); ABTS_PTR_EQUAL(tc, NULL, newproc.err); std = newproc.in; apr_proc_other_child_register(&newproc, ocmaint, NULL, std, p); apr_sleep(apr_time_from_sec(1)); rv = apr_proc_kill(&newproc, SIGKILL); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); /* allow time for things to settle... */ apr_sleep(apr_time_from_sec(3)); apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); ABTS_STR_EQUAL(tc, "APR_OC_REASON_DEATH", reasonstr); }
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 }
static void test_named(abts_case *tc, void *data) { apr_status_t rv; apr_shm_t *shm = NULL; apr_size_t retsize; apr_proc_t pidproducer, pidconsumer; apr_procattr_t *attr1 = NULL, *attr2 = NULL; int sent, received; apr_exit_why_e why; const char *args[4]; apr_shm_remove(SHARED_FILENAME, p); rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p); APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); if (rv != APR_SUCCESS) { return; } ABTS_PTR_NOTNULL(tc, shm); retsize = apr_shm_size_get(shm); ABTS_SIZE_EQUAL(tc, SHARED_SIZE, retsize); boxes = apr_shm_baseaddr_get(shm); ABTS_PTR_NOTNULL(tc, boxes); rv = apr_procattr_create(&attr1, p); ABTS_PTR_NOTNULL(tc, attr1); APR_ASSERT_SUCCESS(tc, "Couldn't create attr1", rv); rv = apr_procattr_cmdtype_set(attr1, APR_PROGRAM_ENV); APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); args[0] = apr_pstrdup(p, "testshmproducer" EXTENSION); args[1] = NULL; rv = apr_proc_create(&pidproducer, TESTBINPATH "testshmproducer" EXTENSION, args, NULL, attr1, p); APR_ASSERT_SUCCESS(tc, "Couldn't launch producer", rv); rv = apr_procattr_create(&attr2, p); ABTS_PTR_NOTNULL(tc, attr2); APR_ASSERT_SUCCESS(tc, "Couldn't create attr2", rv); rv = apr_procattr_cmdtype_set(attr2, APR_PROGRAM_ENV); APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); args[0] = apr_pstrdup(p, "testshmconsumer" EXTENSION); rv = apr_proc_create(&pidconsumer, TESTBINPATH "testshmconsumer" EXTENSION, args, NULL, attr2, p); APR_ASSERT_SUCCESS(tc, "Couldn't launch consumer", rv); rv = apr_proc_wait(&pidconsumer, &received, &why, APR_WAIT); ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why); rv = apr_proc_wait(&pidproducer, &sent, &why, APR_WAIT); ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why); /* Cleanup before testing that producer and consumer worked correctly. * This way, if they didn't succeed, we can just run this test again * without having to cleanup manually. */ APR_ASSERT_SUCCESS(tc, "Error destroying shared memory", apr_shm_destroy(shm)); ABTS_INT_EQUAL(tc, sent, received); }
static svn_error_t * open_tunnel(svn_stream_t **request, svn_stream_t **response, svn_ra_close_tunnel_func_t *close_func, void **close_baton, void *tunnel_baton, const char *tunnel_name, const char *user, const char *hostname, int port, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { svn_node_kind_t kind; apr_proc_t *proc; apr_procattr_t *attr; apr_status_t status; const char *args[] = { "svnserve", "-t", "-r", ".", NULL }; const char *svnserve; tunnel_baton_t *b = tunnel_baton; close_baton_t *cb; SVN_TEST_ASSERT(b->magic == TUNNEL_MAGIC); SVN_ERR(svn_dirent_get_absolute(&svnserve, "../../svnserve/svnserve", pool)); #ifdef WIN32 svnserve = apr_pstrcat(pool, svnserve, ".exe", SVN_VA_NULL); #endif SVN_ERR(svn_io_check_path(svnserve, &kind, pool)); if (kind != svn_node_file) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Could not find svnserve at %s", svn_dirent_local_style(svnserve, pool)); status = apr_procattr_create(&attr, pool); if (status == APR_SUCCESS) status = apr_procattr_io_set(attr, 1, 1, 0); if (status == APR_SUCCESS) status = apr_procattr_cmdtype_set(attr, APR_PROGRAM); proc = apr_palloc(pool, sizeof(*proc)); if (status == APR_SUCCESS) status = apr_proc_create(proc, svn_dirent_local_style(svnserve, pool), args, NULL, attr, pool); if (status != APR_SUCCESS) return svn_error_wrap_apr(status, "Could not run svnserve"); apr_pool_note_subprocess(pool, proc, APR_KILL_NEVER); /* APR pipe objects inherit by default. But we don't want the * tunnel agent's pipes held open by future child processes * (such as other ra_svn sessions), so turn that off. */ apr_file_inherit_unset(proc->in); apr_file_inherit_unset(proc->out); cb = apr_pcalloc(pool, sizeof(*cb)); cb->magic = CLOSE_MAGIC; cb->tb = b; cb->proc = proc; *request = svn_stream_from_aprfile2(proc->in, FALSE, pool); *response = svn_stream_from_aprfile2(proc->out, FALSE, pool); *close_func = close_tunnel; *close_baton = cb; ++b->open_count; return SVN_NO_ERROR; }
apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo, fcgid_procnode *procnode) { HANDLE *finish_event, listen_handle; SECURITY_ATTRIBUTES SecurityAttributes; fcgid_server_conf *sconf; apr_procattr_t *proc_attr; apr_status_t rv; apr_file_t *file; const char * const *proc_environ; char sock_path[FCGID_PATH_MAX]; int argc; char const * wargv[APACHE_ARG_MAX + 1], *word; /* For wrapper */ const char *tmp; /* Build wrapper args */ argc = 0; tmp = cmdline; while (1) { word = ap_getword_white(procnode->proc_pool, &tmp); if (word == NULL || *word == '\0') break; if (argc >= APACHE_ARG_MAX) break; wargv[argc++] = word; } wargv[argc] = NULL; memset(&SecurityAttributes, 0, sizeof(SecurityAttributes)); /* Prepare finish event */ finish_event = apr_palloc(procnode->proc_pool, sizeof(HANDLE)); *finish_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (*finish_event == NULL || !SetHandleInformation(*finish_event, HANDLE_FLAG_INHERIT, TRUE)) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create mutex for subprocess"); return APR_ENOLOCK; } apr_pool_cleanup_register(procnode->proc_pool, finish_event, close_finish_event, apr_pool_cleanup_null); /* For proc_kill_gracefully() */ apr_pool_userdata_set(finish_event, FINISH_EVENT_DATA_NAME, NULL, procnode->proc_pool); /* Pass the finish event id to subprocess */ apr_table_setn(procinfo->proc_environ, SHUTDOWN_EVENT_NAME, apr_ltoa(procnode->proc_pool, (long) *finish_event)); /* Prepare the listen namedpipe file name (no check for truncation) */ apr_snprintf(sock_path, sizeof sock_path, "\\\\.\\pipe\\fcgidpipe-%lu.%d", GetCurrentProcessId(), g_process_counter++); /* Prepare the listen namedpipe handle */ SecurityAttributes.bInheritHandle = TRUE; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; listen_handle = CreateNamedPipe(sock_path, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 8192, 8192, 0, &SecurityAttributes); if (listen_handle == INVALID_HANDLE_VALUE) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create namedpipe for subprocess"); return APR_ENOSOCKET; } apr_cpystrn(procnode->socket_path, sock_path, sizeof(procnode->socket_path)); apr_cpystrn(procnode->executable_path, wargv[0], sizeof(procnode->executable_path)); /* Build environment variables */ proc_environ = (const char * const *) ap_create_environment(procnode->proc_pool, procinfo->proc_environ); if (!proc_environ) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't build environment variables"); return APR_ENOMEM; } /* Create process now */ if ((rv = apr_procattr_create(&proc_attr, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_dir_set(proc_attr, ap_make_dirstr_parent(procnode->proc_pool, wargv[0]))) != APR_SUCCESS || (rv = apr_procattr_cmdtype_set(proc_attr, APR_PROGRAM)) != APR_SUCCESS || (rv = apr_procattr_detach_set(proc_attr, 1)) != APR_SUCCESS || (rv = apr_procattr_io_set(proc_attr, APR_NO_PIPE, APR_NO_FILE, APR_NO_FILE)) != APR_SUCCESS || (rv = apr_os_file_put(&file, &listen_handle, 0, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_child_in_set(proc_attr, file, NULL)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, procinfo->main_server, "mod_fcgid: can't create FastCGI process attribute"); CloseHandle(listen_handle); return APR_ENOPROC; } /* fork and exec now */ rv = apr_proc_create(&(procnode->proc_id), wargv[0], wargv, proc_environ, proc_attr, procnode->proc_pool); /* OK, I created the process, now put it back to idle list */ CloseHandle(listen_handle); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, "mod_fcgid: can't run %s", wargv[0]); return rv; } /* FcgidWin32PreventOrphans feature */ sconf = ap_get_module_config(procinfo->main_server->module_config, &fcgid_module); if (sconf->hJobObjectForAutoCleanup != NULL) { /* Associate cgi process to current process */ if (AssignProcessToJobObject(sconf->hJobObjectForAutoCleanup, procnode->proc_id.hproc) == 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: unable to assign child process to " "job object"); } } return APR_SUCCESS; }
/* 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; }
/* 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; }
/** * Execute system command. First line of the output will be returned in * the "output" parameter. */ int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) { apr_procattr_t *procattr = NULL; apr_proc_t *procnew = NULL; apr_status_t rc = APR_SUCCESS; const char *const *env = NULL; apr_file_t *script_out = NULL; request_rec *r = msr->r; if (argv == NULL) { argv = apr_pcalloc(r->pool, 3 * sizeof(char *)); argv[0] = command; argv[1] = NULL; } ap_add_cgi_vars(r); ap_add_common_vars(r); /* PHP hack, getting around its silly security checks. */ apr_table_add(r->subprocess_env, "PATH_TRANSLATED", command); apr_table_add(r->subprocess_env, "REDIRECT_STATUS", "302"); env = (const char * const *)ap_create_environment(r->pool, r->subprocess_env); if (env == NULL) { msr_log(msr, 1, "Exec: Unable to create environment."); return -1; } procnew = apr_pcalloc(r->pool, sizeof(*procnew)); if (procnew == NULL) { msr_log(msr, 1, "Exec: Unable to allocate %lu bytes.", (unsigned long)sizeof(*procnew)); return -1; } apr_procattr_create(&procattr, r->pool); if (procattr == NULL) { msr_log(msr, 1, "Exec: Unable to create procattr."); return -1; } apr_procattr_io_set(procattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE); apr_procattr_cmdtype_set(procattr, APR_SHELLCMD); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Exec: %s", log_escape_nq(r->pool, command)); } rc = apr_proc_create(procnew, command, argv, env, procattr, r->pool); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Exec: Execution failed: %s (%s)", log_escape_nq(r->pool, command), get_apr_error(r->pool, rc)); return -1; } apr_pool_note_subprocess(r->pool, procnew, APR_KILL_AFTER_TIMEOUT); script_out = procnew->out; if (!script_out) { msr_log(msr, 1, "Exec: Failed to get script output pipe."); return -1; } apr_file_pipe_timeout_set(script_out, r->server->timeout); /* Now read from the pipe. */ { char buf[260] = ""; char *p = buf; apr_size_t nbytes = 255; apr_status_t rc2; rc2 = apr_file_read(script_out, buf, &nbytes); if (rc2 == APR_SUCCESS) { buf[nbytes] = 0; /* if there is more than one line ignore them */ while(*p != 0) { if (*p == 0x0a) *p = 0; p++; } if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Exec: First line from script output: \"%s\"", log_escape(r->pool, buf)); } if (output != NULL) *output = apr_pstrdup(r->pool, buf); /* Soak up the remaining data. */ nbytes = 255; while(apr_file_read(script_out, buf, &nbytes) == APR_SUCCESS) nbytes = 255; } else { msr_log(msr, 1, "Exec: Execution failed while reading output: %s (%s)", log_escape_nq(r->pool, command), get_apr_error(r->pool, rc2)); return -1; } } apr_proc_wait(procnew, NULL, NULL, APR_WAIT); return 1; }
static void test_file_redir(abts_case *tc, void *data) { apr_file_t *testout = NULL; apr_file_t *testerr = NULL; apr_off_t offset; apr_status_t rv; const char *args[2]; apr_procattr_t *attr; apr_file_t *testfile = NULL; apr_size_t length; char *buf; testfile = NULL; rv = apr_file_open(&testfile, "data/stdin", APR_READ | APR_WRITE | APR_CREATE | APR_EXCL, APR_OS_DEFAULT, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_file_open(&testout, "data/stdout", APR_READ | APR_WRITE | APR_CREATE | APR_EXCL, APR_OS_DEFAULT, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_file_open(&testerr, "data/stderr", APR_READ | APR_WRITE | APR_CREATE | APR_EXCL, APR_OS_DEFAULT, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); length = strlen(TESTSTR); apr_file_write(testfile, TESTSTR, &length); offset = 0; rv = apr_file_seek(testfile, APR_SET, &offset); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_ASSERT(tc, "File position mismatch, expected 0", offset == 0); rv = apr_procattr_create(&attr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_child_in_set(attr, testfile, NULL); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_child_out_set(attr, testout, NULL); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_child_err_set(attr, testerr, NULL); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_dir_set(attr, "data"); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); args[0] = "proc_child"; args[1] = NULL; rv = apr_proc_create(&newproc, "../" TESTBINPATH "proc_child" EXTENSION, args, NULL, attr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_proc_wait(&newproc, NULL, NULL, APR_WAIT); ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); offset = 0; rv = apr_file_seek(testout, APR_SET, &offset); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); length = 256; buf = apr_pcalloc(p, length); rv = apr_file_read(testout, buf, &length); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_STR_EQUAL(tc, TESTSTR, buf); apr_file_close(testfile); apr_file_close(testout); apr_file_close(testerr); rv = apr_file_remove("data/stdin", p);; ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_file_remove("data/stdout", p);; ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_file_remove("data/stderr", p);; ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); }
static apr_status_t run_cgi_child(apr_file_t **script_out, apr_file_t **script_in, apr_file_t **script_err, const char *command, const char * const argv[], request_rec *r, apr_pool_t *p, cgi_exec_info_t *e_info) { const char * const *env; apr_procattr_t *procattr; apr_proc_t *procnew; apr_status_t rc = APR_SUCCESS; #if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \ defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS) core_dir_config *conf = ap_get_module_config(r->per_dir_config, &core_module); #endif #ifdef DEBUG_CGI #ifdef OS2 /* Under OS/2 need to use device con. */ FILE *dbg = fopen("con", "w"); #else FILE *dbg = fopen("/dev/tty", "w"); #endif int i; #endif RAISE_SIGSTOP(CGI_CHILD); #ifdef DEBUG_CGI fprintf(dbg, "Attempting to exec %s as CGI child (argv0 = %s)\n", r->filename, argv[0]); #endif env = (const char * const *)ap_create_environment(p, r->subprocess_env); #ifdef DEBUG_CGI fprintf(dbg, "Environment: \n"); for (i = 0; env[i]; ++i) fprintf(dbg, "'%s'\n", env[i]); #endif /* Transmute ourselves into the script. * NB only ISINDEX scripts get decoded arguments. */ if (((rc = apr_procattr_create(&procattr, p)) != APR_SUCCESS) || ((rc = apr_procattr_io_set(procattr, e_info->in_pipe, e_info->out_pipe, e_info->err_pipe)) != APR_SUCCESS) || ((rc = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) || #ifdef RLIMIT_CPU ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu)) != APR_SUCCESS) || #endif #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem)) != APR_SUCCESS) || #endif #ifdef RLIMIT_NPROC ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc)) != APR_SUCCESS) || #endif ((rc = apr_procattr_cmdtype_set(procattr, e_info->cmd_type)) != APR_SUCCESS) || ((rc = apr_procattr_detach_set(procattr, e_info->detached)) != APR_SUCCESS) || ((rc = apr_procattr_addrspace_set(procattr, e_info->addrspace)) != APR_SUCCESS) || ((rc = apr_procattr_child_errfn_set(procattr, cgi_child_errfn)) != APR_SUCCESS)) { /* Something bad happened, tell the world. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "couldn't set child process attributes: %s", r->filename); } else { procnew = apr_pcalloc(p, sizeof(*procnew)); rc = ap_os_create_privileged_process(r, procnew, command, argv, env, procattr, p); if (rc != APR_SUCCESS) { /* Bad things happened. Everyone should have cleaned up. */ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, rc, r, "couldn't create child process: %d: %s", rc, apr_filepath_name_get(r->filename)); } else { apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); *script_in = procnew->out; if (!*script_in) return APR_EBADF; apr_file_pipe_timeout_set(*script_in, r->server->timeout); if (e_info->prog_type == RUN_AS_CGI) { *script_out = procnew->in; if (!*script_out) return APR_EBADF; apr_file_pipe_timeout_set(*script_out, r->server->timeout); *script_err = procnew->err; if (!*script_err) return APR_EBADF; apr_file_pipe_timeout_set(*script_err, r->server->timeout); } } } #ifdef DEBUG_CGI fclose(dbg); #endif return (rc); }
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; }
/** Try to start a process running the master job. */ static int trell_start_master( trell_sconf_t* svr_conf, request_rec* r ) { apr_status_t rv; // Open file into which master job stdout is piped. apr_file_t* master_stdout = NULL; rv = apr_file_open( &master_stdout, apr_psprintf( r->pool, "/tmp/%s.stdout", svr_conf->m_master_id ), APR_FOPEN_CREATE | APR_WRITE | APR_TRUNCATE | APR_XTHREAD, APR_OS_DEFAULT, r->pool ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: Failed to open master job stdout" ); return rv; } // Open file into which master job stderr is piped. apr_file_t* master_stderr = NULL; rv = apr_file_open( &master_stderr, apr_psprintf( r->pool, "/tmp/%s.stderr", svr_conf->m_master_id ), APR_FOPEN_CREATE | APR_WRITE | APR_TRUNCATE | APR_XTHREAD, APR_OS_DEFAULT, r->pool ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: Failed to open master job stderr" ); return rv; } // Create process attribute and set file handles for pipes apr_procattr_t* procattr; rv = apr_procattr_create( &procattr, r->pool ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_create failed" ); return rv; } rv = apr_procattr_child_out_set( procattr, master_stdout, NULL ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_child_out_set failed" ); return rv; } rv = apr_procattr_child_err_set( procattr, master_stderr, NULL ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_child_err_set failed" ); return rv; } rv = apr_procattr_cmdtype_set( procattr, APR_PROGRAM ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_cmdtype_set failed" ); return rv; } const char* env[7] = { apr_psprintf( r->pool, "TINIA_JOB_ID=%s", svr_conf->m_master_id ), apr_psprintf( r->pool, "TINIA_MASTER_ID=%s", svr_conf->m_master_id ), apr_psprintf( r->pool, "TINIA_APP_ROOT=%s", svr_conf->m_app_root_dir ), NULL, // PATH NULL, // LD_LIBRARY_PATH NULL, // DISPLAY NULL }; // Copy PATH and LD_LIBRARY_PATH from the current environement, if set. It // might be an idea to pass these variables through the apache-config, // allowing more detailded control on jobs. int p = 3; char* PATH = NULL; if( (apr_env_get( &PATH, "PATH", r->pool ) == APR_SUCCESS ) && (PATH != NULL) ) { env[p++] = apr_psprintf( r->pool, "PATH=%s", PATH ); } char* LD_LIBRARY_PATH = NULL; if( (apr_env_get( &LD_LIBRARY_PATH, "LD_LIBRARY_PATH", r->pool ) == APR_SUCCESS ) && (LD_LIBRARY_PATH != NULL) ) { env[p++] = apr_psprintf( r->pool, "LD_LIBRARY_PATH=%s", LD_LIBRARY_PATH ); } char* DISPLAY = NULL; if( (apr_env_get( &DISPLAY, "DISPLAY", r->pool ) == APR_SUCCESS ) && (DISPLAY != NULL) ) { env[p++] = apr_psprintf( r->pool, "DISPLAY=%s", DISPLAY ); } // Set up arguments const char* args[2] = { svr_conf->m_master_exe, NULL }; apr_proc_t newproc; rv = apr_proc_create( &newproc, svr_conf->m_master_exe, args, env, procattr, r->pool ); if( rv != APR_SUCCESS ) { ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: Failed to execute '%s'", svr_conf->m_master_exe ); return rv; } rv = trell_set_master_pid( svr_conf, r, newproc.pid ); if( rv != APR_SUCCESS ) { return rv; } ap_log_rerror( APLOG_MARK, APLOG_NOTICE, OK, r, "mod_trell: Master running at pid %d", newproc.pid ); return APR_SUCCESS; }